blob: 051cc671fcef4a21d68a36ccea38c8251ce476fc [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 */
184
Denys Vlasenko7d4aec02017-01-11 14:00:38 +0100185/* So far, all bash compat is controlled by one config option */
186/* Separate defines document which part of code implements what */
187/* function keyword */
188#define BASH_FUNCTION ENABLE_ASH_BASH_COMPAT
189#define IF_BASH_FUNCTION IF_ASH_BASH_COMPAT
190/* &>file */
191#define BASH_REDIR_OUTPUT ENABLE_ASH_BASH_COMPAT
192#define IF_BASH_REDIR_OUTPUT IF_ASH_BASH_COMPAT
193/* $'...' */
194#define BASH_DOLLAR_SQUOTE ENABLE_ASH_BASH_COMPAT
195#define IF_BASH_DOLLAR_SQUOTE IF_ASH_BASH_COMPAT
196#define BASH_PATTERN_SUBST ENABLE_ASH_BASH_COMPAT
197#define IF_BASH_PATTERN_SUBST IF_ASH_BASH_COMPAT
198#define BASH_SUBSTR ENABLE_ASH_BASH_COMPAT
199#define IF_BASH_SUBSTR IF_ASH_BASH_COMPAT
Denys Vlasenko3632cb12018-04-10 15:25:41 +0200200/* BASH_TEST2: [[ EXPR ]]
201 * Status of [[ support:
202 * We replace && and || with -a and -o
203 * TODO:
204 * singleword+noglob expansion:
205 * v='a b'; [[ $v = 'a b' ]]; echo 0:$?
Denys Vlasenko89e9d552018-04-11 01:15:33 +0200206 * [[ /bin/n* ]]; echo 0:$?
Denys Vlasenko3632cb12018-04-10 15:25:41 +0200207 * -a/-o are not AND/OR ops! (they are just strings)
208 * quoting needs to be considered (-f is an operator, "-f" and ""-f are not; etc)
209 * = is glob match operator, not equality operator: STR = GLOB
210 * (in GLOB, quoting is significant on char-by-char basis: a*cd"*")
211 * == same as =
212 * add =~ regex match operator: STR =~ REGEX
213 */
Denys Vlasenko7d4aec02017-01-11 14:00:38 +0100214#define BASH_TEST2 (ENABLE_ASH_BASH_COMPAT * ENABLE_ASH_TEST)
215#define BASH_SOURCE ENABLE_ASH_BASH_COMPAT
216#define BASH_PIPEFAIL ENABLE_ASH_BASH_COMPAT
217#define BASH_HOSTNAME_VAR ENABLE_ASH_BASH_COMPAT
218#define BASH_SHLVL_VAR ENABLE_ASH_BASH_COMPAT
Denys Vlasenkof8cdc7a2017-08-04 15:24:49 +0200219#define BASH_XTRACEFD ENABLE_ASH_BASH_COMPAT
Johannes Schindelin3bef5d82017-08-08 16:46:39 +0200220#define BASH_READ_D ENABLE_ASH_BASH_COMPAT
221#define IF_BASH_READ_D IF_ASH_BASH_COMPAT
Denys Vlasenko7d4aec02017-01-11 14:00:38 +0100222
Denys Vlasenko67047462016-12-22 15:21:58 +0100223#if defined(__ANDROID_API__) && __ANDROID_API__ <= 24
224/* Bionic at least up to version 24 has no glob() */
225# undef ENABLE_ASH_INTERNAL_GLOB
226# define ENABLE_ASH_INTERNAL_GLOB 1
227#endif
228
229#if !ENABLE_ASH_INTERNAL_GLOB && defined(__UCLIBC__)
230# error uClibc glob() is buggy, use ASH_INTERNAL_GLOB.
231# error The bug is: for "$PWD"/<pattern> ash will escape e.g. dashes in "$PWD"
232# error with backslash, even ones which do not need to be: "/a-b" -> "/a\-b"
233# error glob() should unbackslash them and match. uClibc does not unbackslash,
234# error fails to match dirname, subsequently not expanding <pattern> in it.
235// Testcase:
236// if (glob("/etc/polkit\\-1", 0, NULL, &pglob)) - this returns 0 on uclibc, no bug
237// if (glob("/etc/polkit\\-1/*", 0, NULL, &pglob)) printf("uclibc bug!\n");
238#endif
239
240#if !ENABLE_ASH_INTERNAL_GLOB
241# include <glob.h>
242#endif
243
244#include "unicode.h"
245#include "shell_common.h"
Denys Vlasenko0b883582016-12-23 16:49:07 +0100246#if ENABLE_FEATURE_SH_MATH
Denys Vlasenko67047462016-12-22 15:21:58 +0100247# include "math.h"
Denys Vlasenkocf3a7962017-07-26 14:38:19 +0200248#else
249typedef long arith_t;
250# define ARITH_FMT "%ld"
Denys Vlasenko67047462016-12-22 15:21:58 +0100251#endif
252#if ENABLE_ASH_RANDOM_SUPPORT
253# include "random.h"
254#else
255# define CLEAR_RANDOM_T(rnd) ((void)0)
256#endif
257
258#include "NUM_APPLETS.h"
259#if NUM_APPLETS == 1
260/* STANDALONE does not make sense, and won't compile */
261# undef CONFIG_FEATURE_SH_STANDALONE
262# undef ENABLE_FEATURE_SH_STANDALONE
263# undef IF_FEATURE_SH_STANDALONE
264# undef IF_NOT_FEATURE_SH_STANDALONE
265# define ENABLE_FEATURE_SH_STANDALONE 0
266# define IF_FEATURE_SH_STANDALONE(...)
267# define IF_NOT_FEATURE_SH_STANDALONE(...) __VA_ARGS__
268#endif
269
Denys Vlasenko9acd63c2018-03-28 18:35:07 +0200270#ifndef F_DUPFD_CLOEXEC
271# define F_DUPFD_CLOEXEC F_DUPFD
272#endif
Denys Vlasenko60fb98e2018-03-30 22:15:14 +0200273#ifndef O_CLOEXEC
274# define O_CLOEXEC 0
275#endif
Denys Vlasenko67047462016-12-22 15:21:58 +0100276#ifndef PIPE_BUF
277# define PIPE_BUF 4096 /* amount of buffering in a pipe */
278#endif
279
280#if !BB_MMU
281# error "Do not even bother, ash will not run on NOMMU machine"
282#endif
283
Denys Vlasenko6f9442f2018-01-28 20:41:23 +0100284/* We use a trick to have more optimized code (fewer pointer reloads):
285 * ash.c: extern struct globals *const ash_ptr_to_globals;
286 * ash_ptr_hack.c: struct globals *ash_ptr_to_globals;
287 * This way, compiler in ash.c knows the pointer can not change.
288 *
289 * However, this may break on weird arches or toolchains. In this case,
290 * set "-DBB_GLOBAL_CONST=''" in CONFIG_EXTRA_CFLAGS to disable
291 * this optimization.
292 */
293#ifndef BB_GLOBAL_CONST
294# define BB_GLOBAL_CONST const
295#endif
296
Denis Vlasenkob012b102007-02-19 22:43:01 +0000297
Denis Vlasenko01631112007-12-16 17:20:38 +0000298/* ============ Hash table sizes. Configurable. */
299
300#define VTABSIZE 39
301#define ATABSIZE 39
302#define CMDTABLESIZE 31 /* should be prime */
303
304
Denis Vlasenkob012b102007-02-19 22:43:01 +0000305/* ============ Shell options */
306
307static const char *const optletters_optnames[] = {
308 "e" "errexit",
309 "f" "noglob",
310 "I" "ignoreeof",
311 "i" "interactive",
312 "m" "monitor",
313 "n" "noexec",
314 "s" "stdin",
315 "x" "xtrace",
316 "v" "verbose",
317 "C" "noclobber",
318 "a" "allexport",
319 "b" "notify",
320 "u" "nounset",
Denys Vlasenkoe9ac32a2009-12-05 02:01:25 +0100321 "\0" "vi"
Denys Vlasenko7d4aec02017-01-11 14:00:38 +0100322#if BASH_PIPEFAIL
Denys Vlasenkoe9ac32a2009-12-05 02:01:25 +0100323 ,"\0" "pipefail"
Michael Abbott359da5e2009-12-04 23:03:29 +0100324#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +0000325#if DEBUG
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000326 ,"\0" "nolog"
327 ,"\0" "debug"
Denis Vlasenkob012b102007-02-19 22:43:01 +0000328#endif
329};
330
Denys Vlasenko285ad152009-12-04 23:02:27 +0100331#define optletters(n) optletters_optnames[n][0]
332#define optnames(n) (optletters_optnames[n] + 1)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000333
Denis Vlasenko80b8b392007-06-25 10:55:35 +0000334enum { NOPTS = ARRAY_SIZE(optletters_optnames) };
Denis Vlasenkob012b102007-02-19 22:43:01 +0000335
Eric Andersenc470f442003-07-28 09:56:35 +0000336
Denis Vlasenkob012b102007-02-19 22:43:01 +0000337/* ============ Misc data */
Eric Andersenc470f442003-07-28 09:56:35 +0000338
Denys Vlasenkoea8b2522010-06-02 12:57:26 +0200339#define msg_illnum "Illegal number: %s"
Denis Vlasenkoaa744452007-02-23 01:04:22 +0000340
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +0000341/*
Eric Andersenc470f442003-07-28 09:56:35 +0000342 * We enclose jmp_buf in a structure so that we can declare pointers to
343 * jump locations. The global variable handler contains the location to
Denis Vlasenkof1733952009-03-19 23:21:55 +0000344 * jump to when an exception occurs, and the global variable exception_type
Eric Andersenaff114c2004-04-14 17:51:38 +0000345 * contains a code identifying the exception. To implement nested
Eric Andersenc470f442003-07-28 09:56:35 +0000346 * exception handlers, the user should save the value of handler on entry
347 * to an inner scope, set handler to point to a jmploc structure for the
348 * inner scope, and restore handler on exit from the scope.
349 */
Eric Andersenc470f442003-07-28 09:56:35 +0000350struct jmploc {
351 jmp_buf loc;
352};
Denis Vlasenko01631112007-12-16 17:20:38 +0000353
354struct globals_misc {
Denys Vlasenko4d12e942016-10-01 16:03:11 +0200355 uint8_t exitstatus; /* exit status of last command */
356 uint8_t back_exitstatus;/* exit status of backquoted command */
357 smallint job_warning; /* user was warned about stopped jobs (can be 2, 1 or 0). */
358 int rootpid; /* pid of main shell */
Denis Vlasenko01631112007-12-16 17:20:38 +0000359 /* shell level: 0 for the main shell, 1 for its children, and so on */
360 int shlvl;
361#define rootshell (!shlvl)
Denys Vlasenko675d24a2018-01-27 22:02:05 +0100362 int errlinno;
363
Denis Vlasenko01631112007-12-16 17:20:38 +0000364 char *minusc; /* argument to -c option */
365
366 char *curdir; // = nullstr; /* current working directory */
367 char *physdir; // = nullstr; /* physical working directory */
368
369 char *arg0; /* value of $0 */
370
371 struct jmploc *exception_handler;
Denis Vlasenko991a1da2008-02-10 19:02:53 +0000372
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200373 volatile int suppress_int; /* counter */
374 volatile /*sig_atomic_t*/ smallint pending_int; /* 1 = got SIGINT */
Denys Vlasenko458c1f22016-10-27 23:51:19 +0200375 volatile /*sig_atomic_t*/ smallint got_sigchld; /* 1 = got SIGCHLD */
Denys Vlasenko8f7b0242016-10-28 17:16:11 +0200376 volatile /*sig_atomic_t*/ smallint pending_sig; /* last pending signal */
Denis Vlasenko7f88e342009-03-19 03:36:18 +0000377 smallint exception_type; /* kind of exception (0..5) */
Denis Vlasenko01631112007-12-16 17:20:38 +0000378 /* exceptions */
Eric Andersenc470f442003-07-28 09:56:35 +0000379#define EXINT 0 /* SIGINT received */
380#define EXERROR 1 /* a generic error */
Eric Andersenc470f442003-07-28 09:56:35 +0000381#define EXEXIT 4 /* exit the shell */
Eric Andersen2870d962001-07-02 17:27:21 +0000382
Denis Vlasenkob07a4962008-06-22 13:16:23 +0000383 char nullstr[1]; /* zero length string */
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000384
385 char optlist[NOPTS];
386#define eflag optlist[0]
387#define fflag optlist[1]
388#define Iflag optlist[2]
389#define iflag optlist[3]
390#define mflag optlist[4]
391#define nflag optlist[5]
392#define sflag optlist[6]
393#define xflag optlist[7]
394#define vflag optlist[8]
395#define Cflag optlist[9]
396#define aflag optlist[10]
397#define bflag optlist[11]
398#define uflag optlist[12]
399#define viflag optlist[13]
Denys Vlasenko7d4aec02017-01-11 14:00:38 +0100400#if BASH_PIPEFAIL
Michael Abbott359da5e2009-12-04 23:03:29 +0100401# define pipefail optlist[14]
402#else
403# define pipefail 0
404#endif
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000405#if DEBUG
Denys Vlasenko7d4aec02017-01-11 14:00:38 +0100406# define nolog optlist[14 + BASH_PIPEFAIL]
407# define debug optlist[15 + BASH_PIPEFAIL]
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000408#endif
409
410 /* trap handler commands */
Denis Vlasenko01631112007-12-16 17:20:38 +0000411 /*
412 * Sigmode records the current value of the signal handlers for the various
413 * modes. A value of zero means that the current handler is not known.
Denis Vlasenkof8535cc2008-12-03 10:36:26 +0000414 * S_HARD_IGN indicates that the signal was ignored on entry to the shell.
Denis Vlasenko01631112007-12-16 17:20:38 +0000415 */
416 char sigmode[NSIG - 1];
Denis Vlasenkof8535cc2008-12-03 10:36:26 +0000417#define S_DFL 1 /* default signal handling (SIG_DFL) */
418#define S_CATCH 2 /* signal is caught */
419#define S_IGN 3 /* signal is ignored (SIG_IGN) */
Denys Vlasenko0f14f412017-08-06 20:06:19 +0200420#define S_HARD_IGN 4 /* signal is ignored permanently (it was SIG_IGN on entry to shell) */
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +0000421
Denis Vlasenko01631112007-12-16 17:20:38 +0000422 /* indicates specified signal received */
Denis Vlasenko4b875702009-03-19 13:30:04 +0000423 uint8_t gotsig[NSIG - 1]; /* offset by 1: "signal" 0 is meaningless */
Denys Vlasenko238bf182010-05-18 15:49:07 +0200424 uint8_t may_have_traps; /* 0: definitely no traps are set, 1: some traps may be set */
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000425 char *trap[NSIG];
Denys Vlasenko21d87d42009-09-25 00:06:51 +0200426 char **trap_ptr; /* used only by "trap hack" */
Denis Vlasenko448d30e2008-06-27 00:24:11 +0000427
428 /* Rarely referenced stuff */
429#if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenko3ea2e822009-10-09 20:59:04 +0200430 random_t random_gen;
Denis Vlasenko448d30e2008-06-27 00:24:11 +0000431#endif
432 pid_t backgndpid; /* pid of last background process */
Denis Vlasenko01631112007-12-16 17:20:38 +0000433};
Denys Vlasenko6f9442f2018-01-28 20:41:23 +0100434extern struct globals_misc *BB_GLOBAL_CONST ash_ptr_to_globals_misc;
Denis Vlasenko574f2f42008-02-27 18:41:59 +0000435#define G_misc (*ash_ptr_to_globals_misc)
Denys Vlasenko4d12e942016-10-01 16:03:11 +0200436#define exitstatus (G_misc.exitstatus )
437#define back_exitstatus (G_misc.back_exitstatus )
438#define job_warning (G_misc.job_warning)
Denis Vlasenko26bc57d2008-06-27 00:29:34 +0000439#define rootpid (G_misc.rootpid )
440#define shlvl (G_misc.shlvl )
Denys Vlasenko675d24a2018-01-27 22:02:05 +0100441#define errlinno (G_misc.errlinno )
Denis Vlasenko26bc57d2008-06-27 00:29:34 +0000442#define minusc (G_misc.minusc )
443#define curdir (G_misc.curdir )
444#define physdir (G_misc.physdir )
445#define arg0 (G_misc.arg0 )
Denis Vlasenko01631112007-12-16 17:20:38 +0000446#define exception_handler (G_misc.exception_handler)
Denis Vlasenko7f88e342009-03-19 03:36:18 +0000447#define exception_type (G_misc.exception_type )
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200448#define suppress_int (G_misc.suppress_int )
449#define pending_int (G_misc.pending_int )
Denys Vlasenko458c1f22016-10-27 23:51:19 +0200450#define got_sigchld (G_misc.got_sigchld )
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200451#define pending_sig (G_misc.pending_sig )
Denis Vlasenko26bc57d2008-06-27 00:29:34 +0000452#define nullstr (G_misc.nullstr )
453#define optlist (G_misc.optlist )
454#define sigmode (G_misc.sigmode )
455#define gotsig (G_misc.gotsig )
Denys Vlasenko238bf182010-05-18 15:49:07 +0200456#define may_have_traps (G_misc.may_have_traps )
Denis Vlasenko26bc57d2008-06-27 00:29:34 +0000457#define trap (G_misc.trap )
Denys Vlasenko21d87d42009-09-25 00:06:51 +0200458#define trap_ptr (G_misc.trap_ptr )
Denys Vlasenko3ea2e822009-10-09 20:59:04 +0200459#define random_gen (G_misc.random_gen )
Denis Vlasenko448d30e2008-06-27 00:24:11 +0000460#define backgndpid (G_misc.backgndpid )
Denis Vlasenko01631112007-12-16 17:20:38 +0000461#define INIT_G_misc() do { \
Denis Vlasenko574f2f42008-02-27 18:41:59 +0000462 (*(struct globals_misc**)&ash_ptr_to_globals_misc) = xzalloc(sizeof(G_misc)); \
463 barrier(); \
Denis Vlasenko01631112007-12-16 17:20:38 +0000464 curdir = nullstr; \
465 physdir = nullstr; \
Denys Vlasenko21d87d42009-09-25 00:06:51 +0200466 trap_ptr = trap; \
Denis Vlasenko01631112007-12-16 17:20:38 +0000467} while (0)
468
469
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000470/* ============ DEBUG */
471#if DEBUG
472static void trace_printf(const char *fmt, ...);
473static void trace_vprintf(const char *fmt, va_list va);
474# define TRACE(param) trace_printf param
475# define TRACEV(param) trace_vprintf param
Denis Vlasenko1bb3d7e2009-03-20 07:45:36 +0000476# define close(fd) do { \
477 int dfd = (fd); \
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +0000478 if (close(dfd) < 0) \
Denys Vlasenko883cea42009-07-11 15:31:59 +0200479 bb_error_msg("bug on %d: closing %d(0x%x)", \
Denis Vlasenko1bb3d7e2009-03-20 07:45:36 +0000480 __LINE__, dfd, dfd); \
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +0000481} while (0)
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000482#else
483# define TRACE(param)
484# define TRACEV(param)
485#endif
486
487
Denis Vlasenko559691a2008-10-05 18:39:31 +0000488/* ============ Utility functions */
Denys Vlasenko1961aea2013-02-26 00:36:53 +0100489#define is_name(c) ((c) == '_' || isalpha((unsigned char)(c)))
490#define is_in_name(c) ((c) == '_' || isalnum((unsigned char)(c)))
491
Denys Vlasenko37dc08b2016-10-02 04:38:07 +0200492static int
493isdigit_str9(const char *str)
Denis Vlasenko559691a2008-10-05 18:39:31 +0000494{
495 int maxlen = 9 + 1; /* max 9 digits: 999999999 */
496 while (--maxlen && isdigit(*str))
497 str++;
498 return (*str == '\0');
499}
Denis Vlasenko01631112007-12-16 17:20:38 +0000500
Denys Vlasenko37dc08b2016-10-02 04:38:07 +0200501static const char *
502var_end(const char *var)
Denys Vlasenko8837c5d2010-06-02 12:56:18 +0200503{
504 while (*var)
505 if (*var++ == '=')
506 break;
507 return var;
508}
509
Denis Vlasenko559691a2008-10-05 18:39:31 +0000510
511/* ============ Interrupts / exceptions */
Denys Vlasenko66c5b122011-02-08 05:07:02 +0100512
513static void exitshell(void) NORETURN;
514
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +0000515/*
Eric Andersen2870d962001-07-02 17:27:21 +0000516 * These macros allow the user to suspend the handling of interrupt signals
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +0000517 * over a period of time. This is similar to SIGHOLD or to sigblock, but
Eric Andersen2870d962001-07-02 17:27:21 +0000518 * much more efficient and portable. (But hacking the kernel is so much
519 * more fun than worrying about efficiency and portability. :-))
520 */
Denys Vlasenko06b11492016-11-04 16:43:18 +0100521#if DEBUG_INTONOFF
522# define INT_OFF do { \
523 TRACE(("%s:%d INT_OFF(%d)\n", __func__, __LINE__, suppress_int)); \
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200524 suppress_int++; \
Denys Vlasenkode892052016-10-02 01:49:13 +0200525 barrier(); \
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000526} while (0)
Denys Vlasenko06b11492016-11-04 16:43:18 +0100527#else
528# define INT_OFF do { \
529 suppress_int++; \
530 barrier(); \
531} while (0)
532#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +0000533
534/*
535 * Called to raise an exception. Since C doesn't include exceptions, we
536 * just do a longjmp to the exception handler. The type of exception is
Denis Vlasenko4b875702009-03-19 13:30:04 +0000537 * stored in the global variable "exception_type".
Denis Vlasenkob012b102007-02-19 22:43:01 +0000538 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000539static void raise_exception(int) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +0000540static void
541raise_exception(int e)
542{
543#if DEBUG
Denis Vlasenko2da584f2007-02-19 22:44:05 +0000544 if (exception_handler == NULL)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000545 abort();
546#endif
547 INT_OFF;
Denis Vlasenko7f88e342009-03-19 03:36:18 +0000548 exception_type = e;
Denis Vlasenko2da584f2007-02-19 22:44:05 +0000549 longjmp(exception_handler->loc, 1);
Denis Vlasenkob012b102007-02-19 22:43:01 +0000550}
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000551#if DEBUG
552#define raise_exception(e) do { \
553 TRACE(("raising exception %d on line %d\n", (e), __LINE__)); \
554 raise_exception(e); \
555} while (0)
556#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +0000557
558/*
Denys Vlasenkof37e1152016-10-07 03:17:28 +0200559 * Called when a SIGINT is received. (If the user specifies
Denis Vlasenkob012b102007-02-19 22:43:01 +0000560 * that SIGINT is to be trapped or ignored using the trap builtin, then
561 * this routine is not called.) Suppressint is nonzero when interrupts
562 * are held using the INT_OFF macro. (The test for iflag is just
563 * defensive programming.)
564 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000565static void raise_interrupt(void) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +0000566static void
567raise_interrupt(void)
568{
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200569 pending_int = 0;
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +0000570 /* Signal is not automatically unmasked after it is raised,
571 * do it ourself - unmask all signals */
Denis Vlasenko3f165fa2008-03-17 08:29:08 +0000572 sigprocmask_allsigs(SIG_UNBLOCK);
Denys Vlasenko238bf182010-05-18 15:49:07 +0200573 /* pending_sig = 0; - now done in signal_handler() */
Denis Vlasenko7c139b42007-03-21 20:17:27 +0000574
Denys Vlasenkoc0663c72016-10-27 21:09:01 +0200575 if (!(rootshell && iflag)) {
576 /* Kill ourself with SIGINT */
577 signal(SIGINT, SIG_DFL);
578 raise(SIGINT);
Denis Vlasenkob012b102007-02-19 22:43:01 +0000579 }
Denys Vlasenko4d12e942016-10-01 16:03:11 +0200580 /* bash: ^C even on empty command line sets $? */
581 exitstatus = SIGINT + 128;
Denys Vlasenkoc0663c72016-10-27 21:09:01 +0200582 raise_exception(EXINT);
Denis Vlasenkob012b102007-02-19 22:43:01 +0000583 /* NOTREACHED */
584}
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000585#if DEBUG
586#define raise_interrupt() do { \
587 TRACE(("raising interrupt on line %d\n", __LINE__)); \
588 raise_interrupt(); \
589} while (0)
590#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +0000591
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000592static IF_ASH_OPTIMIZE_FOR_SIZE(inline) void
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000593int_on(void)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000594{
Denys Vlasenkode892052016-10-02 01:49:13 +0200595 barrier();
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200596 if (--suppress_int == 0 && pending_int) {
Denis Vlasenkob012b102007-02-19 22:43:01 +0000597 raise_interrupt();
598 }
599}
Denys Vlasenko06b11492016-11-04 16:43:18 +0100600#if DEBUG_INTONOFF
601# define INT_ON do { \
602 TRACE(("%s:%d INT_ON(%d)\n", __func__, __LINE__, suppress_int-1)); \
603 int_on(); \
604} while (0)
605#else
606# define INT_ON int_on()
607#endif
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000608static IF_ASH_OPTIMIZE_FOR_SIZE(inline) void
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000609force_int_on(void)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000610{
Denys Vlasenkode892052016-10-02 01:49:13 +0200611 barrier();
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200612 suppress_int = 0;
613 if (pending_int)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000614 raise_interrupt();
615}
616#define FORCE_INT_ON force_int_on()
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000617
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200618#define SAVE_INT(v) ((v) = suppress_int)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000619
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000620#define RESTORE_INT(v) do { \
Denys Vlasenkode892052016-10-02 01:49:13 +0200621 barrier(); \
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200622 suppress_int = (v); \
623 if (suppress_int == 0 && pending_int) \
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000624 raise_interrupt(); \
625} while (0)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000626
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000627
Denis Vlasenkobc54cff2007-02-23 01:05:52 +0000628/* ============ Stdout/stderr output */
Eric Andersenc470f442003-07-28 09:56:35 +0000629
Eric Andersenc470f442003-07-28 09:56:35 +0000630static void
Denis Vlasenkob012b102007-02-19 22:43:01 +0000631outstr(const char *p, FILE *file)
Denis Vlasenkoe5570da2007-02-19 22:41:55 +0000632{
Denis Vlasenkob012b102007-02-19 22:43:01 +0000633 INT_OFF;
634 fputs(p, file);
635 INT_ON;
636}
637
638static void
639flush_stdout_stderr(void)
640{
641 INT_OFF;
Denys Vlasenko8131eea2009-11-02 14:19:51 +0100642 fflush_all();
Denis Vlasenkob012b102007-02-19 22:43:01 +0000643 INT_ON;
644}
645
Denys Vlasenko9c541002015-10-07 15:44:36 +0200646/* Was called outcslow(c,FILE*), but c was always '\n' */
Denis Vlasenkob012b102007-02-19 22:43:01 +0000647static void
Denys Vlasenko9c541002015-10-07 15:44:36 +0200648newline_and_flush(FILE *dest)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000649{
650 INT_OFF;
Denys Vlasenko9c541002015-10-07 15:44:36 +0200651 putc('\n', dest);
Denis Vlasenkob012b102007-02-19 22:43:01 +0000652 fflush(dest);
653 INT_ON;
654}
655
656static int out1fmt(const char *, ...) __attribute__((__format__(__printf__,1,2)));
657static int
658out1fmt(const char *fmt, ...)
659{
660 va_list ap;
661 int r;
662
663 INT_OFF;
664 va_start(ap, fmt);
665 r = vprintf(fmt, ap);
666 va_end(ap);
667 INT_ON;
668 return r;
669}
670
671static int fmtstr(char *, size_t, const char *, ...) __attribute__((__format__(__printf__,3,4)));
672static int
673fmtstr(char *outbuf, size_t length, const char *fmt, ...)
674{
675 va_list ap;
676 int ret;
677
Denis Vlasenkob012b102007-02-19 22:43:01 +0000678 INT_OFF;
Denys Vlasenkocf3a7962017-07-26 14:38:19 +0200679 va_start(ap, fmt);
Denis Vlasenkob012b102007-02-19 22:43:01 +0000680 ret = vsnprintf(outbuf, length, fmt, ap);
681 va_end(ap);
682 INT_ON;
683 return ret;
684}
685
686static void
687out1str(const char *p)
688{
689 outstr(p, stdout);
690}
691
692static void
693out2str(const char *p)
694{
695 outstr(p, stderr);
Denys Vlasenko8131eea2009-11-02 14:19:51 +0100696 flush_stdout_stderr();
Denis Vlasenkob012b102007-02-19 22:43:01 +0000697}
698
699
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +0000700/* ============ Parser structures */
Denis Vlasenko4d2183b2007-02-23 01:05:38 +0000701
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000702/* control characters in argument strings */
Denys Vlasenko2ce42e92009-11-29 02:18:13 +0100703#define CTL_FIRST CTLESC
Denys Vlasenkob6c84342009-08-29 20:23:20 +0200704#define CTLESC ((unsigned char)'\201') /* escape next character */
705#define CTLVAR ((unsigned char)'\202') /* variable defn */
706#define CTLENDVAR ((unsigned char)'\203')
707#define CTLBACKQ ((unsigned char)'\204')
Denys Vlasenkob6c84342009-08-29 20:23:20 +0200708#define CTLARI ((unsigned char)'\206') /* arithmetic expression */
709#define CTLENDARI ((unsigned char)'\207')
710#define CTLQUOTEMARK ((unsigned char)'\210')
Denys Vlasenko2ce42e92009-11-29 02:18:13 +0100711#define CTL_LAST CTLQUOTEMARK
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000712
713/* variable substitution byte (follows CTLVAR) */
714#define VSTYPE 0x0f /* type of variable substitution */
715#define VSNUL 0x10 /* colon--treat the empty string as unset */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000716
717/* values of VSTYPE field */
Denis Vlasenko92e13c22008-03-25 01:17:40 +0000718#define VSNORMAL 0x1 /* normal variable: $var or ${var} */
719#define VSMINUS 0x2 /* ${var-text} */
720#define VSPLUS 0x3 /* ${var+text} */
721#define VSQUESTION 0x4 /* ${var?message} */
722#define VSASSIGN 0x5 /* ${var=text} */
723#define VSTRIMRIGHT 0x6 /* ${var%pattern} */
724#define VSTRIMRIGHTMAX 0x7 /* ${var%%pattern} */
725#define VSTRIMLEFT 0x8 /* ${var#pattern} */
726#define VSTRIMLEFTMAX 0x9 /* ${var##pattern} */
727#define VSLENGTH 0xa /* ${#var} */
Denys Vlasenko7d4aec02017-01-11 14:00:38 +0100728#if BASH_SUBSTR
Denis Vlasenko92e13c22008-03-25 01:17:40 +0000729#define VSSUBSTR 0xc /* ${var:position:length} */
Denys Vlasenko7d4aec02017-01-11 14:00:38 +0100730#endif
731#if BASH_PATTERN_SUBST
Denis Vlasenko92e13c22008-03-25 01:17:40 +0000732#define VSREPLACE 0xd /* ${var/pattern/replacement} */
733#define VSREPLACEALL 0xe /* ${var//pattern/replacement} */
734#endif
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000735
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000736static const char dolatstr[] ALIGN1 = {
Ron Yorston549deab2015-05-18 09:57:51 +0200737 CTLQUOTEMARK, CTLVAR, VSNORMAL, '@', '=', CTLQUOTEMARK, '\0'
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000738};
Ron Yorston549deab2015-05-18 09:57:51 +0200739#define DOLATSTRLEN 6
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +0000740
Denis Vlasenko559691a2008-10-05 18:39:31 +0000741#define NCMD 0
742#define NPIPE 1
743#define NREDIR 2
744#define NBACKGND 3
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000745#define NSUBSHELL 4
Denis Vlasenko559691a2008-10-05 18:39:31 +0000746#define NAND 5
747#define NOR 6
748#define NSEMI 7
749#define NIF 8
750#define NWHILE 9
751#define NUNTIL 10
752#define NFOR 11
753#define NCASE 12
754#define NCLIST 13
755#define NDEFUN 14
756#define NARG 15
757#define NTO 16
Denys Vlasenko7d4aec02017-01-11 14:00:38 +0100758#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +0000759#define NTO2 17
760#endif
761#define NCLOBBER 18
762#define NFROM 19
763#define NFROMTO 20
764#define NAPPEND 21
765#define NTOFD 22
766#define NFROMFD 23
767#define NHERE 24
768#define NXHERE 25
769#define NNOT 26
Denis Vlasenko340299a2008-11-21 10:36:36 +0000770#define N_NUMBER 27
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000771
772union node;
773
774struct ncmd {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000775 smallint type; /* Nxxxx */
Denys Vlasenko675d24a2018-01-27 22:02:05 +0100776 int linno;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000777 union node *assign;
778 union node *args;
779 union node *redirect;
780};
781
782struct npipe {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000783 smallint type;
784 smallint pipe_backgnd;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000785 struct nodelist *cmdlist;
786};
787
788struct nredir {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000789 smallint type;
Denys Vlasenko675d24a2018-01-27 22:02:05 +0100790 int linno;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000791 union node *n;
792 union node *redirect;
793};
794
795struct nbinary {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000796 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000797 union node *ch1;
798 union node *ch2;
799};
800
801struct nif {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000802 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000803 union node *test;
804 union node *ifpart;
805 union node *elsepart;
806};
807
808struct nfor {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000809 smallint type;
Denys Vlasenko675d24a2018-01-27 22:02:05 +0100810 int linno;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000811 union node *args;
812 union node *body;
813 char *var;
814};
815
816struct ncase {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000817 smallint type;
Denys Vlasenko675d24a2018-01-27 22:02:05 +0100818 int linno;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000819 union node *expr;
820 union node *cases;
821};
822
823struct nclist {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000824 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000825 union node *next;
826 union node *pattern;
827 union node *body;
828};
829
Denys Vlasenko675d24a2018-01-27 22:02:05 +0100830struct ndefun {
831 smallint type;
832 int linno;
833 char *text;
834 union node *body;
835};
836
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000837struct narg {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000838 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000839 union node *next;
840 char *text;
841 struct nodelist *backquote;
842};
843
Denis Vlasenko559691a2008-10-05 18:39:31 +0000844/* nfile and ndup layout must match!
845 * NTOFD (>&fdnum) uses ndup structure, but we may discover mid-flight
846 * that it is actually NTO2 (>&file), and change its type.
847 */
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000848struct nfile {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000849 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000850 union node *next;
851 int fd;
Denis Vlasenko559691a2008-10-05 18:39:31 +0000852 int _unused_dupfd;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000853 union node *fname;
854 char *expfname;
855};
856
857struct ndup {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000858 smallint type;
Denis Vlasenko559691a2008-10-05 18:39:31 +0000859 union node *next;
860 int fd;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000861 int dupfd;
862 union node *vname;
Denis Vlasenko559691a2008-10-05 18:39:31 +0000863 char *_unused_expfname;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000864};
865
866struct nhere {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000867 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000868 union node *next;
869 int fd;
870 union node *doc;
871};
872
873struct nnot {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000874 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000875 union node *com;
876};
877
878union node {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000879 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000880 struct ncmd ncmd;
881 struct npipe npipe;
882 struct nredir nredir;
883 struct nbinary nbinary;
884 struct nif nif;
885 struct nfor nfor;
886 struct ncase ncase;
887 struct nclist nclist;
Denys Vlasenko675d24a2018-01-27 22:02:05 +0100888 struct ndefun ndefun;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000889 struct narg narg;
890 struct nfile nfile;
891 struct ndup ndup;
892 struct nhere nhere;
893 struct nnot nnot;
894};
895
Denys Vlasenko86e83ec2009-07-23 22:07:07 +0200896/*
897 * NODE_EOF is returned by parsecmd when it encounters an end of file.
898 * It must be distinct from NULL.
899 */
900#define NODE_EOF ((union node *) -1L)
901
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000902struct nodelist {
903 struct nodelist *next;
904 union node *n;
905};
906
907struct funcnode {
908 int count;
909 union node n;
910};
911
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000912/*
913 * Free a parse tree.
914 */
915static void
916freefunc(struct funcnode *f)
917{
918 if (f && --f->count < 0)
919 free(f);
920}
921
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000922
923/* ============ Debugging output */
924
925#if DEBUG
926
927static FILE *tracefile;
928
929static void
930trace_printf(const char *fmt, ...)
931{
932 va_list va;
933
934 if (debug != 1)
935 return;
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000936 if (DEBUG_TIME)
937 fprintf(tracefile, "%u ", (int) time(NULL));
938 if (DEBUG_PID)
939 fprintf(tracefile, "[%u] ", (int) getpid());
940 if (DEBUG_SIG)
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200941 fprintf(tracefile, "pending s:%d i:%d(supp:%d) ", pending_sig, pending_int, suppress_int);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000942 va_start(va, fmt);
943 vfprintf(tracefile, fmt, va);
944 va_end(va);
945}
946
947static void
948trace_vprintf(const char *fmt, va_list va)
949{
950 if (debug != 1)
951 return;
952 vfprintf(tracefile, fmt, va);
Denys Vlasenko474ed062016-10-30 18:30:29 +0100953 fprintf(tracefile, "\n");
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000954}
955
956static void
957trace_puts(const char *s)
958{
959 if (debug != 1)
960 return;
961 fputs(s, tracefile);
962}
963
964static void
965trace_puts_quoted(char *s)
966{
967 char *p;
968 char c;
969
970 if (debug != 1)
971 return;
972 putc('"', tracefile);
973 for (p = s; *p; p++) {
Denys Vlasenkocd716832009-11-28 22:14:02 +0100974 switch ((unsigned char)*p) {
975 case '\n': c = 'n'; goto backslash;
976 case '\t': c = 't'; goto backslash;
977 case '\r': c = 'r'; goto backslash;
978 case '\"': c = '\"'; goto backslash;
979 case '\\': c = '\\'; goto backslash;
980 case CTLESC: c = 'e'; goto backslash;
981 case CTLVAR: c = 'v'; goto backslash;
Denys Vlasenkocd716832009-11-28 22:14:02 +0100982 case CTLBACKQ: c = 'q'; goto backslash;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000983 backslash:
984 putc('\\', tracefile);
985 putc(c, tracefile);
986 break;
987 default:
988 if (*p >= ' ' && *p <= '~')
989 putc(*p, tracefile);
990 else {
991 putc('\\', tracefile);
Denys Vlasenkocd716832009-11-28 22:14:02 +0100992 putc((*p >> 6) & 03, tracefile);
993 putc((*p >> 3) & 07, tracefile);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000994 putc(*p & 07, tracefile);
995 }
996 break;
997 }
998 }
999 putc('"', tracefile);
1000}
1001
1002static void
1003trace_puts_args(char **ap)
1004{
1005 if (debug != 1)
1006 return;
1007 if (!*ap)
1008 return;
1009 while (1) {
1010 trace_puts_quoted(*ap);
1011 if (!*++ap) {
1012 putc('\n', tracefile);
1013 break;
1014 }
1015 putc(' ', tracefile);
1016 }
1017}
1018
1019static void
1020opentrace(void)
1021{
1022 char s[100];
1023#ifdef O_APPEND
1024 int flags;
1025#endif
1026
1027 if (debug != 1) {
1028 if (tracefile)
1029 fflush(tracefile);
1030 /* leave open because libedit might be using it */
1031 return;
1032 }
1033 strcpy(s, "./trace");
1034 if (tracefile) {
1035 if (!freopen(s, "a", tracefile)) {
1036 fprintf(stderr, "Can't re-open %s\n", s);
1037 debug = 0;
1038 return;
1039 }
1040 } else {
1041 tracefile = fopen(s, "a");
1042 if (tracefile == NULL) {
1043 fprintf(stderr, "Can't open %s\n", s);
1044 debug = 0;
1045 return;
1046 }
1047 }
1048#ifdef O_APPEND
Denis Vlasenkod37f2222007-08-19 13:42:08 +00001049 flags = fcntl(fileno(tracefile), F_GETFL);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001050 if (flags >= 0)
1051 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
1052#endif
1053 setlinebuf(tracefile);
1054 fputs("\nTracing started.\n", tracefile);
1055}
1056
1057static void
1058indent(int amount, char *pfx, FILE *fp)
1059{
1060 int i;
1061
1062 for (i = 0; i < amount; i++) {
1063 if (pfx && i == amount - 1)
1064 fputs(pfx, fp);
1065 putc('\t', fp);
1066 }
1067}
1068
1069/* little circular references here... */
1070static void shtree(union node *n, int ind, char *pfx, FILE *fp);
1071
1072static void
1073sharg(union node *arg, FILE *fp)
1074{
1075 char *p;
1076 struct nodelist *bqlist;
Denys Vlasenkocd716832009-11-28 22:14:02 +01001077 unsigned char subtype;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001078
1079 if (arg->type != NARG) {
1080 out1fmt("<node type %d>\n", arg->type);
1081 abort();
1082 }
1083 bqlist = arg->narg.backquote;
1084 for (p = arg->narg.text; *p; p++) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01001085 switch ((unsigned char)*p) {
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001086 case CTLESC:
Dan Fandrich77d48722010-09-07 23:38:28 -07001087 p++;
1088 putc(*p, fp);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001089 break;
1090 case CTLVAR:
1091 putc('$', fp);
1092 putc('{', fp);
1093 subtype = *++p;
1094 if (subtype == VSLENGTH)
1095 putc('#', fp);
1096
Dan Fandrich77d48722010-09-07 23:38:28 -07001097 while (*p != '=') {
1098 putc(*p, fp);
1099 p++;
1100 }
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001101
1102 if (subtype & VSNUL)
1103 putc(':', fp);
1104
1105 switch (subtype & VSTYPE) {
1106 case VSNORMAL:
1107 putc('}', fp);
1108 break;
1109 case VSMINUS:
1110 putc('-', fp);
1111 break;
1112 case VSPLUS:
1113 putc('+', fp);
1114 break;
1115 case VSQUESTION:
1116 putc('?', fp);
1117 break;
1118 case VSASSIGN:
1119 putc('=', fp);
1120 break;
1121 case VSTRIMLEFT:
1122 putc('#', fp);
1123 break;
1124 case VSTRIMLEFTMAX:
1125 putc('#', fp);
1126 putc('#', fp);
1127 break;
1128 case VSTRIMRIGHT:
1129 putc('%', fp);
1130 break;
1131 case VSTRIMRIGHTMAX:
1132 putc('%', fp);
1133 putc('%', fp);
1134 break;
1135 case VSLENGTH:
1136 break;
1137 default:
1138 out1fmt("<subtype %d>", subtype);
1139 }
1140 break;
1141 case CTLENDVAR:
1142 putc('}', fp);
1143 break;
1144 case CTLBACKQ:
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001145 putc('$', fp);
1146 putc('(', fp);
1147 shtree(bqlist->n, -1, NULL, fp);
1148 putc(')', fp);
1149 break;
1150 default:
1151 putc(*p, fp);
1152 break;
1153 }
1154 }
1155}
1156
Denys Vlasenko641dd7b2009-06-11 19:30:19 +02001157static void
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001158shcmd(union node *cmd, FILE *fp)
1159{
1160 union node *np;
1161 int first;
1162 const char *s;
1163 int dftfd;
1164
1165 first = 1;
1166 for (np = cmd->ncmd.args; np; np = np->narg.next) {
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001167 if (!first)
1168 putc(' ', fp);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001169 sharg(np, fp);
1170 first = 0;
1171 }
1172 for (np = cmd->ncmd.redirect; np; np = np->nfile.next) {
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001173 if (!first)
1174 putc(' ', fp);
1175 dftfd = 0;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001176 switch (np->nfile.type) {
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001177 case NTO: s = ">>"+1; dftfd = 1; break;
1178 case NCLOBBER: s = ">|"; dftfd = 1; break;
1179 case NAPPEND: s = ">>"; dftfd = 1; break;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01001180#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00001181 case NTO2:
1182#endif
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001183 case NTOFD: s = ">&"; dftfd = 1; break;
Denis Vlasenko559691a2008-10-05 18:39:31 +00001184 case NFROM: s = "<"; break;
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001185 case NFROMFD: s = "<&"; break;
1186 case NFROMTO: s = "<>"; break;
1187 default: s = "*error*"; break;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001188 }
1189 if (np->nfile.fd != dftfd)
1190 fprintf(fp, "%d", np->nfile.fd);
1191 fputs(s, fp);
1192 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
1193 fprintf(fp, "%d", np->ndup.dupfd);
1194 } else {
1195 sharg(np->nfile.fname, fp);
1196 }
1197 first = 0;
1198 }
1199}
1200
1201static void
1202shtree(union node *n, int ind, char *pfx, FILE *fp)
1203{
1204 struct nodelist *lp;
1205 const char *s;
1206
1207 if (n == NULL)
1208 return;
1209
1210 indent(ind, pfx, fp);
Denys Vlasenko86e83ec2009-07-23 22:07:07 +02001211
1212 if (n == NODE_EOF) {
1213 fputs("<EOF>", fp);
1214 return;
1215 }
1216
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001217 switch (n->type) {
1218 case NSEMI:
1219 s = "; ";
1220 goto binop;
1221 case NAND:
1222 s = " && ";
1223 goto binop;
1224 case NOR:
1225 s = " || ";
1226 binop:
1227 shtree(n->nbinary.ch1, ind, NULL, fp);
1228 /* if (ind < 0) */
1229 fputs(s, fp);
1230 shtree(n->nbinary.ch2, ind, NULL, fp);
1231 break;
1232 case NCMD:
1233 shcmd(n, fp);
1234 if (ind >= 0)
1235 putc('\n', fp);
1236 break;
1237 case NPIPE:
1238 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
Denys Vlasenko7cee00e2009-07-24 01:08:03 +02001239 shtree(lp->n, 0, NULL, fp);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001240 if (lp->next)
1241 fputs(" | ", fp);
1242 }
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00001243 if (n->npipe.pipe_backgnd)
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001244 fputs(" &", fp);
1245 if (ind >= 0)
1246 putc('\n', fp);
1247 break;
1248 default:
1249 fprintf(fp, "<node type %d>", n->type);
1250 if (ind >= 0)
1251 putc('\n', fp);
1252 break;
1253 }
1254}
1255
1256static void
1257showtree(union node *n)
1258{
1259 trace_puts("showtree called\n");
Denys Vlasenko883cea42009-07-11 15:31:59 +02001260 shtree(n, 1, NULL, stderr);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001261}
1262
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001263#endif /* DEBUG */
1264
1265
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00001266/* ============ Parser data */
1267
1268/*
Denis Vlasenkob012b102007-02-19 22:43:01 +00001269 * ash_vmsg() needs parsefile->fd, hence parsefile definition is moved up.
1270 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001271struct strlist {
1272 struct strlist *next;
1273 char *text;
1274};
1275
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001276struct alias;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001277
Denis Vlasenkob012b102007-02-19 22:43:01 +00001278struct strpush {
1279 struct strpush *prev; /* preceding string on stack */
Denis Vlasenko41eb3002008-11-28 03:42:31 +00001280 char *prev_string;
1281 int prev_left_in_line;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001282#if ENABLE_ASH_ALIAS
1283 struct alias *ap; /* if push was associated with an alias */
1284#endif
1285 char *string; /* remember the string since it may change */
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02001286
1287 /* Remember last two characters for pungetc. */
1288 int lastc[2];
1289
1290 /* Number of outstanding calls to pungetc. */
1291 int unget;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001292};
1293
Denys Vlasenko0485b672017-08-14 19:46:56 +02001294/*
1295 * The parsefile structure pointed to by the global variable parsefile
1296 * contains information about the current file being read.
1297 */
Denis Vlasenkob012b102007-02-19 22:43:01 +00001298struct parsefile {
1299 struct parsefile *prev; /* preceding file on stack */
1300 int linno; /* current line */
Denys Vlasenko79b3d422010-06-03 04:29:08 +02001301 int pf_fd; /* file descriptor (or -1 if string) */
Denis Vlasenko41eb3002008-11-28 03:42:31 +00001302 int left_in_line; /* number of chars left in this line */
1303 int left_in_buffer; /* number of chars left in this buffer past the line */
1304 char *next_to_pgetc; /* next char in buffer */
Denis Vlasenkob012b102007-02-19 22:43:01 +00001305 char *buf; /* input buffer */
1306 struct strpush *strpush; /* for pushing strings at this level */
1307 struct strpush basestrpush; /* so pushing one is fast */
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02001308
1309 /* Remember last two characters for pungetc. */
1310 int lastc[2];
1311
1312 /* Number of outstanding calls to pungetc. */
1313 int unget;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001314};
1315
Denis Vlasenko448d30e2008-06-27 00:24:11 +00001316static struct parsefile basepf; /* top level input file */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00001317static struct parsefile *g_parsefile = &basepf; /* current input file */
Denis Vlasenkob012b102007-02-19 22:43:01 +00001318static char *commandname; /* currently executing command */
Denis Vlasenkob012b102007-02-19 22:43:01 +00001319
1320
1321/* ============ Message printing */
1322
1323static void
1324ash_vmsg(const char *msg, va_list ap)
1325{
1326 fprintf(stderr, "%s: ", arg0);
1327 if (commandname) {
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00001328 if (strcmp(arg0, commandname))
1329 fprintf(stderr, "%s: ", commandname);
Denys Vlasenko79b3d422010-06-03 04:29:08 +02001330 if (!iflag || g_parsefile->pf_fd > 0)
Denys Vlasenko675d24a2018-01-27 22:02:05 +01001331 fprintf(stderr, "line %d: ", errlinno);
Eric Andersenc470f442003-07-28 09:56:35 +00001332 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00001333 vfprintf(stderr, msg, ap);
Denys Vlasenko9c541002015-10-07 15:44:36 +02001334 newline_and_flush(stderr);
Eric Andersenc470f442003-07-28 09:56:35 +00001335}
Denis Vlasenkob012b102007-02-19 22:43:01 +00001336
1337/*
1338 * Exverror is called to raise the error exception. If the second argument
1339 * is not NULL then error prints an error message using printf style
1340 * formatting. It then raises the error exception.
1341 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00001342static void ash_vmsg_and_raise(int, const char *, va_list) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001343static void
1344ash_vmsg_and_raise(int cond, const char *msg, va_list ap)
Eric Andersenc470f442003-07-28 09:56:35 +00001345{
Denis Vlasenkob012b102007-02-19 22:43:01 +00001346#if DEBUG
1347 if (msg) {
Denys Vlasenko474ed062016-10-30 18:30:29 +01001348 TRACE(("ash_vmsg_and_raise(%d):", cond));
Denis Vlasenkob012b102007-02-19 22:43:01 +00001349 TRACEV((msg, ap));
Denis Vlasenkob012b102007-02-19 22:43:01 +00001350 } else
Denys Vlasenko474ed062016-10-30 18:30:29 +01001351 TRACE(("ash_vmsg_and_raise(%d):NULL\n", cond));
Denis Vlasenkob012b102007-02-19 22:43:01 +00001352 if (msg)
1353#endif
1354 ash_vmsg(msg, ap);
1355
1356 flush_stdout_stderr();
1357 raise_exception(cond);
1358 /* NOTREACHED */
Eric Andersenc470f442003-07-28 09:56:35 +00001359}
Denis Vlasenkob012b102007-02-19 22:43:01 +00001360
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00001361static void ash_msg_and_raise_error(const char *, ...) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001362static void
1363ash_msg_and_raise_error(const char *msg, ...)
1364{
1365 va_list ap;
1366
Ron Yorstonea7d2f62017-01-03 11:18:23 +01001367 exitstatus = 2;
1368
Denis Vlasenkob012b102007-02-19 22:43:01 +00001369 va_start(ap, msg);
1370 ash_vmsg_and_raise(EXERROR, msg, ap);
1371 /* NOTREACHED */
1372 va_end(ap);
1373}
1374
Ron Yorstonbe366e52017-07-27 13:53:39 +01001375/*
Ron Yorstonbe366e52017-07-27 13:53:39 +01001376 * 'fmt' must be a string literal.
1377 */
Denys Vlasenko6f97b302017-09-29 18:17:25 +02001378#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 +01001379
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00001380static void raise_error_syntax(const char *) NORETURN;
1381static void
1382raise_error_syntax(const char *msg)
1383{
Denys Vlasenko675d24a2018-01-27 22:02:05 +01001384 errlinno = g_parsefile->linno;
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00001385 ash_msg_and_raise_error("syntax error: %s", msg);
1386 /* NOTREACHED */
1387}
1388
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00001389static void ash_msg_and_raise(int, const char *, ...) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001390static void
1391ash_msg_and_raise(int cond, const char *msg, ...)
1392{
1393 va_list ap;
1394
1395 va_start(ap, msg);
1396 ash_vmsg_and_raise(cond, msg, ap);
1397 /* NOTREACHED */
1398 va_end(ap);
1399}
1400
1401/*
1402 * error/warning routines for external builtins
1403 */
1404static void
1405ash_msg(const char *fmt, ...)
1406{
1407 va_list ap;
1408
1409 va_start(ap, fmt);
1410 ash_vmsg(fmt, ap);
1411 va_end(ap);
1412}
1413
1414/*
1415 * Return a string describing an error. The returned string may be a
1416 * pointer to a static buffer that will be overwritten on the next call.
1417 * Action describes the operation that got the error.
1418 */
1419static const char *
1420errmsg(int e, const char *em)
1421{
1422 if (e == ENOENT || e == ENOTDIR) {
1423 return em;
1424 }
1425 return strerror(e);
1426}
1427
1428
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001429/* ============ Memory allocation */
1430
Denys Vlasenkoe7670ff2009-10-11 00:45:25 +02001431#if 0
1432/* I consider these wrappers nearly useless:
1433 * ok, they return you to nearest exception handler, but
1434 * how much memory do you leak in the process, making
1435 * memory starvation worse?
1436 */
1437static void *
1438ckrealloc(void * p, size_t nbytes)
1439{
1440 p = realloc(p, nbytes);
1441 if (!p)
1442 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1443 return p;
1444}
1445
1446static void *
1447ckmalloc(size_t nbytes)
1448{
1449 return ckrealloc(NULL, nbytes);
1450}
1451
1452static void *
1453ckzalloc(size_t nbytes)
1454{
1455 return memset(ckmalloc(nbytes), 0, nbytes);
1456}
1457
1458static char *
1459ckstrdup(const char *s)
1460{
1461 char *p = strdup(s);
1462 if (!p)
1463 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1464 return p;
1465}
1466#else
1467/* Using bbox equivalents. They exit if out of memory */
1468# define ckrealloc xrealloc
1469# define ckmalloc xmalloc
1470# define ckzalloc xzalloc
1471# define ckstrdup xstrdup
1472#endif
1473
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001474/*
1475 * It appears that grabstackstr() will barf with such alignments
1476 * because stalloc() will return a string allocated in a new stackblock.
1477 */
1478#define SHELL_ALIGN(nbytes) (((nbytes) + SHELL_SIZE) & ~SHELL_SIZE)
1479enum {
1480 /* Most machines require the value returned from malloc to be aligned
1481 * in some way. The following macro will get this right
1482 * on many machines. */
Denys Vlasenko0e5e4ea2009-10-11 00:36:20 +02001483 SHELL_SIZE = sizeof(union { int i; char *cp; double d; }) - 1,
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001484 /* Minimum size of a block */
Denis Vlasenko01631112007-12-16 17:20:38 +00001485 MINSIZE = SHELL_ALIGN(504),
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001486};
1487
1488struct stack_block {
1489 struct stack_block *prev;
1490 char space[MINSIZE];
1491};
1492
1493struct stackmark {
1494 struct stack_block *stackp;
1495 char *stacknxt;
1496 size_t stacknleft;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001497};
1498
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001499
Denis Vlasenko01631112007-12-16 17:20:38 +00001500struct globals_memstack {
1501 struct stack_block *g_stackp; // = &stackbase;
Denis Vlasenko01631112007-12-16 17:20:38 +00001502 char *g_stacknxt; // = stackbase.space;
1503 char *sstrend; // = stackbase.space + MINSIZE;
1504 size_t g_stacknleft; // = MINSIZE;
Denis Vlasenko01631112007-12-16 17:20:38 +00001505 struct stack_block stackbase;
1506};
Denys Vlasenko6f9442f2018-01-28 20:41:23 +01001507extern struct globals_memstack *BB_GLOBAL_CONST ash_ptr_to_globals_memstack;
Denis Vlasenko574f2f42008-02-27 18:41:59 +00001508#define G_memstack (*ash_ptr_to_globals_memstack)
Denis Vlasenko01631112007-12-16 17:20:38 +00001509#define g_stackp (G_memstack.g_stackp )
Denis Vlasenko01631112007-12-16 17:20:38 +00001510#define g_stacknxt (G_memstack.g_stacknxt )
1511#define sstrend (G_memstack.sstrend )
1512#define g_stacknleft (G_memstack.g_stacknleft)
Denis Vlasenko01631112007-12-16 17:20:38 +00001513#define stackbase (G_memstack.stackbase )
1514#define INIT_G_memstack() do { \
Denis Vlasenko574f2f42008-02-27 18:41:59 +00001515 (*(struct globals_memstack**)&ash_ptr_to_globals_memstack) = xzalloc(sizeof(G_memstack)); \
1516 barrier(); \
Denis Vlasenko01631112007-12-16 17:20:38 +00001517 g_stackp = &stackbase; \
1518 g_stacknxt = stackbase.space; \
1519 g_stacknleft = MINSIZE; \
1520 sstrend = stackbase.space + MINSIZE; \
Denis Vlasenko01631112007-12-16 17:20:38 +00001521} while (0)
1522
Denys Vlasenkoe7670ff2009-10-11 00:45:25 +02001523
Denis Vlasenko01631112007-12-16 17:20:38 +00001524#define stackblock() ((void *)g_stacknxt)
1525#define stackblocksize() g_stacknleft
1526
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001527/*
1528 * Parse trees for commands are allocated in lifo order, so we use a stack
1529 * to make this more efficient, and also to avoid all sorts of exception
1530 * handling code to handle interrupts in the middle of a parse.
1531 *
1532 * The size 504 was chosen because the Ultrix malloc handles that size
1533 * well.
1534 */
1535static void *
1536stalloc(size_t nbytes)
1537{
1538 char *p;
1539 size_t aligned;
1540
1541 aligned = SHELL_ALIGN(nbytes);
Denis Vlasenko01631112007-12-16 17:20:38 +00001542 if (aligned > g_stacknleft) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001543 size_t len;
1544 size_t blocksize;
1545 struct stack_block *sp;
1546
1547 blocksize = aligned;
1548 if (blocksize < MINSIZE)
1549 blocksize = MINSIZE;
1550 len = sizeof(struct stack_block) - MINSIZE + blocksize;
1551 if (len < blocksize)
1552 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1553 INT_OFF;
1554 sp = ckmalloc(len);
Denis Vlasenko01631112007-12-16 17:20:38 +00001555 sp->prev = g_stackp;
1556 g_stacknxt = sp->space;
1557 g_stacknleft = blocksize;
1558 sstrend = g_stacknxt + blocksize;
1559 g_stackp = sp;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001560 INT_ON;
1561 }
Denis Vlasenko01631112007-12-16 17:20:38 +00001562 p = g_stacknxt;
1563 g_stacknxt += aligned;
1564 g_stacknleft -= aligned;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001565 return p;
1566}
1567
Denis Vlasenko597906c2008-02-20 16:38:54 +00001568static void *
1569stzalloc(size_t nbytes)
1570{
1571 return memset(stalloc(nbytes), 0, nbytes);
1572}
1573
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001574static void
1575stunalloc(void *p)
1576{
1577#if DEBUG
Denis Vlasenko01631112007-12-16 17:20:38 +00001578 if (!p || (g_stacknxt < (char *)p) || ((char *)p < g_stackp->space)) {
Bernhard Reutner-Fischer5e25ddb2008-05-19 09:48:17 +00001579 write(STDERR_FILENO, "stunalloc\n", 10);
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001580 abort();
1581 }
1582#endif
Denis Vlasenko01631112007-12-16 17:20:38 +00001583 g_stacknleft += g_stacknxt - (char *)p;
1584 g_stacknxt = p;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001585}
1586
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001587/*
1588 * Like strdup but works with the ash stack.
1589 */
1590static char *
Denys Vlasenko8e2bc472016-09-28 23:02:57 +02001591sstrdup(const char *p)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001592{
1593 size_t len = strlen(p) + 1;
1594 return memcpy(stalloc(len), p, len);
1595}
1596
Denys Vlasenko03c36e02018-01-10 15:18:35 +01001597static ALWAYS_INLINE void
Denys Vlasenko60ca8342016-09-30 11:21:21 +02001598grabstackblock(size_t len)
1599{
Denys Vlasenkoa318bba2016-10-26 18:26:27 +02001600 stalloc(len);
Denys Vlasenko60ca8342016-09-30 11:21:21 +02001601}
1602
1603static void
1604pushstackmark(struct stackmark *mark, size_t len)
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001605{
Denis Vlasenko01631112007-12-16 17:20:38 +00001606 mark->stackp = g_stackp;
1607 mark->stacknxt = g_stacknxt;
1608 mark->stacknleft = g_stacknleft;
Denys Vlasenko60ca8342016-09-30 11:21:21 +02001609 grabstackblock(len);
1610}
1611
1612static void
1613setstackmark(struct stackmark *mark)
1614{
1615 pushstackmark(mark, g_stacknxt == g_stackp->space && g_stackp != &stackbase);
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001616}
1617
1618static void
1619popstackmark(struct stackmark *mark)
1620{
1621 struct stack_block *sp;
1622
Denis Vlasenko93ebd4f2007-03-13 20:55:36 +00001623 if (!mark->stackp)
1624 return;
1625
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001626 INT_OFF;
Denis Vlasenko01631112007-12-16 17:20:38 +00001627 while (g_stackp != mark->stackp) {
1628 sp = g_stackp;
1629 g_stackp = sp->prev;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001630 free(sp);
1631 }
Denis Vlasenko01631112007-12-16 17:20:38 +00001632 g_stacknxt = mark->stacknxt;
1633 g_stacknleft = mark->stacknleft;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001634 sstrend = mark->stacknxt + mark->stacknleft;
1635 INT_ON;
1636}
1637
1638/*
1639 * When the parser reads in a string, it wants to stick the string on the
1640 * stack and only adjust the stack pointer when it knows how big the
1641 * string is. Stackblock (defined in stack.h) returns a pointer to a block
1642 * of space on top of the stack and stackblocklen returns the length of
1643 * this block. Growstackblock will grow this space by at least one byte,
1644 * possibly moving it (like realloc). Grabstackblock actually allocates the
1645 * part of the block that has been used.
1646 */
1647static void
1648growstackblock(void)
1649{
1650 size_t newlen;
1651
Denis Vlasenko01631112007-12-16 17:20:38 +00001652 newlen = g_stacknleft * 2;
1653 if (newlen < g_stacknleft)
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001654 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1655 if (newlen < 128)
1656 newlen += 128;
1657
Denis Vlasenko01631112007-12-16 17:20:38 +00001658 if (g_stacknxt == g_stackp->space && g_stackp != &stackbase) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001659 struct stack_block *sp;
1660 struct stack_block *prevstackp;
1661 size_t grosslen;
1662
1663 INT_OFF;
Denis Vlasenko01631112007-12-16 17:20:38 +00001664 sp = g_stackp;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001665 prevstackp = sp->prev;
1666 grosslen = newlen + sizeof(struct stack_block) - MINSIZE;
1667 sp = ckrealloc(sp, grosslen);
1668 sp->prev = prevstackp;
Denis Vlasenko01631112007-12-16 17:20:38 +00001669 g_stackp = sp;
1670 g_stacknxt = sp->space;
1671 g_stacknleft = newlen;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001672 sstrend = sp->space + newlen;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001673 INT_ON;
1674 } else {
Denis Vlasenko01631112007-12-16 17:20:38 +00001675 char *oldspace = g_stacknxt;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001676 size_t oldlen = g_stacknleft;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001677 char *p = stalloc(newlen);
1678
1679 /* free the space we just allocated */
Denis Vlasenko01631112007-12-16 17:20:38 +00001680 g_stacknxt = memcpy(p, oldspace, oldlen);
1681 g_stacknleft += newlen;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001682 }
1683}
1684
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001685/*
1686 * The following routines are somewhat easier to use than the above.
1687 * The user declares a variable of type STACKSTR, which may be declared
1688 * to be a register. The macro STARTSTACKSTR initializes things. Then
1689 * the user uses the macro STPUTC to add characters to the string. In
1690 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
1691 * grown as necessary. When the user is done, she can just leave the
1692 * string there and refer to it using stackblock(). Or she can allocate
1693 * the space for it using grabstackstr(). If it is necessary to allow
1694 * someone else to use the stack temporarily and then continue to grow
1695 * the string, the user should use grabstack to allocate the space, and
1696 * then call ungrabstr(p) to return to the previous mode of operation.
1697 *
1698 * USTPUTC is like STPUTC except that it doesn't check for overflow.
1699 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
1700 * is space for at least one character.
1701 */
1702static void *
1703growstackstr(void)
1704{
1705 size_t len = stackblocksize();
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001706 growstackblock();
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001707 return (char *)stackblock() + len;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001708}
1709
1710/*
1711 * Called from CHECKSTRSPACE.
1712 */
1713static char *
1714makestrspace(size_t newlen, char *p)
1715{
Denis Vlasenko01631112007-12-16 17:20:38 +00001716 size_t len = p - g_stacknxt;
Denys Vlasenko53d6e032016-09-30 11:24:12 +02001717 size_t size;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001718
1719 for (;;) {
1720 size_t nleft;
1721
1722 size = stackblocksize();
1723 nleft = size - len;
1724 if (nleft >= newlen)
1725 break;
1726 growstackblock();
1727 }
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001728 return (char *)stackblock() + len;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001729}
1730
1731static char *
1732stack_nputstr(const char *s, size_t n, char *p)
1733{
1734 p = makestrspace(n, p);
Denys Vlasenko5ace96a2017-07-23 21:46:02 +02001735 p = (char *)mempcpy(p, s, n);
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001736 return p;
1737}
1738
1739static char *
1740stack_putstr(const char *s, char *p)
1741{
1742 return stack_nputstr(s, strlen(s), p);
1743}
1744
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001745static char *
1746_STPUTC(int c, char *p)
1747{
1748 if (p == sstrend)
1749 p = growstackstr();
1750 *p++ = c;
1751 return p;
1752}
1753
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00001754#define STARTSTACKSTR(p) ((p) = stackblock())
1755#define STPUTC(c, p) ((p) = _STPUTC((c), (p)))
Denis Vlasenko843cbd52008-06-27 00:23:18 +00001756#define CHECKSTRSPACE(n, p) do { \
1757 char *q = (p); \
1758 size_t l = (n); \
1759 size_t m = sstrend - q; \
1760 if (l > m) \
1761 (p) = makestrspace(l, q); \
1762} while (0)
Denis Vlasenkoef527f52008-06-23 01:52:30 +00001763#define USTPUTC(c, p) (*(p)++ = (c))
Denis Vlasenko843cbd52008-06-27 00:23:18 +00001764#define STACKSTRNUL(p) do { \
1765 if ((p) == sstrend) \
1766 (p) = growstackstr(); \
1767 *(p) = '\0'; \
1768} while (0)
Denis Vlasenkoef527f52008-06-23 01:52:30 +00001769#define STUNPUTC(p) (--(p))
1770#define STTOPC(p) ((p)[-1])
1771#define STADJUST(amount, p) ((p) += (amount))
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001772
1773#define grabstackstr(p) stalloc((char *)(p) - (char *)stackblock())
Denis Vlasenkoef527f52008-06-23 01:52:30 +00001774#define ungrabstackstr(s, p) stunalloc(s)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001775#define stackstrend() ((void *)sstrend)
1776
1777
1778/* ============ String helpers */
1779
1780/*
1781 * prefix -- see if pfx is a prefix of string.
1782 */
1783static char *
1784prefix(const char *string, const char *pfx)
1785{
1786 while (*pfx) {
1787 if (*pfx++ != *string++)
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00001788 return NULL;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001789 }
1790 return (char *) string;
1791}
1792
1793/*
1794 * Check for a valid number. This should be elsewhere.
1795 */
1796static int
1797is_number(const char *p)
1798{
1799 do {
1800 if (!isdigit(*p))
1801 return 0;
1802 } while (*++p != '\0');
1803 return 1;
1804}
1805
1806/*
1807 * Convert a string of digits to an integer, printing an error message on
1808 * failure.
1809 */
1810static int
1811number(const char *s)
1812{
1813 if (!is_number(s))
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02001814 ash_msg_and_raise_error(msg_illnum, s);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001815 return atoi(s);
1816}
1817
1818/*
Denys Vlasenko42ba7572017-07-21 13:20:14 +02001819 * Produce a single quoted string suitable as input to the shell.
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001820 * The return string is allocated on the stack.
1821 */
1822static char *
1823single_quote(const char *s)
1824{
1825 char *p;
1826
1827 STARTSTACKSTR(p);
1828
1829 do {
1830 char *q;
1831 size_t len;
1832
1833 len = strchrnul(s, '\'') - s;
1834
1835 q = p = makestrspace(len + 3, p);
1836
1837 *q++ = '\'';
Denys Vlasenko94af83e2017-07-23 21:55:40 +02001838 q = (char *)mempcpy(q, s, len);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001839 *q++ = '\'';
1840 s += len;
1841
1842 STADJUST(q - p, p);
1843
Denys Vlasenkocd716832009-11-28 22:14:02 +01001844 if (*s != '\'')
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001845 break;
Denys Vlasenkocd716832009-11-28 22:14:02 +01001846 len = 0;
1847 do len++; while (*++s == '\'');
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001848
1849 q = p = makestrspace(len + 3, p);
1850
1851 *q++ = '"';
Denys Vlasenko5ace96a2017-07-23 21:46:02 +02001852 q = (char *)mempcpy(q, s - len, len);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001853 *q++ = '"';
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001854
1855 STADJUST(q - p, p);
1856 } while (*s);
1857
Denys Vlasenkocd716832009-11-28 22:14:02 +01001858 USTPUTC('\0', p);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001859
1860 return stackblock();
1861}
1862
Denys Vlasenko42ba7572017-07-21 13:20:14 +02001863/*
1864 * Produce a possibly single quoted string suitable as input to the shell.
Denys Vlasenko42ba7572017-07-21 13:20:14 +02001865 * If quoting was done, the return string is allocated on the stack,
1866 * otherwise a pointer to the original string is returned.
1867 */
1868static const char *
1869maybe_single_quote(const char *s)
1870{
1871 const char *p = s;
1872
1873 while (*p) {
1874 /* Assuming ACSII */
1875 /* quote ctrl_chars space !"#$%&'()* */
1876 if (*p < '+')
1877 goto need_quoting;
1878 /* quote ;<=>? */
1879 if (*p >= ';' && *p <= '?')
1880 goto need_quoting;
1881 /* quote `[\ */
1882 if (*p == '`')
1883 goto need_quoting;
1884 if (*p == '[')
1885 goto need_quoting;
1886 if (*p == '\\')
1887 goto need_quoting;
1888 /* quote {|}~ DEL and high bytes */
1889 if (*p > 'z')
1890 goto need_quoting;
1891 /* Not quoting these: +,-./ 0-9 :@ A-Z ]^_ a-z */
1892 /* TODO: maybe avoid quoting % */
1893 p++;
1894 }
1895 return s;
1896
1897 need_quoting:
1898 return single_quote(s);
1899}
1900
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001901
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00001902/* ============ nextopt */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001903
1904static char **argptr; /* argument list for builtin commands */
1905static char *optionarg; /* set by nextopt (like getopt) */
1906static char *optptr; /* used by nextopt */
1907
1908/*
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001909 * XXX - should get rid of. Have all builtins use getopt(3).
1910 * The library getopt must have the BSD extension static variable
1911 * "optreset", otherwise it can't be used within the shell safely.
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001912 *
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001913 * Standard option processing (a la getopt) for builtin routines.
1914 * The only argument that is passed to nextopt is the option string;
1915 * the other arguments are unnecessary. It returns the character,
1916 * or '\0' on end of input.
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001917 */
1918static int
1919nextopt(const char *optstring)
1920{
1921 char *p;
1922 const char *q;
1923 char c;
1924
1925 p = optptr;
1926 if (p == NULL || *p == '\0') {
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001927 /* We ate entire "-param", take next one */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001928 p = *argptr;
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001929 if (p == NULL)
1930 return '\0';
1931 if (*p != '-')
1932 return '\0';
1933 if (*++p == '\0') /* just "-" ? */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001934 return '\0';
1935 argptr++;
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001936 if (LONE_DASH(p)) /* "--" ? */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001937 return '\0';
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001938 /* p => next "-param" */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001939 }
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001940 /* p => some option char in the middle of a "-param" */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001941 c = *p++;
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +00001942 for (q = optstring; *q != c;) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001943 if (*q == '\0')
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00001944 ash_msg_and_raise_error("illegal option -%c", c);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001945 if (*++q == ':')
1946 q++;
1947 }
1948 if (*++q == ':') {
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001949 if (*p == '\0') {
1950 p = *argptr++;
1951 if (p == NULL)
1952 ash_msg_and_raise_error("no arg for -%c option", c);
1953 }
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001954 optionarg = p;
1955 p = NULL;
1956 }
1957 optptr = p;
1958 return c;
1959}
1960
1961
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00001962/* ============ Shell variables */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001963
Denis Vlasenko01631112007-12-16 17:20:38 +00001964struct shparam {
1965 int nparam; /* # of positional parameters (without $0) */
1966#if ENABLE_ASH_GETOPTS
1967 int optind; /* next parameter to be processed by getopts */
1968 int optoff; /* used by getopts */
1969#endif
1970 unsigned char malloced; /* if parameter list dynamically allocated */
1971 char **p; /* parameter list */
1972};
1973
1974/*
1975 * Free the list of positional parameters.
1976 */
1977static void
1978freeparam(volatile struct shparam *param)
1979{
Denis Vlasenko01631112007-12-16 17:20:38 +00001980 if (param->malloced) {
Denis Vlasenko3177ba02008-07-13 20:39:23 +00001981 char **ap, **ap1;
1982 ap = ap1 = param->p;
1983 while (*ap)
1984 free(*ap++);
1985 free(ap1);
Denis Vlasenko01631112007-12-16 17:20:38 +00001986 }
1987}
1988
1989#if ENABLE_ASH_GETOPTS
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02001990static void FAST_FUNC getoptsreset(const char *value);
Denis Vlasenko01631112007-12-16 17:20:38 +00001991#endif
1992
1993struct var {
1994 struct var *next; /* next entry in hash list */
1995 int flags; /* flags are defined above */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001996 const char *var_text; /* name=value */
1997 void (*var_func)(const char *) FAST_FUNC; /* function to be called when */
Denis Vlasenko01631112007-12-16 17:20:38 +00001998 /* the variable gets set/unset */
1999};
2000
2001struct localvar {
2002 struct localvar *next; /* next local variable in list */
2003 struct var *vp; /* the variable that was made local */
2004 int flags; /* saved flags */
2005 const char *text; /* saved text */
2006};
2007
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002008/* flags */
2009#define VEXPORT 0x01 /* variable is exported */
2010#define VREADONLY 0x02 /* variable cannot be modified */
2011#define VSTRFIXED 0x04 /* variable struct is statically allocated */
2012#define VTEXTFIXED 0x08 /* text is statically allocated */
2013#define VSTACK 0x10 /* text is allocated on the stack */
2014#define VUNSET 0x20 /* the variable is not set */
2015#define VNOFUNC 0x40 /* don't call the callback function */
2016#define VNOSET 0x80 /* do not set variable - just readonly test */
2017#define VNOSAVE 0x100 /* when text is on the heap before setvareq */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00002018#if ENABLE_ASH_RANDOM_SUPPORT
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00002019# define VDYNAMIC 0x200 /* dynamic variable */
2020#else
2021# define VDYNAMIC 0
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002022#endif
2023
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00002024
Denis Vlasenko01631112007-12-16 17:20:38 +00002025/* Need to be before varinit_data[] */
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00002026#if ENABLE_LOCALE_SUPPORT
Denys Vlasenko2634bf32009-06-09 18:40:07 +02002027static void FAST_FUNC
Denis Vlasenkoa8915072007-02-23 21:10:06 +00002028change_lc_all(const char *value)
2029{
2030 if (value && *value != '\0')
2031 setlocale(LC_ALL, value);
2032}
Denys Vlasenko2634bf32009-06-09 18:40:07 +02002033static void FAST_FUNC
Denis Vlasenkoa8915072007-02-23 21:10:06 +00002034change_lc_ctype(const char *value)
2035{
2036 if (value && *value != '\0')
2037 setlocale(LC_CTYPE, value);
2038}
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00002039#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002040#if ENABLE_ASH_MAIL
2041static void chkmail(void);
Denys Vlasenko8c52f802011-02-04 17:36:21 +01002042static void changemail(const char *var_value) FAST_FUNC;
2043#else
2044# define chkmail() ((void)0)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002045#endif
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02002046static void changepath(const char *) FAST_FUNC;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002047#if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02002048static void change_random(const char *) FAST_FUNC;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002049#endif
2050
Denis Vlasenko01631112007-12-16 17:20:38 +00002051static const struct {
2052 int flags;
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002053 const char *var_text;
2054 void (*var_func)(const char *) FAST_FUNC;
Denis Vlasenko01631112007-12-16 17:20:38 +00002055} varinit_data[] = {
Denys Vlasenko566a3132012-07-07 21:40:35 +02002056 /*
2057 * Note: VEXPORT would not work correctly here for NOFORK applets:
2058 * some environment strings may be constant.
2059 */
Denis Vlasenko01631112007-12-16 17:20:38 +00002060 { VSTRFIXED|VTEXTFIXED , defifsvar , NULL },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002061#if ENABLE_ASH_MAIL
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002062 { VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL" , changemail },
2063 { VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH" , changemail },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002064#endif
Denis Vlasenko01631112007-12-16 17:20:38 +00002065 { VSTRFIXED|VTEXTFIXED , bb_PATH_root_path, changepath },
2066 { VSTRFIXED|VTEXTFIXED , "PS1=$ " , NULL },
2067 { VSTRFIXED|VTEXTFIXED , "PS2=> " , NULL },
2068 { VSTRFIXED|VTEXTFIXED , "PS4=+ " , NULL },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002069#if ENABLE_ASH_GETOPTS
Denys Vlasenkoe627ac92016-09-30 14:36:59 +02002070 { VSTRFIXED|VTEXTFIXED , defoptindvar, getoptsreset },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002071#endif
Denys Vlasenko675d24a2018-01-27 22:02:05 +01002072 { VSTRFIXED|VTEXTFIXED , NULL /* inited to linenovar */, NULL },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002073#if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002074 { VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM", change_random },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002075#endif
2076#if ENABLE_LOCALE_SUPPORT
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002077 { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_ALL" , change_lc_all },
2078 { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_CTYPE" , change_lc_ctype },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002079#endif
2080#if ENABLE_FEATURE_EDITING_SAVEHISTORY
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002081 { VSTRFIXED|VTEXTFIXED|VUNSET, "HISTFILE" , NULL },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002082#endif
2083};
2084
Denis Vlasenko0b769642008-07-24 07:54:57 +00002085struct redirtab;
Denis Vlasenko01631112007-12-16 17:20:38 +00002086
2087struct globals_var {
2088 struct shparam shellparam; /* $@ current positional parameters */
2089 struct redirtab *redirlist;
Denys Vlasenkod07a15b2017-07-30 16:51:05 +02002090 int preverrout_fd; /* stderr fd: usually 2, unless redirect moved it */
Denis Vlasenko01631112007-12-16 17:20:38 +00002091 struct var *vartab[VTABSIZE];
2092 struct var varinit[ARRAY_SIZE(varinit_data)];
Denys Vlasenko675d24a2018-01-27 22:02:05 +01002093 int lineno;
2094 char linenovar[sizeof("LINENO=") + sizeof(int)*3];
Denis Vlasenko01631112007-12-16 17:20:38 +00002095};
Denys Vlasenko6f9442f2018-01-28 20:41:23 +01002096extern struct globals_var *BB_GLOBAL_CONST ash_ptr_to_globals_var;
Denis Vlasenko574f2f42008-02-27 18:41:59 +00002097#define G_var (*ash_ptr_to_globals_var)
Denis Vlasenko01631112007-12-16 17:20:38 +00002098#define shellparam (G_var.shellparam )
Denis Vlasenko0b769642008-07-24 07:54:57 +00002099//#define redirlist (G_var.redirlist )
Denis Vlasenko01631112007-12-16 17:20:38 +00002100#define preverrout_fd (G_var.preverrout_fd)
2101#define vartab (G_var.vartab )
2102#define varinit (G_var.varinit )
Denys Vlasenko675d24a2018-01-27 22:02:05 +01002103#define lineno (G_var.lineno )
2104#define linenovar (G_var.linenovar )
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002105#define vifs varinit[0]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002106#if ENABLE_ASH_MAIL
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002107# define vmail (&vifs)[1]
2108# define vmpath (&vmail)[1]
2109# define vpath (&vmpath)[1]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002110#else
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002111# define vpath (&vifs)[1]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002112#endif
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002113#define vps1 (&vpath)[1]
2114#define vps2 (&vps1)[1]
2115#define vps4 (&vps2)[1]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002116#if ENABLE_ASH_GETOPTS
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002117# define voptind (&vps4)[1]
Denys Vlasenko675d24a2018-01-27 22:02:05 +01002118# define vlineno (&voptind)[1]
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002119# if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenko675d24a2018-01-27 22:02:05 +01002120# define vrandom (&vlineno)[1]
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002121# endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002122#else
Denys Vlasenko675d24a2018-01-27 22:02:05 +01002123# define vlineno (&vps4)[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#endif
Denys Vlasenko675d24a2018-01-27 22:02:05 +01002128#define INIT_G_var() do { \
2129 unsigned i; \
2130 (*(struct globals_var**)&ash_ptr_to_globals_var) = xzalloc(sizeof(G_var)); \
2131 barrier(); \
2132 for (i = 0; i < ARRAY_SIZE(varinit_data); i++) { \
2133 varinit[i].flags = varinit_data[i].flags; \
2134 varinit[i].var_text = varinit_data[i].var_text; \
2135 varinit[i].var_func = varinit_data[i].var_func; \
2136 } \
2137 strcpy(linenovar, "LINENO="); \
2138 vlineno.var_text = linenovar; \
2139} while (0)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002140
2141/*
2142 * The following macros access the values of the above variables.
2143 * They have to skip over the name. They return the null string
2144 * for unset variables.
2145 */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002146#define ifsval() (vifs.var_text + 4)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002147#define ifsset() ((vifs.flags & VUNSET) == 0)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002148#if ENABLE_ASH_MAIL
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002149# define mailval() (vmail.var_text + 5)
2150# define mpathval() (vmpath.var_text + 9)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002151# define mpathset() ((vmpath.flags & VUNSET) == 0)
2152#endif
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002153#define pathval() (vpath.var_text + 5)
2154#define ps1val() (vps1.var_text + 4)
2155#define ps2val() (vps2.var_text + 4)
2156#define ps4val() (vps4.var_text + 4)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002157#if ENABLE_ASH_GETOPTS
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002158# define optindval() (voptind.var_text + 7)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002159#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002160
Denis Vlasenko01631112007-12-16 17:20:38 +00002161#if ENABLE_ASH_GETOPTS
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02002162static void FAST_FUNC
Denis Vlasenko01631112007-12-16 17:20:38 +00002163getoptsreset(const char *value)
2164{
Denys Vlasenko46289452017-08-11 00:59:36 +02002165 shellparam.optind = 1;
2166 if (is_number(value))
2167 shellparam.optind = number(value) ?: 1;
Denis Vlasenko01631112007-12-16 17:20:38 +00002168 shellparam.optoff = -1;
2169}
2170#endif
2171
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002172/*
2173 * Compares two strings up to the first = or '\0'. The first
2174 * string must be terminated by '='; the second may be terminated by
2175 * either '=' or '\0'.
2176 */
2177static int
2178varcmp(const char *p, const char *q)
2179{
2180 int c, d;
2181
2182 while ((c = *p) == (d = *q)) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02002183 if (c == '\0' || c == '=')
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002184 goto out;
2185 p++;
2186 q++;
2187 }
2188 if (c == '=')
Denis Vlasenko9650f362007-02-23 01:04:37 +00002189 c = '\0';
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002190 if (d == '=')
Denis Vlasenko9650f362007-02-23 01:04:37 +00002191 d = '\0';
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002192 out:
2193 return c - d;
2194}
2195
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002196/*
2197 * Find the appropriate entry in the hash table from the name.
2198 */
2199static struct var **
2200hashvar(const char *p)
2201{
2202 unsigned hashval;
2203
2204 hashval = ((unsigned char) *p) << 4;
2205 while (*p && *p != '=')
2206 hashval += (unsigned char) *p++;
2207 return &vartab[hashval % VTABSIZE];
2208}
2209
2210static int
2211vpcmp(const void *a, const void *b)
2212{
2213 return varcmp(*(const char **)a, *(const char **)b);
2214}
2215
2216/*
2217 * This routine initializes the builtin variables.
2218 */
2219static void
2220initvar(void)
2221{
2222 struct var *vp;
2223 struct var *end;
2224 struct var **vpp;
2225
2226 /*
2227 * PS1 depends on uid
2228 */
2229#if ENABLE_FEATURE_EDITING && ENABLE_FEATURE_EDITING_FANCY_PROMPT
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002230 vps1.var_text = "PS1=\\w \\$ ";
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002231#else
2232 if (!geteuid())
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002233 vps1.var_text = "PS1=# ";
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002234#endif
2235 vp = varinit;
Denis Vlasenko80b8b392007-06-25 10:55:35 +00002236 end = vp + ARRAY_SIZE(varinit);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002237 do {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002238 vpp = hashvar(vp->var_text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002239 vp->next = *vpp;
2240 *vpp = vp;
2241 } while (++vp < end);
2242}
2243
2244static struct var **
2245findvar(struct var **vpp, const char *name)
2246{
2247 for (; *vpp; vpp = &(*vpp)->next) {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002248 if (varcmp((*vpp)->var_text, name) == 0) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002249 break;
2250 }
2251 }
2252 return vpp;
2253}
2254
2255/*
2256 * Find the value of a variable. Returns NULL if not set.
2257 */
Denys Vlasenko03dad222010-01-12 23:29:57 +01002258static const char* FAST_FUNC
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002259lookupvar(const char *name)
2260{
2261 struct var *v;
2262
2263 v = *findvar(hashvar(name), name);
2264 if (v) {
Denis Vlasenko448d30e2008-06-27 00:24:11 +00002265#if ENABLE_ASH_RANDOM_SUPPORT
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002266 /*
2267 * Dynamic variables are implemented roughly the same way they are
2268 * in bash. Namely, they're "special" so long as they aren't unset.
2269 * As soon as they're unset, they're no longer dynamic, and dynamic
2270 * lookup will no longer happen at that point. -- PFM.
2271 */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002272 if (v->flags & VDYNAMIC)
2273 v->var_func(NULL);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002274#endif
Denys Vlasenko675d24a2018-01-27 22:02:05 +01002275 if (!(v->flags & VUNSET)) {
2276 if (v == &vlineno && v->var_text == linenovar) {
2277 fmtstr(linenovar+7, sizeof(linenovar)-7, "%d", lineno);
2278 }
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002279 return var_end(v->var_text);
Denys Vlasenko675d24a2018-01-27 22:02:05 +01002280 }
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002281 }
2282 return NULL;
2283}
2284
Denys Vlasenko0b883582016-12-23 16:49:07 +01002285#if ENABLE_UNICODE_SUPPORT
Denys Vlasenko37dc08b2016-10-02 04:38:07 +02002286static void
2287reinit_unicode_for_ash(void)
Denys Vlasenkoe9ab07c2014-08-13 18:00:08 +02002288{
2289 /* Unicode support should be activated even if LANG is set
2290 * _during_ shell execution, not only if it was set when
2291 * shell was started. Therefore, re-check LANG every time:
2292 */
2293 if (ENABLE_FEATURE_CHECK_UNICODE_IN_ENV
2294 || ENABLE_UNICODE_USING_LOCALE
2295 ) {
2296 const char *s = lookupvar("LC_ALL");
2297 if (!s) s = lookupvar("LC_CTYPE");
2298 if (!s) s = lookupvar("LANG");
2299 reinit_unicode(s);
2300 }
2301}
Denys Vlasenko0b883582016-12-23 16:49:07 +01002302#else
2303# define reinit_unicode_for_ash() ((void)0)
2304#endif
Denys Vlasenkoe9ab07c2014-08-13 18:00:08 +02002305
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002306/*
2307 * Search the environment of a builtin command.
2308 */
Denys Vlasenko488e6092017-07-26 23:08:36 +02002309static ALWAYS_INLINE const char *
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002310bltinlookup(const char *name)
2311{
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002312 return lookupvar(name);
2313}
2314
2315/*
2316 * Same as setvar except that the variable and value are passed in
2317 * the first argument as name=value. Since the first argument will
2318 * be actually stored in the table, it should not be a string that
2319 * will go away.
2320 * Called with interrupts off.
2321 */
Denys Vlasenkod04fc712017-07-26 20:06:48 +02002322static struct var *
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002323setvareq(char *s, int flags)
2324{
2325 struct var *vp, **vpp;
2326
2327 vpp = hashvar(s);
2328 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
Denys Vlasenkod04fc712017-07-26 20:06:48 +02002329 vpp = findvar(vpp, s);
2330 vp = *vpp;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002331 if (vp) {
2332 if ((vp->flags & (VREADONLY|VDYNAMIC)) == VREADONLY) {
2333 const char *n;
2334
2335 if (flags & VNOSAVE)
2336 free(s);
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002337 n = vp->var_text;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +02002338 exitstatus = 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002339 ash_msg_and_raise_error("%.*s: is read only", strchrnul(n, '=') - n, n);
2340 }
2341
2342 if (flags & VNOSET)
Denys Vlasenkod04fc712017-07-26 20:06:48 +02002343 goto out;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002344
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002345 if (vp->var_func && !(flags & VNOFUNC))
2346 vp->var_func(var_end(s));
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002347
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002348 if (!(vp->flags & (VTEXTFIXED|VSTACK)))
2349 free((char*)vp->var_text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002350
Denys Vlasenkob28d4c32017-07-25 16:29:36 +02002351 if (((flags & (VEXPORT|VREADONLY|VSTRFIXED|VUNSET)) | (vp->flags & VSTRFIXED)) == VUNSET) {
2352 *vpp = vp->next;
2353 free(vp);
2354 out_free:
2355 if ((flags & (VTEXTFIXED|VSTACK|VNOSAVE)) == VNOSAVE)
2356 free(s);
Denys Vlasenkod04fc712017-07-26 20:06:48 +02002357 goto out;
Denys Vlasenkob28d4c32017-07-25 16:29:36 +02002358 }
2359
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002360 flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
2361 } else {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002362 /* variable s is not found */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002363 if (flags & VNOSET)
Denys Vlasenkod04fc712017-07-26 20:06:48 +02002364 goto out;
Denys Vlasenkob28d4c32017-07-25 16:29:36 +02002365 if ((flags & (VEXPORT|VREADONLY|VSTRFIXED|VUNSET)) == VUNSET)
2366 goto out_free;
Denis Vlasenko597906c2008-02-20 16:38:54 +00002367 vp = ckzalloc(sizeof(*vp));
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002368 vp->next = *vpp;
Denis Vlasenko597906c2008-02-20 16:38:54 +00002369 /*vp->func = NULL; - ckzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002370 *vpp = vp;
2371 }
2372 if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE)))
2373 s = ckstrdup(s);
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002374 vp->var_text = s;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002375 vp->flags = flags;
Denys Vlasenkod04fc712017-07-26 20:06:48 +02002376
2377 out:
2378 return vp;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002379}
2380
2381/*
2382 * Set the value of a variable. The flags argument is ored with the
2383 * flags of the variable. If val is NULL, the variable is unset.
2384 */
Denys Vlasenkod04fc712017-07-26 20:06:48 +02002385static struct var *
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002386setvar(const char *name, const char *val, int flags)
2387{
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002388 const char *q;
2389 char *p;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002390 char *nameeq;
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002391 size_t namelen;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002392 size_t vallen;
Denys Vlasenkod04fc712017-07-26 20:06:48 +02002393 struct var *vp;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002394
2395 q = endofname(name);
2396 p = strchrnul(q, '=');
2397 namelen = p - name;
2398 if (!namelen || p != q)
2399 ash_msg_and_raise_error("%.*s: bad variable name", namelen, name);
2400 vallen = 0;
2401 if (val == NULL) {
2402 flags |= VUNSET;
2403 } else {
2404 vallen = strlen(val);
2405 }
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002406
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002407 INT_OFF;
2408 nameeq = ckmalloc(namelen + vallen + 2);
Denys Vlasenkoda2244f2017-07-21 18:51:29 +02002409 p = mempcpy(nameeq, name, namelen);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002410 if (val) {
2411 *p++ = '=';
Denys Vlasenkoda2244f2017-07-21 18:51:29 +02002412 p = mempcpy(p, val, vallen);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002413 }
2414 *p = '\0';
Denys Vlasenkod04fc712017-07-26 20:06:48 +02002415 vp = setvareq(nameeq, flags | VNOSAVE);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002416 INT_ON;
Denys Vlasenkod04fc712017-07-26 20:06:48 +02002417
2418 return vp;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002419}
2420
Denys Vlasenko03dad222010-01-12 23:29:57 +01002421static void FAST_FUNC
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02002422setvar0(const char *name, const char *val)
Denys Vlasenko03dad222010-01-12 23:29:57 +01002423{
2424 setvar(name, val, 0);
2425}
2426
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002427/*
2428 * Unset the specified variable.
2429 */
Denys Vlasenkob28d4c32017-07-25 16:29:36 +02002430static void
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002431unsetvar(const char *s)
2432{
Denys Vlasenkocf3a7962017-07-26 14:38:19 +02002433 setvar(s, NULL, 0);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002434}
2435
2436/*
2437 * Process a linked list of variable assignments.
2438 */
2439static void
2440listsetvar(struct strlist *list_set_var, int flags)
2441{
2442 struct strlist *lp = list_set_var;
2443
2444 if (!lp)
2445 return;
2446 INT_OFF;
2447 do {
2448 setvareq(lp->text, flags);
Denis Vlasenko9650f362007-02-23 01:04:37 +00002449 lp = lp->next;
2450 } while (lp);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002451 INT_ON;
2452}
2453
2454/*
2455 * Generate a list of variables satisfying the given conditions.
2456 */
Denys Vlasenkoa5060b82017-11-03 14:16:25 +01002457#if !ENABLE_FEATURE_SH_NOFORK
2458# define listvars(on, off, lp, end) listvars(on, off, end)
2459#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002460static char **
Denys Vlasenkoa5060b82017-11-03 14:16:25 +01002461listvars(int on, int off, struct strlist *lp, char ***end)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002462{
2463 struct var **vpp;
2464 struct var *vp;
2465 char **ep;
2466 int mask;
2467
2468 STARTSTACKSTR(ep);
2469 vpp = vartab;
2470 mask = on | off;
2471 do {
2472 for (vp = *vpp; vp; vp = vp->next) {
2473 if ((vp->flags & mask) == on) {
Denys Vlasenkoa5060b82017-11-03 14:16:25 +01002474#if ENABLE_FEATURE_SH_NOFORK
2475 /* If variable with the same name is both
2476 * exported and temporarily set for a command:
2477 * export ZVAR=5
2478 * ZVAR=6 printenv
2479 * then "ZVAR=6" will be both in vartab and
2480 * lp lists. Do not pass it twice to printenv.
2481 */
2482 struct strlist *lp1 = lp;
2483 while (lp1) {
2484 if (strcmp(lp1->text, vp->var_text) == 0)
2485 goto skip;
2486 lp1 = lp1->next;
2487 }
2488#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002489 if (ep == stackstrend())
2490 ep = growstackstr();
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002491 *ep++ = (char*)vp->var_text;
Denys Vlasenkoa5060b82017-11-03 14:16:25 +01002492#if ENABLE_FEATURE_SH_NOFORK
2493 skip: ;
2494#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002495 }
2496 }
2497 } while (++vpp < vartab + VTABSIZE);
Denys Vlasenkoa5060b82017-11-03 14:16:25 +01002498
2499#if ENABLE_FEATURE_SH_NOFORK
2500 while (lp) {
2501 if (ep == stackstrend())
2502 ep = growstackstr();
2503 *ep++ = lp->text;
2504 lp = lp->next;
2505 }
2506#endif
2507
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002508 if (ep == stackstrend())
2509 ep = growstackstr();
2510 if (end)
2511 *end = ep;
2512 *ep++ = NULL;
2513 return grabstackstr(ep);
2514}
2515
2516
2517/* ============ Path search helper
2518 *
2519 * The variable path (passed by reference) should be set to the start
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002520 * of the path before the first call; path_advance will update
2521 * this value as it proceeds. Successive calls to path_advance will return
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002522 * the possible path expansions in sequence. If an option (indicated by
2523 * a percent sign) appears in the path entry then the global variable
2524 * pathopt will be set to point to it; otherwise pathopt will be set to
2525 * NULL.
2526 */
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002527static const char *pathopt; /* set by path_advance */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002528
2529static char *
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002530path_advance(const char **path, const char *name)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002531{
2532 const char *p;
2533 char *q;
2534 const char *start;
2535 size_t len;
2536
2537 if (*path == NULL)
2538 return NULL;
2539 start = *path;
Denis Vlasenkof7d56652008-03-25 05:51:41 +00002540 for (p = start; *p && *p != ':' && *p != '%'; p++)
2541 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002542 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
2543 while (stackblocksize() < len)
2544 growstackblock();
2545 q = stackblock();
2546 if (p != start) {
Denys Vlasenko5ace96a2017-07-23 21:46:02 +02002547 q = mempcpy(q, start, p - start);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002548 *q++ = '/';
2549 }
2550 strcpy(q, name);
2551 pathopt = NULL;
2552 if (*p == '%') {
2553 pathopt = ++p;
Denis Vlasenkof7d56652008-03-25 05:51:41 +00002554 while (*p && *p != ':')
2555 p++;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002556 }
2557 if (*p == ':')
2558 *path = p + 1;
2559 else
2560 *path = NULL;
2561 return stalloc(len);
2562}
2563
2564
2565/* ============ Prompt */
2566
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +00002567static smallint doprompt; /* if set, prompt the user */
2568static smallint needprompt; /* true if interactive and at start of line */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002569
2570#if ENABLE_FEATURE_EDITING
2571static line_input_t *line_input_state;
2572static const char *cmdedit_prompt;
2573static void
2574putprompt(const char *s)
2575{
2576 if (ENABLE_ASH_EXPAND_PRMT) {
2577 free((char*)cmdedit_prompt);
Denis Vlasenko4222ae42007-02-25 02:37:49 +00002578 cmdedit_prompt = ckstrdup(s);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002579 return;
2580 }
2581 cmdedit_prompt = s;
2582}
2583#else
2584static void
2585putprompt(const char *s)
2586{
2587 out2str(s);
2588}
2589#endif
2590
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002591/* expandstr() needs parsing machinery, so it is far away ahead... */
Denys Vlasenko46999802017-07-29 21:12:29 +02002592static const char *expandstr(const char *ps, int syntax_type);
2593/* Values for syntax param */
2594#define BASESYNTAX 0 /* not in quotes */
2595#define DQSYNTAX 1 /* in double quotes */
2596#define SQSYNTAX 2 /* in single quotes */
2597#define ARISYNTAX 3 /* in arithmetic */
Denys Vlasenko5f0a75f2017-07-29 22:58:44 +02002598#if ENABLE_ASH_EXPAND_PRMT
2599# define PSSYNTAX 4 /* prompt. never passed to SIT() */
2600#endif
Denys Vlasenko46999802017-07-29 21:12:29 +02002601/* PSSYNTAX expansion is identical to DQSYNTAX, except keeping '\$' as '\$' */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002602
Denys Vlasenko46999802017-07-29 21:12:29 +02002603/*
2604 * called by editline -- any expansions to the prompt should be added here.
2605 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002606static void
Denys Vlasenko958581a2010-09-12 15:04:27 +02002607setprompt_if(smallint do_set, int whichprompt)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002608{
2609 const char *prompt;
Denys Vlasenko958581a2010-09-12 15:04:27 +02002610 IF_ASH_EXPAND_PRMT(struct stackmark smark;)
2611
2612 if (!do_set)
2613 return;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002614
2615 needprompt = 0;
2616
2617 switch (whichprompt) {
2618 case 1:
2619 prompt = ps1val();
2620 break;
2621 case 2:
2622 prompt = ps2val();
2623 break;
2624 default: /* 0 */
2625 prompt = nullstr;
2626 }
2627#if ENABLE_ASH_EXPAND_PRMT
Denys Vlasenko60ca8342016-09-30 11:21:21 +02002628 pushstackmark(&smark, stackblocksize());
Denys Vlasenko46999802017-07-29 21:12:29 +02002629 putprompt(expandstr(prompt, PSSYNTAX));
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002630 popstackmark(&smark);
Denys Vlasenko48c803a2017-07-01 23:24:48 +02002631#else
2632 putprompt(prompt);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002633#endif
2634}
2635
2636
2637/* ============ The cd and pwd commands */
2638
2639#define CD_PHYSICAL 1
2640#define CD_PRINT 2
2641
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002642static int
2643cdopt(void)
2644{
2645 int flags = 0;
2646 int i, j;
2647
2648 j = 'L';
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02002649 while ((i = nextopt("LP")) != '\0') {
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002650 if (i != j) {
2651 flags ^= CD_PHYSICAL;
2652 j = i;
2653 }
2654 }
2655
2656 return flags;
2657}
2658
2659/*
2660 * Update curdir (the name of the current directory) in response to a
2661 * cd command.
2662 */
2663static const char *
2664updatepwd(const char *dir)
2665{
2666 char *new;
2667 char *p;
2668 char *cdcomppath;
2669 const char *lim;
2670
Denys Vlasenko8e2bc472016-09-28 23:02:57 +02002671 cdcomppath = sstrdup(dir);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002672 STARTSTACKSTR(new);
2673 if (*dir != '/') {
2674 if (curdir == nullstr)
2675 return 0;
2676 new = stack_putstr(curdir, new);
2677 }
2678 new = makestrspace(strlen(dir) + 2, new);
Denis Vlasenko29eb3592008-05-18 14:06:08 +00002679 lim = (char *)stackblock() + 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002680 if (*dir != '/') {
2681 if (new[-1] != '/')
2682 USTPUTC('/', new);
2683 if (new > lim && *lim == '/')
2684 lim++;
2685 } else {
2686 USTPUTC('/', new);
2687 cdcomppath++;
2688 if (dir[1] == '/' && dir[2] != '/') {
2689 USTPUTC('/', new);
2690 cdcomppath++;
2691 lim++;
2692 }
2693 }
2694 p = strtok(cdcomppath, "/");
2695 while (p) {
2696 switch (*p) {
2697 case '.':
2698 if (p[1] == '.' && p[2] == '\0') {
2699 while (new > lim) {
2700 STUNPUTC(new);
2701 if (new[-1] == '/')
2702 break;
2703 }
2704 break;
Denis Vlasenko16abcd92007-04-13 23:59:52 +00002705 }
2706 if (p[1] == '\0')
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002707 break;
2708 /* fall through */
2709 default:
2710 new = stack_putstr(p, new);
2711 USTPUTC('/', new);
2712 }
Denys Vlasenko00da72b2015-10-23 18:43:16 +02002713 p = strtok(NULL, "/");
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002714 }
2715 if (new > lim)
2716 STUNPUTC(new);
2717 *new = 0;
2718 return stackblock();
2719}
2720
2721/*
2722 * Find out what the current directory is. If we already know the current
2723 * directory, this routine returns immediately.
2724 */
2725static char *
2726getpwd(void)
2727{
Denis Vlasenko01631112007-12-16 17:20:38 +00002728 char *dir = getcwd(NULL, 0); /* huh, using glibc extension? */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002729 return dir ? dir : nullstr;
2730}
2731
2732static void
2733setpwd(const char *val, int setold)
2734{
2735 char *oldcur, *dir;
2736
2737 oldcur = dir = curdir;
2738
2739 if (setold) {
2740 setvar("OLDPWD", oldcur, VEXPORT);
2741 }
2742 INT_OFF;
2743 if (physdir != nullstr) {
2744 if (physdir != oldcur)
2745 free(physdir);
2746 physdir = nullstr;
2747 }
2748 if (oldcur == val || !val) {
2749 char *s = getpwd();
2750 physdir = s;
2751 if (!val)
2752 dir = s;
2753 } else
2754 dir = ckstrdup(val);
2755 if (oldcur != dir && oldcur != nullstr) {
2756 free(oldcur);
2757 }
2758 curdir = dir;
2759 INT_ON;
2760 setvar("PWD", dir, VEXPORT);
2761}
2762
2763static void hashcd(void);
2764
2765/*
Denys Vlasenko70392332016-10-27 02:31:55 +02002766 * Actually do the chdir. We also call hashcd to let other routines
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002767 * know that the current directory has changed.
2768 */
2769static int
2770docd(const char *dest, int flags)
2771{
Denys Vlasenko4b1100e2010-03-05 14:10:54 +01002772 const char *dir = NULL;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002773 int err;
2774
2775 TRACE(("docd(\"%s\", %d) called\n", dest, flags));
2776
2777 INT_OFF;
2778 if (!(flags & CD_PHYSICAL)) {
2779 dir = updatepwd(dest);
2780 if (dir)
2781 dest = dir;
2782 }
2783 err = chdir(dest);
2784 if (err)
2785 goto out;
2786 setpwd(dir, 1);
2787 hashcd();
2788 out:
2789 INT_ON;
2790 return err;
2791}
2792
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02002793static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00002794cdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002795{
2796 const char *dest;
2797 const char *path;
2798 const char *p;
2799 char c;
2800 struct stat statb;
2801 int flags;
2802
2803 flags = cdopt();
2804 dest = *argptr;
2805 if (!dest)
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02002806 dest = bltinlookup("HOME");
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002807 else if (LONE_DASH(dest)) {
2808 dest = bltinlookup("OLDPWD");
2809 flags |= CD_PRINT;
2810 }
2811 if (!dest)
2812 dest = nullstr;
2813 if (*dest == '/')
Denys Vlasenko0e081d02016-10-26 19:56:05 +02002814 goto step6;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002815 if (*dest == '.') {
2816 c = dest[1];
2817 dotdot:
2818 switch (c) {
2819 case '\0':
2820 case '/':
2821 goto step6;
2822 case '.':
2823 c = dest[2];
2824 if (c != '.')
2825 goto dotdot;
2826 }
2827 }
2828 if (!*dest)
2829 dest = ".";
2830 path = bltinlookup("CDPATH");
Denys Vlasenko0e081d02016-10-26 19:56:05 +02002831 while (path) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002832 c = *path;
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002833 p = path_advance(&path, dest);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002834 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
2835 if (c && c != ':')
2836 flags |= CD_PRINT;
2837 docd:
2838 if (!docd(p, flags))
2839 goto out;
Denys Vlasenko0e081d02016-10-26 19:56:05 +02002840 goto err;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002841 }
Denys Vlasenko0e081d02016-10-26 19:56:05 +02002842 }
2843
2844 step6:
2845 p = dest;
2846 goto docd;
2847
2848 err:
Johannes Schindelin687aac02017-08-22 22:03:22 +02002849 ash_msg_and_raise_perror("can't cd to %s", dest);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002850 /* NOTREACHED */
2851 out:
2852 if (flags & CD_PRINT)
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02002853 out1fmt("%s\n", curdir);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002854 return 0;
2855}
2856
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02002857static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00002858pwdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002859{
2860 int flags;
2861 const char *dir = curdir;
2862
2863 flags = cdopt();
2864 if (flags) {
2865 if (physdir == nullstr)
2866 setpwd(dir, 0);
2867 dir = physdir;
2868 }
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02002869 out1fmt("%s\n", dir);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002870 return 0;
2871}
2872
Denis Vlasenko0c032a42007-02-23 01:03:40 +00002873
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00002874/* ============ ... */
Eric Andersenc470f442003-07-28 09:56:35 +00002875
Denis Vlasenko834dee72008-10-07 09:18:30 +00002876
Denys Vlasenko82dd14a2010-05-17 10:10:01 +02002877#define IBUFSIZ (ENABLE_FEATURE_EDITING ? CONFIG_FEATURE_EDITING_MAX_LEN : 1024)
Eric Andersenc470f442003-07-28 09:56:35 +00002878
Eric Andersenc470f442003-07-28 09:56:35 +00002879/* Syntax classes */
Denis Vlasenko834dee72008-10-07 09:18:30 +00002880#define CWORD 0 /* character is nothing special */
2881#define CNL 1 /* newline character */
2882#define CBACK 2 /* a backslash character */
2883#define CSQUOTE 3 /* single quote */
2884#define CDQUOTE 4 /* double quote */
Eric Andersenc470f442003-07-28 09:56:35 +00002885#define CENDQUOTE 5 /* a terminating quote */
Denis Vlasenko834dee72008-10-07 09:18:30 +00002886#define CBQUOTE 6 /* backwards single quote */
2887#define CVAR 7 /* a dollar sign */
2888#define CENDVAR 8 /* a '}' character */
2889#define CLP 9 /* a left paren in arithmetic */
2890#define CRP 10 /* a right paren in arithmetic */
Eric Andersenc470f442003-07-28 09:56:35 +00002891#define CENDFILE 11 /* end of file */
Denis Vlasenko834dee72008-10-07 09:18:30 +00002892#define CCTL 12 /* like CWORD, except it must be escaped */
2893#define CSPCL 13 /* these terminate a word */
2894#define CIGN 14 /* character should be ignored */
Eric Andersenc470f442003-07-28 09:56:35 +00002895
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002896#define PEOF 256
Denis Vlasenko131ae172007-02-18 13:00:19 +00002897#if ENABLE_ASH_ALIAS
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002898# define PEOA 257
Eric Andersenc470f442003-07-28 09:56:35 +00002899#endif
2900
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002901#define USE_SIT_FUNCTION ENABLE_ASH_OPTIMIZE_FOR_SIZE
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002902
Denys Vlasenko0b883582016-12-23 16:49:07 +01002903#if ENABLE_FEATURE_SH_MATH
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002904# define SIT_ITEM(a,b,c,d) (a | (b << 4) | (c << 8) | (d << 12))
Eric Andersenc470f442003-07-28 09:56:35 +00002905#else
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002906# define SIT_ITEM(a,b,c,d) (a | (b << 4) | (c << 8))
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002907#endif
Denys Vlasenko3e134eb2016-04-22 18:09:21 +02002908static const uint16_t S_I_T[] ALIGN2 = {
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002909#if ENABLE_ASH_ALIAS
2910 SIT_ITEM(CSPCL , CIGN , CIGN , CIGN ), /* 0, PEOA */
2911#endif
2912 SIT_ITEM(CSPCL , CWORD , CWORD, CWORD ), /* 1, ' ' */
2913 SIT_ITEM(CNL , CNL , CNL , CNL ), /* 2, \n */
2914 SIT_ITEM(CWORD , CCTL , CCTL , CWORD ), /* 3, !*-/:=?[]~ */
2915 SIT_ITEM(CDQUOTE , CENDQUOTE, CWORD, CWORD ), /* 4, '"' */
2916 SIT_ITEM(CVAR , CVAR , CWORD, CVAR ), /* 5, $ */
2917 SIT_ITEM(CSQUOTE , CWORD , CENDQUOTE, CWORD), /* 6, "'" */
2918 SIT_ITEM(CSPCL , CWORD , CWORD, CLP ), /* 7, ( */
2919 SIT_ITEM(CSPCL , CWORD , CWORD, CRP ), /* 8, ) */
2920 SIT_ITEM(CBACK , CBACK , CCTL , CBACK ), /* 9, \ */
2921 SIT_ITEM(CBQUOTE , CBQUOTE , CWORD, CBQUOTE), /* 10, ` */
2922 SIT_ITEM(CENDVAR , CENDVAR , CWORD, CENDVAR), /* 11, } */
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002923#if !USE_SIT_FUNCTION
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002924 SIT_ITEM(CENDFILE, CENDFILE , CENDFILE, CENDFILE),/* 12, PEOF */
2925 SIT_ITEM(CWORD , CWORD , CWORD, CWORD ), /* 13, 0-9A-Za-z */
2926 SIT_ITEM(CCTL , CCTL , CCTL , CCTL ) /* 14, CTLESC ... */
2927#endif
2928#undef SIT_ITEM
Eric Andersenc470f442003-07-28 09:56:35 +00002929};
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002930/* Constants below must match table above */
2931enum {
2932#if ENABLE_ASH_ALIAS
2933 CSPCL_CIGN_CIGN_CIGN , /* 0 */
2934#endif
2935 CSPCL_CWORD_CWORD_CWORD , /* 1 */
2936 CNL_CNL_CNL_CNL , /* 2 */
2937 CWORD_CCTL_CCTL_CWORD , /* 3 */
2938 CDQUOTE_CENDQUOTE_CWORD_CWORD , /* 4 */
2939 CVAR_CVAR_CWORD_CVAR , /* 5 */
2940 CSQUOTE_CWORD_CENDQUOTE_CWORD , /* 6 */
2941 CSPCL_CWORD_CWORD_CLP , /* 7 */
2942 CSPCL_CWORD_CWORD_CRP , /* 8 */
2943 CBACK_CBACK_CCTL_CBACK , /* 9 */
2944 CBQUOTE_CBQUOTE_CWORD_CBQUOTE , /* 10 */
2945 CENDVAR_CENDVAR_CWORD_CENDVAR , /* 11 */
2946 CENDFILE_CENDFILE_CENDFILE_CENDFILE, /* 12 */
2947 CWORD_CWORD_CWORD_CWORD , /* 13 */
2948 CCTL_CCTL_CCTL_CCTL , /* 14 */
2949};
Eric Andersen2870d962001-07-02 17:27:21 +00002950
Denys Vlasenkocd716832009-11-28 22:14:02 +01002951/* c in SIT(c, syntax) must be an *unsigned char* or PEOA or PEOF,
2952 * caller must ensure proper cast on it if c is *char_ptr!
2953 */
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002954#if USE_SIT_FUNCTION
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002955
Denis Vlasenko0c032a42007-02-23 01:03:40 +00002956static int
2957SIT(int c, int syntax)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002958{
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02002959 /* Used to also have '/' in this string: "\t\n !\"$&'()*-/:;<=>?[\\]`|}~" */
2960 static const char spec_symbls[] ALIGN1 = "\t\n !\"$&'()*-:;<=>?[\\]`|}~";
2961 /*
2962 * This causes '/' to be prepended with CTLESC in dquoted string,
2963 * making "./file"* treated incorrectly because we feed
2964 * ".\/file*" string to glob(), confusing it (see expandmeta func).
2965 * The "homegrown" glob implementation is okay with that,
2966 * but glibc one isn't. With '/' always treated as CWORD,
2967 * both work fine.
2968 */
Denys Vlasenkocd716832009-11-28 22:14:02 +01002969# if ENABLE_ASH_ALIAS
2970 static const uint8_t syntax_index_table[] ALIGN1 = {
Eric Andersenc470f442003-07-28 09:56:35 +00002971 1, 2, 1, 3, 4, 5, 1, 6, /* "\t\n !\"$&'" */
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02002972 7, 8, 3, 3,/*3,*/3, 1, 1, /* "()*-/:;<" */
Eric Andersenc470f442003-07-28 09:56:35 +00002973 3, 1, 3, 3, 9, 3, 10, 1, /* "=>?[\\]`|" */
2974 11, 3 /* "}~" */
2975 };
Denys Vlasenkocd716832009-11-28 22:14:02 +01002976# else
2977 static const uint8_t syntax_index_table[] ALIGN1 = {
Eric Andersenc470f442003-07-28 09:56:35 +00002978 0, 1, 0, 2, 3, 4, 0, 5, /* "\t\n !\"$&'" */
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02002979 6, 7, 2, 2,/*2,*/2, 0, 0, /* "()*-/:;<" */
Eric Andersenc470f442003-07-28 09:56:35 +00002980 2, 0, 2, 2, 8, 2, 9, 0, /* "=>?[\\]`|" */
2981 10, 2 /* "}~" */
2982 };
Denys Vlasenkocd716832009-11-28 22:14:02 +01002983# endif
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002984 const char *s;
2985 int indx;
2986
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002987 if (c == PEOF)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002988 return CENDFILE;
Denys Vlasenkocd716832009-11-28 22:14:02 +01002989# if ENABLE_ASH_ALIAS
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002990 if (c == PEOA)
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002991 indx = 0;
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002992 else
Denys Vlasenkocd716832009-11-28 22:14:02 +01002993# endif
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002994 {
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002995 /* Cast is purely for paranoia here,
2996 * just in case someone passed signed char to us */
2997 if ((unsigned char)c >= CTL_FIRST
2998 && (unsigned char)c <= CTL_LAST
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002999 ) {
3000 return CCTL;
3001 }
3002 s = strchrnul(spec_symbls, c);
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01003003 if (*s == '\0')
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00003004 return CWORD;
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00003005 indx = syntax_index_table[s - spec_symbls];
3006 }
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01003007 return (S_I_T[indx] >> (syntax*4)) & 0xf;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00003008}
3009
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00003010#else /* !USE_SIT_FUNCTION */
Manuel Novoa III 16815d42001-08-10 19:36:07 +00003011
Denys Vlasenko3e134eb2016-04-22 18:09:21 +02003012static const uint8_t syntax_index_table[] ALIGN1 = {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003013 /* BASESYNTAX_DQSYNTAX_SQSYNTAX_ARISYNTAX */
Denys Vlasenkocd716832009-11-28 22:14:02 +01003014 /* 0 */ CWORD_CWORD_CWORD_CWORD,
3015 /* 1 */ CWORD_CWORD_CWORD_CWORD,
3016 /* 2 */ CWORD_CWORD_CWORD_CWORD,
3017 /* 3 */ CWORD_CWORD_CWORD_CWORD,
3018 /* 4 */ CWORD_CWORD_CWORD_CWORD,
3019 /* 5 */ CWORD_CWORD_CWORD_CWORD,
3020 /* 6 */ CWORD_CWORD_CWORD_CWORD,
3021 /* 7 */ CWORD_CWORD_CWORD_CWORD,
3022 /* 8 */ CWORD_CWORD_CWORD_CWORD,
3023 /* 9 "\t" */ CSPCL_CWORD_CWORD_CWORD,
3024 /* 10 "\n" */ CNL_CNL_CNL_CNL,
3025 /* 11 */ CWORD_CWORD_CWORD_CWORD,
3026 /* 12 */ CWORD_CWORD_CWORD_CWORD,
3027 /* 13 */ CWORD_CWORD_CWORD_CWORD,
3028 /* 14 */ CWORD_CWORD_CWORD_CWORD,
3029 /* 15 */ CWORD_CWORD_CWORD_CWORD,
3030 /* 16 */ CWORD_CWORD_CWORD_CWORD,
3031 /* 17 */ CWORD_CWORD_CWORD_CWORD,
3032 /* 18 */ CWORD_CWORD_CWORD_CWORD,
3033 /* 19 */ CWORD_CWORD_CWORD_CWORD,
3034 /* 20 */ CWORD_CWORD_CWORD_CWORD,
3035 /* 21 */ CWORD_CWORD_CWORD_CWORD,
3036 /* 22 */ CWORD_CWORD_CWORD_CWORD,
3037 /* 23 */ CWORD_CWORD_CWORD_CWORD,
3038 /* 24 */ CWORD_CWORD_CWORD_CWORD,
3039 /* 25 */ CWORD_CWORD_CWORD_CWORD,
3040 /* 26 */ CWORD_CWORD_CWORD_CWORD,
3041 /* 27 */ CWORD_CWORD_CWORD_CWORD,
3042 /* 28 */ CWORD_CWORD_CWORD_CWORD,
3043 /* 29 */ CWORD_CWORD_CWORD_CWORD,
3044 /* 30 */ CWORD_CWORD_CWORD_CWORD,
3045 /* 31 */ CWORD_CWORD_CWORD_CWORD,
3046 /* 32 " " */ CSPCL_CWORD_CWORD_CWORD,
3047 /* 33 "!" */ CWORD_CCTL_CCTL_CWORD,
3048 /* 34 """ */ CDQUOTE_CENDQUOTE_CWORD_CWORD,
3049 /* 35 "#" */ CWORD_CWORD_CWORD_CWORD,
3050 /* 36 "$" */ CVAR_CVAR_CWORD_CVAR,
3051 /* 37 "%" */ CWORD_CWORD_CWORD_CWORD,
3052 /* 38 "&" */ CSPCL_CWORD_CWORD_CWORD,
3053 /* 39 "'" */ CSQUOTE_CWORD_CENDQUOTE_CWORD,
3054 /* 40 "(" */ CSPCL_CWORD_CWORD_CLP,
3055 /* 41 ")" */ CSPCL_CWORD_CWORD_CRP,
3056 /* 42 "*" */ CWORD_CCTL_CCTL_CWORD,
3057 /* 43 "+" */ CWORD_CWORD_CWORD_CWORD,
3058 /* 44 "," */ CWORD_CWORD_CWORD_CWORD,
3059 /* 45 "-" */ CWORD_CCTL_CCTL_CWORD,
3060 /* 46 "." */ CWORD_CWORD_CWORD_CWORD,
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02003061/* "/" was CWORD_CCTL_CCTL_CWORD, see comment in SIT() function why this is changed: */
3062 /* 47 "/" */ CWORD_CWORD_CWORD_CWORD,
Denys Vlasenkocd716832009-11-28 22:14:02 +01003063 /* 48 "0" */ CWORD_CWORD_CWORD_CWORD,
3064 /* 49 "1" */ CWORD_CWORD_CWORD_CWORD,
3065 /* 50 "2" */ CWORD_CWORD_CWORD_CWORD,
3066 /* 51 "3" */ CWORD_CWORD_CWORD_CWORD,
3067 /* 52 "4" */ CWORD_CWORD_CWORD_CWORD,
3068 /* 53 "5" */ CWORD_CWORD_CWORD_CWORD,
3069 /* 54 "6" */ CWORD_CWORD_CWORD_CWORD,
3070 /* 55 "7" */ CWORD_CWORD_CWORD_CWORD,
3071 /* 56 "8" */ CWORD_CWORD_CWORD_CWORD,
3072 /* 57 "9" */ CWORD_CWORD_CWORD_CWORD,
3073 /* 58 ":" */ CWORD_CCTL_CCTL_CWORD,
3074 /* 59 ";" */ CSPCL_CWORD_CWORD_CWORD,
3075 /* 60 "<" */ CSPCL_CWORD_CWORD_CWORD,
3076 /* 61 "=" */ CWORD_CCTL_CCTL_CWORD,
3077 /* 62 ">" */ CSPCL_CWORD_CWORD_CWORD,
3078 /* 63 "?" */ CWORD_CCTL_CCTL_CWORD,
3079 /* 64 "@" */ CWORD_CWORD_CWORD_CWORD,
3080 /* 65 "A" */ CWORD_CWORD_CWORD_CWORD,
3081 /* 66 "B" */ CWORD_CWORD_CWORD_CWORD,
3082 /* 67 "C" */ CWORD_CWORD_CWORD_CWORD,
3083 /* 68 "D" */ CWORD_CWORD_CWORD_CWORD,
3084 /* 69 "E" */ CWORD_CWORD_CWORD_CWORD,
3085 /* 70 "F" */ CWORD_CWORD_CWORD_CWORD,
3086 /* 71 "G" */ CWORD_CWORD_CWORD_CWORD,
3087 /* 72 "H" */ CWORD_CWORD_CWORD_CWORD,
3088 /* 73 "I" */ CWORD_CWORD_CWORD_CWORD,
3089 /* 74 "J" */ CWORD_CWORD_CWORD_CWORD,
3090 /* 75 "K" */ CWORD_CWORD_CWORD_CWORD,
3091 /* 76 "L" */ CWORD_CWORD_CWORD_CWORD,
3092 /* 77 "M" */ CWORD_CWORD_CWORD_CWORD,
3093 /* 78 "N" */ CWORD_CWORD_CWORD_CWORD,
3094 /* 79 "O" */ CWORD_CWORD_CWORD_CWORD,
3095 /* 80 "P" */ CWORD_CWORD_CWORD_CWORD,
3096 /* 81 "Q" */ CWORD_CWORD_CWORD_CWORD,
3097 /* 82 "R" */ CWORD_CWORD_CWORD_CWORD,
3098 /* 83 "S" */ CWORD_CWORD_CWORD_CWORD,
3099 /* 84 "T" */ CWORD_CWORD_CWORD_CWORD,
3100 /* 85 "U" */ CWORD_CWORD_CWORD_CWORD,
3101 /* 86 "V" */ CWORD_CWORD_CWORD_CWORD,
3102 /* 87 "W" */ CWORD_CWORD_CWORD_CWORD,
3103 /* 88 "X" */ CWORD_CWORD_CWORD_CWORD,
3104 /* 89 "Y" */ CWORD_CWORD_CWORD_CWORD,
3105 /* 90 "Z" */ CWORD_CWORD_CWORD_CWORD,
3106 /* 91 "[" */ CWORD_CCTL_CCTL_CWORD,
3107 /* 92 "\" */ CBACK_CBACK_CCTL_CBACK,
3108 /* 93 "]" */ CWORD_CCTL_CCTL_CWORD,
3109 /* 94 "^" */ CWORD_CWORD_CWORD_CWORD,
3110 /* 95 "_" */ CWORD_CWORD_CWORD_CWORD,
3111 /* 96 "`" */ CBQUOTE_CBQUOTE_CWORD_CBQUOTE,
3112 /* 97 "a" */ CWORD_CWORD_CWORD_CWORD,
3113 /* 98 "b" */ CWORD_CWORD_CWORD_CWORD,
3114 /* 99 "c" */ CWORD_CWORD_CWORD_CWORD,
3115 /* 100 "d" */ CWORD_CWORD_CWORD_CWORD,
3116 /* 101 "e" */ CWORD_CWORD_CWORD_CWORD,
3117 /* 102 "f" */ CWORD_CWORD_CWORD_CWORD,
3118 /* 103 "g" */ CWORD_CWORD_CWORD_CWORD,
3119 /* 104 "h" */ CWORD_CWORD_CWORD_CWORD,
3120 /* 105 "i" */ CWORD_CWORD_CWORD_CWORD,
3121 /* 106 "j" */ CWORD_CWORD_CWORD_CWORD,
3122 /* 107 "k" */ CWORD_CWORD_CWORD_CWORD,
3123 /* 108 "l" */ CWORD_CWORD_CWORD_CWORD,
3124 /* 109 "m" */ CWORD_CWORD_CWORD_CWORD,
3125 /* 110 "n" */ CWORD_CWORD_CWORD_CWORD,
3126 /* 111 "o" */ CWORD_CWORD_CWORD_CWORD,
3127 /* 112 "p" */ CWORD_CWORD_CWORD_CWORD,
3128 /* 113 "q" */ CWORD_CWORD_CWORD_CWORD,
3129 /* 114 "r" */ CWORD_CWORD_CWORD_CWORD,
3130 /* 115 "s" */ CWORD_CWORD_CWORD_CWORD,
3131 /* 116 "t" */ CWORD_CWORD_CWORD_CWORD,
3132 /* 117 "u" */ CWORD_CWORD_CWORD_CWORD,
3133 /* 118 "v" */ CWORD_CWORD_CWORD_CWORD,
3134 /* 119 "w" */ CWORD_CWORD_CWORD_CWORD,
3135 /* 120 "x" */ CWORD_CWORD_CWORD_CWORD,
3136 /* 121 "y" */ CWORD_CWORD_CWORD_CWORD,
3137 /* 122 "z" */ CWORD_CWORD_CWORD_CWORD,
3138 /* 123 "{" */ CWORD_CWORD_CWORD_CWORD,
3139 /* 124 "|" */ CSPCL_CWORD_CWORD_CWORD,
3140 /* 125 "}" */ CENDVAR_CENDVAR_CWORD_CENDVAR,
3141 /* 126 "~" */ CWORD_CCTL_CCTL_CWORD,
3142 /* 127 del */ CWORD_CWORD_CWORD_CWORD,
3143 /* 128 0x80 */ CWORD_CWORD_CWORD_CWORD,
3144 /* 129 CTLESC */ CCTL_CCTL_CCTL_CCTL,
3145 /* 130 CTLVAR */ CCTL_CCTL_CCTL_CCTL,
3146 /* 131 CTLENDVAR */ CCTL_CCTL_CCTL_CCTL,
3147 /* 132 CTLBACKQ */ CCTL_CCTL_CCTL_CCTL,
3148 /* 133 CTLQUOTE */ CCTL_CCTL_CCTL_CCTL,
3149 /* 134 CTLARI */ CCTL_CCTL_CCTL_CCTL,
3150 /* 135 CTLENDARI */ CCTL_CCTL_CCTL_CCTL,
3151 /* 136 CTLQUOTEMARK */ CCTL_CCTL_CCTL_CCTL,
3152 /* 137 */ CWORD_CWORD_CWORD_CWORD,
3153 /* 138 */ CWORD_CWORD_CWORD_CWORD,
3154 /* 139 */ CWORD_CWORD_CWORD_CWORD,
3155 /* 140 */ CWORD_CWORD_CWORD_CWORD,
3156 /* 141 */ CWORD_CWORD_CWORD_CWORD,
3157 /* 142 */ CWORD_CWORD_CWORD_CWORD,
3158 /* 143 */ CWORD_CWORD_CWORD_CWORD,
3159 /* 144 */ CWORD_CWORD_CWORD_CWORD,
3160 /* 145 */ CWORD_CWORD_CWORD_CWORD,
3161 /* 146 */ CWORD_CWORD_CWORD_CWORD,
3162 /* 147 */ CWORD_CWORD_CWORD_CWORD,
3163 /* 148 */ CWORD_CWORD_CWORD_CWORD,
3164 /* 149 */ CWORD_CWORD_CWORD_CWORD,
3165 /* 150 */ CWORD_CWORD_CWORD_CWORD,
3166 /* 151 */ CWORD_CWORD_CWORD_CWORD,
3167 /* 152 */ CWORD_CWORD_CWORD_CWORD,
3168 /* 153 */ CWORD_CWORD_CWORD_CWORD,
3169 /* 154 */ CWORD_CWORD_CWORD_CWORD,
3170 /* 155 */ CWORD_CWORD_CWORD_CWORD,
3171 /* 156 */ CWORD_CWORD_CWORD_CWORD,
3172 /* 157 */ CWORD_CWORD_CWORD_CWORD,
3173 /* 158 */ CWORD_CWORD_CWORD_CWORD,
3174 /* 159 */ CWORD_CWORD_CWORD_CWORD,
3175 /* 160 */ CWORD_CWORD_CWORD_CWORD,
3176 /* 161 */ CWORD_CWORD_CWORD_CWORD,
3177 /* 162 */ CWORD_CWORD_CWORD_CWORD,
3178 /* 163 */ CWORD_CWORD_CWORD_CWORD,
3179 /* 164 */ CWORD_CWORD_CWORD_CWORD,
3180 /* 165 */ CWORD_CWORD_CWORD_CWORD,
3181 /* 166 */ CWORD_CWORD_CWORD_CWORD,
3182 /* 167 */ CWORD_CWORD_CWORD_CWORD,
3183 /* 168 */ CWORD_CWORD_CWORD_CWORD,
3184 /* 169 */ CWORD_CWORD_CWORD_CWORD,
3185 /* 170 */ CWORD_CWORD_CWORD_CWORD,
3186 /* 171 */ CWORD_CWORD_CWORD_CWORD,
3187 /* 172 */ CWORD_CWORD_CWORD_CWORD,
3188 /* 173 */ CWORD_CWORD_CWORD_CWORD,
3189 /* 174 */ CWORD_CWORD_CWORD_CWORD,
3190 /* 175 */ CWORD_CWORD_CWORD_CWORD,
3191 /* 176 */ CWORD_CWORD_CWORD_CWORD,
3192 /* 177 */ CWORD_CWORD_CWORD_CWORD,
3193 /* 178 */ CWORD_CWORD_CWORD_CWORD,
3194 /* 179 */ CWORD_CWORD_CWORD_CWORD,
3195 /* 180 */ CWORD_CWORD_CWORD_CWORD,
3196 /* 181 */ CWORD_CWORD_CWORD_CWORD,
3197 /* 182 */ CWORD_CWORD_CWORD_CWORD,
3198 /* 183 */ CWORD_CWORD_CWORD_CWORD,
3199 /* 184 */ CWORD_CWORD_CWORD_CWORD,
3200 /* 185 */ CWORD_CWORD_CWORD_CWORD,
3201 /* 186 */ CWORD_CWORD_CWORD_CWORD,
3202 /* 187 */ CWORD_CWORD_CWORD_CWORD,
3203 /* 188 */ CWORD_CWORD_CWORD_CWORD,
3204 /* 189 */ CWORD_CWORD_CWORD_CWORD,
3205 /* 190 */ CWORD_CWORD_CWORD_CWORD,
3206 /* 191 */ CWORD_CWORD_CWORD_CWORD,
3207 /* 192 */ CWORD_CWORD_CWORD_CWORD,
3208 /* 193 */ CWORD_CWORD_CWORD_CWORD,
3209 /* 194 */ CWORD_CWORD_CWORD_CWORD,
3210 /* 195 */ CWORD_CWORD_CWORD_CWORD,
3211 /* 196 */ CWORD_CWORD_CWORD_CWORD,
3212 /* 197 */ CWORD_CWORD_CWORD_CWORD,
3213 /* 198 */ CWORD_CWORD_CWORD_CWORD,
3214 /* 199 */ CWORD_CWORD_CWORD_CWORD,
3215 /* 200 */ CWORD_CWORD_CWORD_CWORD,
3216 /* 201 */ CWORD_CWORD_CWORD_CWORD,
3217 /* 202 */ CWORD_CWORD_CWORD_CWORD,
3218 /* 203 */ CWORD_CWORD_CWORD_CWORD,
3219 /* 204 */ CWORD_CWORD_CWORD_CWORD,
3220 /* 205 */ CWORD_CWORD_CWORD_CWORD,
3221 /* 206 */ CWORD_CWORD_CWORD_CWORD,
3222 /* 207 */ CWORD_CWORD_CWORD_CWORD,
3223 /* 208 */ CWORD_CWORD_CWORD_CWORD,
3224 /* 209 */ CWORD_CWORD_CWORD_CWORD,
3225 /* 210 */ CWORD_CWORD_CWORD_CWORD,
3226 /* 211 */ CWORD_CWORD_CWORD_CWORD,
3227 /* 212 */ CWORD_CWORD_CWORD_CWORD,
3228 /* 213 */ CWORD_CWORD_CWORD_CWORD,
3229 /* 214 */ CWORD_CWORD_CWORD_CWORD,
3230 /* 215 */ CWORD_CWORD_CWORD_CWORD,
3231 /* 216 */ CWORD_CWORD_CWORD_CWORD,
3232 /* 217 */ CWORD_CWORD_CWORD_CWORD,
3233 /* 218 */ CWORD_CWORD_CWORD_CWORD,
3234 /* 219 */ CWORD_CWORD_CWORD_CWORD,
3235 /* 220 */ CWORD_CWORD_CWORD_CWORD,
3236 /* 221 */ CWORD_CWORD_CWORD_CWORD,
3237 /* 222 */ CWORD_CWORD_CWORD_CWORD,
3238 /* 223 */ CWORD_CWORD_CWORD_CWORD,
3239 /* 224 */ CWORD_CWORD_CWORD_CWORD,
3240 /* 225 */ CWORD_CWORD_CWORD_CWORD,
3241 /* 226 */ CWORD_CWORD_CWORD_CWORD,
3242 /* 227 */ CWORD_CWORD_CWORD_CWORD,
3243 /* 228 */ CWORD_CWORD_CWORD_CWORD,
3244 /* 229 */ CWORD_CWORD_CWORD_CWORD,
3245 /* 230 */ CWORD_CWORD_CWORD_CWORD,
3246 /* 231 */ CWORD_CWORD_CWORD_CWORD,
3247 /* 232 */ CWORD_CWORD_CWORD_CWORD,
3248 /* 233 */ CWORD_CWORD_CWORD_CWORD,
3249 /* 234 */ CWORD_CWORD_CWORD_CWORD,
3250 /* 235 */ CWORD_CWORD_CWORD_CWORD,
3251 /* 236 */ CWORD_CWORD_CWORD_CWORD,
3252 /* 237 */ CWORD_CWORD_CWORD_CWORD,
3253 /* 238 */ CWORD_CWORD_CWORD_CWORD,
3254 /* 239 */ CWORD_CWORD_CWORD_CWORD,
3255 /* 230 */ CWORD_CWORD_CWORD_CWORD,
3256 /* 241 */ CWORD_CWORD_CWORD_CWORD,
3257 /* 242 */ CWORD_CWORD_CWORD_CWORD,
3258 /* 243 */ CWORD_CWORD_CWORD_CWORD,
3259 /* 244 */ CWORD_CWORD_CWORD_CWORD,
3260 /* 245 */ CWORD_CWORD_CWORD_CWORD,
3261 /* 246 */ CWORD_CWORD_CWORD_CWORD,
3262 /* 247 */ CWORD_CWORD_CWORD_CWORD,
3263 /* 248 */ CWORD_CWORD_CWORD_CWORD,
3264 /* 249 */ CWORD_CWORD_CWORD_CWORD,
3265 /* 250 */ CWORD_CWORD_CWORD_CWORD,
3266 /* 251 */ CWORD_CWORD_CWORD_CWORD,
3267 /* 252 */ CWORD_CWORD_CWORD_CWORD,
3268 /* 253 */ CWORD_CWORD_CWORD_CWORD,
3269 /* 254 */ CWORD_CWORD_CWORD_CWORD,
3270 /* 255 */ CWORD_CWORD_CWORD_CWORD,
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01003271 /* PEOF */ CENDFILE_CENDFILE_CENDFILE_CENDFILE,
Denys Vlasenkocd716832009-11-28 22:14:02 +01003272# if ENABLE_ASH_ALIAS
3273 /* PEOA */ CSPCL_CIGN_CIGN_CIGN,
3274# endif
Eric Andersen2870d962001-07-02 17:27:21 +00003275};
3276
Denys Vlasenko2fe66b12016-12-12 17:39:12 +01003277#if 1
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01003278# define SIT(c, syntax) ((S_I_T[syntax_index_table[c]] >> ((syntax)*4)) & 0xf)
Denys Vlasenko2fe66b12016-12-12 17:39:12 +01003279#else /* debug version, caught one signed char bug */
3280# define SIT(c, syntax) \
3281 ({ \
3282 if ((c) < 0 || (c) > (PEOF + ENABLE_ASH_ALIAS)) \
3283 bb_error_msg_and_die("line:%d c:%d", __LINE__, (c)); \
Denys Vlasenko0b883582016-12-23 16:49:07 +01003284 if ((syntax) < 0 || (syntax) > (2 + ENABLE_FEATURE_SH_MATH)) \
Denys Vlasenko2fe66b12016-12-12 17:39:12 +01003285 bb_error_msg_and_die("line:%d c:%d", __LINE__, (c)); \
3286 ((S_I_T[syntax_index_table[c]] >> ((syntax)*4)) & 0xf); \
3287 })
3288#endif
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00003289
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01003290#endif /* !USE_SIT_FUNCTION */
Eric Andersenc470f442003-07-28 09:56:35 +00003291
Eric Andersen2870d962001-07-02 17:27:21 +00003292
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00003293/* ============ Alias handling */
Denis Vlasenkofc06f292007-02-23 21:09:35 +00003294
Denis Vlasenko131ae172007-02-18 13:00:19 +00003295#if ENABLE_ASH_ALIAS
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00003296
3297#define ALIASINUSE 1
3298#define ALIASDEAD 2
3299
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00003300struct alias {
3301 struct alias *next;
3302 char *name;
3303 char *val;
3304 int flag;
3305};
3306
Denis Vlasenko01631112007-12-16 17:20:38 +00003307
3308static struct alias **atab; // [ATABSIZE];
3309#define INIT_G_alias() do { \
3310 atab = xzalloc(ATABSIZE * sizeof(atab[0])); \
3311} while (0)
3312
Eric Andersen2870d962001-07-02 17:27:21 +00003313
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00003314static struct alias **
Denys Vlasenko37dc08b2016-10-02 04:38:07 +02003315__lookupalias(const char *name)
3316{
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00003317 unsigned int hashval;
3318 struct alias **app;
3319 const char *p;
3320 unsigned int ch;
3321
3322 p = name;
3323
3324 ch = (unsigned char)*p;
3325 hashval = ch << 4;
3326 while (ch) {
3327 hashval += ch;
3328 ch = (unsigned char)*++p;
3329 }
3330 app = &atab[hashval % ATABSIZE];
3331
3332 for (; *app; app = &(*app)->next) {
3333 if (strcmp(name, (*app)->name) == 0) {
3334 break;
3335 }
3336 }
3337
3338 return app;
3339}
3340
3341static struct alias *
3342lookupalias(const char *name, int check)
3343{
3344 struct alias *ap = *__lookupalias(name);
3345
3346 if (check && ap && (ap->flag & ALIASINUSE))
3347 return NULL;
3348 return ap;
3349}
3350
3351static struct alias *
3352freealias(struct alias *ap)
3353{
3354 struct alias *next;
3355
3356 if (ap->flag & ALIASINUSE) {
3357 ap->flag |= ALIASDEAD;
3358 return ap;
3359 }
3360
3361 next = ap->next;
3362 free(ap->name);
3363 free(ap->val);
3364 free(ap);
3365 return next;
3366}
Eric Andersencb57d552001-06-28 07:25:16 +00003367
Eric Andersenc470f442003-07-28 09:56:35 +00003368static void
3369setalias(const char *name, const char *val)
Eric Andersencb57d552001-06-28 07:25:16 +00003370{
3371 struct alias *ap, **app;
3372
3373 app = __lookupalias(name);
3374 ap = *app;
Denis Vlasenkob012b102007-02-19 22:43:01 +00003375 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +00003376 if (ap) {
3377 if (!(ap->flag & ALIASINUSE)) {
Denis Vlasenkob012b102007-02-19 22:43:01 +00003378 free(ap->val);
Eric Andersencb57d552001-06-28 07:25:16 +00003379 }
Denis Vlasenko0c032a42007-02-23 01:03:40 +00003380 ap->val = ckstrdup(val);
Eric Andersencb57d552001-06-28 07:25:16 +00003381 ap->flag &= ~ALIASDEAD;
3382 } else {
3383 /* not found */
Denis Vlasenko597906c2008-02-20 16:38:54 +00003384 ap = ckzalloc(sizeof(struct alias));
Denis Vlasenko0c032a42007-02-23 01:03:40 +00003385 ap->name = ckstrdup(name);
3386 ap->val = ckstrdup(val);
Denis Vlasenko597906c2008-02-20 16:38:54 +00003387 /*ap->flag = 0; - ckzalloc did it */
3388 /*ap->next = NULL;*/
Eric Andersencb57d552001-06-28 07:25:16 +00003389 *app = ap;
3390 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00003391 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +00003392}
3393
Eric Andersenc470f442003-07-28 09:56:35 +00003394static int
3395unalias(const char *name)
Eric Andersen2870d962001-07-02 17:27:21 +00003396{
Eric Andersencb57d552001-06-28 07:25:16 +00003397 struct alias **app;
3398
3399 app = __lookupalias(name);
3400
3401 if (*app) {
Denis Vlasenkob012b102007-02-19 22:43:01 +00003402 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +00003403 *app = freealias(*app);
Denis Vlasenkob012b102007-02-19 22:43:01 +00003404 INT_ON;
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003405 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003406 }
3407
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003408 return 1;
Eric Andersencb57d552001-06-28 07:25:16 +00003409}
3410
Eric Andersenc470f442003-07-28 09:56:35 +00003411static void
3412rmaliases(void)
Eric Andersen2870d962001-07-02 17:27:21 +00003413{
Eric Andersencb57d552001-06-28 07:25:16 +00003414 struct alias *ap, **app;
3415 int i;
3416
Denis Vlasenkob012b102007-02-19 22:43:01 +00003417 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +00003418 for (i = 0; i < ATABSIZE; i++) {
3419 app = &atab[i];
3420 for (ap = *app; ap; ap = *app) {
3421 *app = freealias(*app);
3422 if (ap == *app) {
3423 app = &ap->next;
3424 }
3425 }
3426 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00003427 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +00003428}
3429
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00003430static void
3431printalias(const struct alias *ap)
3432{
3433 out1fmt("%s=%s\n", ap->name, single_quote(ap->val));
3434}
3435
Eric Andersencb57d552001-06-28 07:25:16 +00003436/*
3437 * TODO - sort output
3438 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02003439static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003440aliascmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003441{
3442 char *n, *v;
3443 int ret = 0;
3444 struct alias *ap;
3445
Denis Vlasenko68404f12008-03-17 09:00:54 +00003446 if (!argv[1]) {
Eric Andersencb57d552001-06-28 07:25:16 +00003447 int i;
3448
Denis Vlasenko68404f12008-03-17 09:00:54 +00003449 for (i = 0; i < ATABSIZE; i++) {
Eric Andersencb57d552001-06-28 07:25:16 +00003450 for (ap = atab[i]; ap; ap = ap->next) {
3451 printalias(ap);
3452 }
Denis Vlasenko68404f12008-03-17 09:00:54 +00003453 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003454 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003455 }
3456 while ((n = *++argv) != NULL) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +00003457 v = strchr(n+1, '=');
3458 if (v == NULL) { /* n+1: funny ksh stuff */
3459 ap = *__lookupalias(n);
3460 if (ap == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00003461 fprintf(stderr, "%s: %s not found\n", "alias", n);
Eric Andersencb57d552001-06-28 07:25:16 +00003462 ret = 1;
3463 } else
3464 printalias(ap);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003465 } else {
Eric Andersencb57d552001-06-28 07:25:16 +00003466 *v++ = '\0';
3467 setalias(n, v);
3468 }
3469 }
3470
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003471 return ret;
Eric Andersencb57d552001-06-28 07:25:16 +00003472}
3473
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02003474static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003475unaliascmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +00003476{
3477 int i;
3478
Denys Vlasenko6c149f42017-04-12 21:31:32 +02003479 while (nextopt("a") != '\0') {
3480 rmaliases();
3481 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003482 }
3483 for (i = 0; *argptr; argptr++) {
3484 if (unalias(*argptr)) {
Eric Andersenc470f442003-07-28 09:56:35 +00003485 fprintf(stderr, "%s: %s not found\n", "unalias", *argptr);
Eric Andersencb57d552001-06-28 07:25:16 +00003486 i = 1;
3487 }
3488 }
3489
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003490 return i;
Eric Andersencb57d552001-06-28 07:25:16 +00003491}
Denis Vlasenkofc06f292007-02-23 21:09:35 +00003492
Denis Vlasenko131ae172007-02-18 13:00:19 +00003493#endif /* ASH_ALIAS */
Eric Andersencb57d552001-06-28 07:25:16 +00003494
Eric Andersenc470f442003-07-28 09:56:35 +00003495
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003496/* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */
Denys Vlasenko285ad152009-12-04 23:02:27 +01003497#define FORK_FG 0
3498#define FORK_BG 1
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003499#define FORK_NOJOB 2
3500
3501/* mode flags for showjob(s) */
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02003502#define SHOW_ONLY_PGID 0x01 /* show only pgid (jobs -p) */
3503#define SHOW_PIDS 0x02 /* show individual pids, not just one line per job */
3504#define SHOW_CHANGED 0x04 /* only jobs whose state has changed */
Denys Vlasenko9c541002015-10-07 15:44:36 +02003505#define SHOW_STDERR 0x08 /* print to stderr (else stdout) */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003506
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003507/*
3508 * A job structure contains information about a job. A job is either a
3509 * single process or a set of processes contained in a pipeline. In the
3510 * latter case, pidlist will be non-NULL, and will point to a -1 terminated
3511 * array of pids.
3512 */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003513struct procstat {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003514 pid_t ps_pid; /* process id */
3515 int ps_status; /* last process status from wait() */
3516 char *ps_cmd; /* text of command being run */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003517};
3518
3519struct job {
3520 struct procstat ps0; /* status of process */
3521 struct procstat *ps; /* status or processes when more than one */
3522#if JOBS
3523 int stopstatus; /* status of a stopped job */
3524#endif
Denys Vlasenko4c179372017-01-11 18:44:15 +01003525 unsigned nprocs; /* number of processes */
3526
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003527#define JOBRUNNING 0 /* at least one proc running */
3528#define JOBSTOPPED 1 /* all procs are stopped */
3529#define JOBDONE 2 /* all procs are completed */
Denys Vlasenko4c179372017-01-11 18:44:15 +01003530 unsigned
3531 state: 8,
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003532#if JOBS
3533 sigint: 1, /* job was killed by SIGINT */
3534 jobctl: 1, /* job running under job control */
3535#endif
3536 waited: 1, /* true if this entry has been waited for */
3537 used: 1, /* true if this entry is in used */
3538 changed: 1; /* true if status has changed */
3539 struct job *prev_job; /* previous job */
3540};
3541
Denis Vlasenko68404f12008-03-17 09:00:54 +00003542static struct job *makejob(/*union node *,*/ int);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003543static int forkshell(struct job *, union node *, int);
3544static int waitforjob(struct job *);
3545
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00003546#if !JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +00003547enum { doing_jobctl = 0 };
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00003548#define setjobctl(on) do {} while (0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003549#else
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003550static smallint doing_jobctl; //references:8
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003551static void setjobctl(int);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003552#endif
3553
3554/*
Denis Vlasenko4b875702009-03-19 13:30:04 +00003555 * Ignore a signal.
3556 */
3557static void
3558ignoresig(int signo)
3559{
3560 /* Avoid unnecessary system calls. Is it already SIG_IGNed? */
3561 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
3562 /* No, need to do it */
3563 signal(signo, SIG_IGN);
3564 }
3565 sigmode[signo - 1] = S_HARD_IGN;
3566}
3567
3568/*
Denys Vlasenko238bf182010-05-18 15:49:07 +02003569 * Only one usage site - in setsignal()
Denis Vlasenko4b875702009-03-19 13:30:04 +00003570 */
3571static void
Denys Vlasenko238bf182010-05-18 15:49:07 +02003572signal_handler(int signo)
Denis Vlasenko4b875702009-03-19 13:30:04 +00003573{
Denys Vlasenko458c1f22016-10-27 23:51:19 +02003574 if (signo == SIGCHLD) {
3575 got_sigchld = 1;
3576 if (!trap[SIGCHLD])
3577 return;
3578 }
3579
Denis Vlasenko4b875702009-03-19 13:30:04 +00003580 gotsig[signo - 1] = 1;
Denys Vlasenko458c1f22016-10-27 23:51:19 +02003581 pending_sig = signo;
Denis Vlasenko4b875702009-03-19 13:30:04 +00003582
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02003583 if (signo == SIGINT && !trap[SIGINT]) {
3584 if (!suppress_int) {
3585 pending_sig = 0;
Denis Vlasenko4b875702009-03-19 13:30:04 +00003586 raise_interrupt(); /* does not return */
3587 }
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02003588 pending_int = 1;
Denis Vlasenko4b875702009-03-19 13:30:04 +00003589 }
3590}
3591
3592/*
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003593 * Set the signal handler for the specified signal. The routine figures
3594 * out what it should be set to.
3595 */
3596static void
3597setsignal(int signo)
3598{
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003599 char *t;
3600 char cur_act, new_act;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003601 struct sigaction act;
3602
3603 t = trap[signo];
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003604 new_act = S_DFL;
3605 if (t != NULL) { /* trap for this sig is set */
3606 new_act = S_CATCH;
3607 if (t[0] == '\0') /* trap is "": ignore this sig */
3608 new_act = S_IGN;
3609 }
3610
3611 if (rootshell && new_act == S_DFL) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003612 switch (signo) {
3613 case SIGINT:
3614 if (iflag || minusc || sflag == 0)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003615 new_act = S_CATCH;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003616 break;
3617 case SIGQUIT:
3618#if DEBUG
3619 if (debug)
3620 break;
3621#endif
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003622 /* man bash:
3623 * "In all cases, bash ignores SIGQUIT. Non-builtin
3624 * commands run by bash have signal handlers
3625 * set to the values inherited by the shell
3626 * from its parent". */
3627 new_act = S_IGN;
3628 break;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003629 case SIGTERM:
3630 if (iflag)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003631 new_act = S_IGN;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003632 break;
3633#if JOBS
3634 case SIGTSTP:
3635 case SIGTTOU:
3636 if (mflag)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003637 new_act = S_IGN;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003638 break;
3639#endif
3640 }
3641 }
Denys Vlasenko49e6bf22017-08-04 14:28:16 +02003642 /* if !rootshell, we reset SIGQUIT to DFL,
3643 * whereas we have to restore it to what shell got on entry.
3644 * This is handled by the fact that if signal was IGNored on entry,
3645 * then cur_act is S_HARD_IGN and we never change its sigaction
3646 * (see code below).
3647 */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003648
Denys Vlasenko458c1f22016-10-27 23:51:19 +02003649 if (signo == SIGCHLD)
3650 new_act = S_CATCH;
3651
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003652 t = &sigmode[signo - 1];
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003653 cur_act = *t;
3654 if (cur_act == 0) {
3655 /* current setting is not yet known */
3656 if (sigaction(signo, NULL, &act)) {
3657 /* pretend it worked; maybe we should give a warning,
3658 * but other shells don't. We don't alter sigmode,
3659 * so we retry every time.
3660 * btw, in Linux it never fails. --vda */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003661 return;
3662 }
3663 if (act.sa_handler == SIG_IGN) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003664 cur_act = S_HARD_IGN;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003665 if (mflag
3666 && (signo == SIGTSTP || signo == SIGTTIN || signo == SIGTTOU)
3667 ) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003668 cur_act = S_IGN; /* don't hard ignore these */
Denis Vlasenko991a1da2008-02-10 19:02:53 +00003669 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003670 }
Denys Vlasenko0f14f412017-08-06 20:06:19 +02003671 if (act.sa_handler == SIG_DFL && new_act == S_DFL) {
3672 /* installing SIG_DFL over SIG_DFL is a no-op */
3673 /* saves one sigaction call in each "sh -c SCRIPT" invocation */
3674 *t = S_DFL;
3675 return;
3676 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003677 }
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003678 if (cur_act == S_HARD_IGN || cur_act == new_act)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003679 return;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003680
Denys Vlasenko49e6bf22017-08-04 14:28:16 +02003681 *t = new_act;
3682
Denis Vlasenko991a1da2008-02-10 19:02:53 +00003683 act.sa_handler = SIG_DFL;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003684 switch (new_act) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003685 case S_CATCH:
Denys Vlasenko238bf182010-05-18 15:49:07 +02003686 act.sa_handler = signal_handler;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003687 break;
3688 case S_IGN:
3689 act.sa_handler = SIG_IGN;
3690 break;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003691 }
Ian Wienand89b3cba2011-04-16 20:05:14 +02003692 /* flags and mask matter only if !DFL and !IGN, but we do it
3693 * for all cases for more deterministic behavior:
3694 */
Denys Vlasenko49e6bf22017-08-04 14:28:16 +02003695 act.sa_flags = 0; //TODO: why not SA_RESTART?
Ian Wienand89b3cba2011-04-16 20:05:14 +02003696 sigfillset(&act.sa_mask);
3697
Denis Vlasenko8e2cfec2008-03-12 23:19:35 +00003698 sigaction_set(signo, &act);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003699}
3700
3701/* mode flags for set_curjob */
3702#define CUR_DELETE 2
3703#define CUR_RUNNING 1
3704#define CUR_STOPPED 0
3705
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003706#if JOBS
3707/* pgrp of shell on invocation */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003708static int initialpgrp; //references:2
3709static int ttyfd = -1; //5
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003710#endif
3711/* array of jobs */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003712static struct job *jobtab; //5
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003713/* size of array */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003714static unsigned njobs; //4
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003715/* current job */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003716static struct job *curjob; //lots
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003717/* number of presumed living untracked jobs */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003718static int jobless; //4
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003719
Denys Vlasenko098b7132017-01-11 19:59:03 +01003720#if 0
3721/* Bash has a feature: it restores termios after a successful wait for
3722 * a foreground job which had at least one stopped or sigkilled member.
3723 * The probable rationale is that SIGSTOP and SIGKILL can preclude task from
3724 * properly restoring tty state. Should we do this too?
3725 * A reproducer: ^Z an interactive python:
3726 *
3727 * # python
3728 * Python 2.7.12 (...)
3729 * >>> ^Z
3730 * { python leaves tty in -icanon -echo state. We do survive that... }
3731 * [1]+ Stopped python
3732 * { ...however, next program (python #2) does not survive it well: }
3733 * # python
3734 * Python 2.7.12 (...)
3735 * >>> Traceback (most recent call last):
3736 * { above, I typed "qwerty<CR>", but -echo state is still in effect }
3737 * File "<stdin>", line 1, in <module>
3738 * NameError: name 'qwerty' is not defined
3739 *
3740 * The implementation below is modeled on bash code and seems to work.
3741 * However, I'm not sure we should do this. For one: what if I'd fg
3742 * the stopped python instead? It'll be confused by "restored" tty state.
3743 */
3744static struct termios shell_tty_info;
3745static void
3746get_tty_state(void)
3747{
3748 if (rootshell && ttyfd >= 0)
3749 tcgetattr(ttyfd, &shell_tty_info);
3750}
3751static void
3752set_tty_state(void)
3753{
3754 /* if (rootshell) - caller ensures this */
3755 if (ttyfd >= 0)
3756 tcsetattr(ttyfd, TCSADRAIN, &shell_tty_info);
3757}
3758static int
3759job_signal_status(struct job *jp)
3760{
3761 int status;
3762 unsigned i;
3763 struct procstat *ps = jp->ps;
3764 for (i = 0; i < jp->nprocs; i++) {
3765 status = ps[i].ps_status;
3766 if (WIFSIGNALED(status) || WIFSTOPPED(status))
3767 return status;
3768 }
3769 return 0;
3770}
3771static void
3772restore_tty_if_stopped_or_signaled(struct job *jp)
3773{
3774//TODO: check what happens if we come from waitforjob() in expbackq()
3775 if (rootshell) {
3776 int s = job_signal_status(jp);
3777 if (s) /* WIFSIGNALED(s) || WIFSTOPPED(s) */
3778 set_tty_state();
3779 }
3780}
3781#else
3782# define get_tty_state() ((void)0)
3783# define restore_tty_if_stopped_or_signaled(jp) ((void)0)
3784#endif
3785
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003786static void
3787set_curjob(struct job *jp, unsigned mode)
3788{
3789 struct job *jp1;
3790 struct job **jpp, **curp;
3791
3792 /* first remove from list */
3793 jpp = curp = &curjob;
Denys Vlasenko940c7202011-03-02 04:07:14 +01003794 while (1) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003795 jp1 = *jpp;
3796 if (jp1 == jp)
3797 break;
3798 jpp = &jp1->prev_job;
Denys Vlasenko940c7202011-03-02 04:07:14 +01003799 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003800 *jpp = jp1->prev_job;
3801
3802 /* Then re-insert in correct position */
3803 jpp = curp;
3804 switch (mode) {
3805 default:
3806#if DEBUG
3807 abort();
3808#endif
3809 case CUR_DELETE:
3810 /* job being deleted */
3811 break;
3812 case CUR_RUNNING:
3813 /* newly created job or backgrounded job,
Denys Vlasenko60cb48c2013-01-14 15:57:44 +01003814 * put after all stopped jobs.
3815 */
Denys Vlasenko940c7202011-03-02 04:07:14 +01003816 while (1) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003817 jp1 = *jpp;
3818#if JOBS
3819 if (!jp1 || jp1->state != JOBSTOPPED)
3820#endif
3821 break;
3822 jpp = &jp1->prev_job;
Denys Vlasenko940c7202011-03-02 04:07:14 +01003823 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003824 /* FALLTHROUGH */
3825#if JOBS
3826 case CUR_STOPPED:
3827#endif
3828 /* newly stopped job - becomes curjob */
3829 jp->prev_job = *jpp;
3830 *jpp = jp;
3831 break;
3832 }
3833}
3834
3835#if JOBS || DEBUG
3836static int
3837jobno(const struct job *jp)
3838{
3839 return jp - jobtab + 1;
3840}
3841#endif
3842
3843/*
3844 * Convert a job name to a job structure.
3845 */
Denis Vlasenko85c24712008-03-17 09:04:04 +00003846#if !JOBS
3847#define getjob(name, getctl) getjob(name)
3848#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003849static struct job *
3850getjob(const char *name, int getctl)
3851{
3852 struct job *jp;
3853 struct job *found;
Denys Vlasenkoffc39202009-08-17 02:12:20 +02003854 const char *err_msg = "%s: no such job";
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003855 unsigned num;
3856 int c;
3857 const char *p;
3858 char *(*match)(const char *, const char *);
3859
3860 jp = curjob;
3861 p = name;
3862 if (!p)
3863 goto currentjob;
3864
3865 if (*p != '%')
3866 goto err;
3867
3868 c = *++p;
3869 if (!c)
3870 goto currentjob;
3871
3872 if (!p[1]) {
3873 if (c == '+' || c == '%') {
3874 currentjob:
3875 err_msg = "No current job";
3876 goto check;
3877 }
3878 if (c == '-') {
3879 if (jp)
3880 jp = jp->prev_job;
3881 err_msg = "No previous job";
3882 check:
3883 if (!jp)
3884 goto err;
3885 goto gotit;
3886 }
3887 }
3888
3889 if (is_number(p)) {
3890 num = atoi(p);
Denys Vlasenko46a45ce2016-09-29 01:10:08 +02003891 if (num > 0 && num <= njobs) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003892 jp = jobtab + num - 1;
3893 if (jp->used)
3894 goto gotit;
3895 goto err;
3896 }
3897 }
3898
3899 match = prefix;
3900 if (*p == '?') {
3901 match = strstr;
3902 p++;
3903 }
3904
Denys Vlasenkoffc39202009-08-17 02:12:20 +02003905 found = NULL;
3906 while (jp) {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003907 if (match(jp->ps[0].ps_cmd, p)) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003908 if (found)
3909 goto err;
3910 found = jp;
3911 err_msg = "%s: ambiguous";
3912 }
3913 jp = jp->prev_job;
3914 }
Denys Vlasenkoffc39202009-08-17 02:12:20 +02003915 if (!found)
3916 goto err;
3917 jp = found;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003918
3919 gotit:
3920#if JOBS
3921 err_msg = "job %s not created under job control";
3922 if (getctl && jp->jobctl == 0)
3923 goto err;
3924#endif
3925 return jp;
3926 err:
3927 ash_msg_and_raise_error(err_msg, name);
3928}
3929
3930/*
3931 * Mark a job structure as unused.
3932 */
3933static void
3934freejob(struct job *jp)
3935{
3936 struct procstat *ps;
3937 int i;
3938
3939 INT_OFF;
3940 for (i = jp->nprocs, ps = jp->ps; --i >= 0; ps++) {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003941 if (ps->ps_cmd != nullstr)
3942 free(ps->ps_cmd);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003943 }
3944 if (jp->ps != &jp->ps0)
3945 free(jp->ps);
3946 jp->used = 0;
3947 set_curjob(jp, CUR_DELETE);
3948 INT_ON;
3949}
3950
3951#if JOBS
3952static void
3953xtcsetpgrp(int fd, pid_t pgrp)
3954{
3955 if (tcsetpgrp(fd, pgrp))
Ron Yorstonbe366e52017-07-27 13:53:39 +01003956 ash_msg_and_raise_perror("can't set tty process group");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003957}
3958
3959/*
3960 * Turn job control on and off.
3961 *
3962 * Note: This code assumes that the third arg to ioctl is a character
3963 * pointer, which is true on Berkeley systems but not System V. Since
3964 * System V doesn't have job control yet, this isn't a problem now.
3965 *
3966 * Called with interrupts off.
3967 */
3968static void
3969setjobctl(int on)
3970{
3971 int fd;
3972 int pgrp;
3973
Denis Vlasenkob07a4962008-06-22 13:16:23 +00003974 if (on == doing_jobctl || rootshell == 0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003975 return;
3976 if (on) {
3977 int ofd;
3978 ofd = fd = open(_PATH_TTY, O_RDWR);
3979 if (fd < 0) {
3980 /* BTW, bash will try to open(ttyname(0)) if open("/dev/tty") fails.
3981 * That sometimes helps to acquire controlling tty.
3982 * Obviously, a workaround for bugs when someone
3983 * failed to provide a controlling tty to bash! :) */
Denis Vlasenkoed270a52007-11-26 05:37:07 +00003984 fd = 2;
3985 while (!isatty(fd))
3986 if (--fd < 0)
3987 goto out;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003988 }
Denys Vlasenko64774602016-10-26 15:24:30 +02003989 /* fd is a tty at this point */
Denys Vlasenko60fb98e2018-03-30 22:15:14 +02003990 fd = fcntl(fd, F_DUPFD_CLOEXEC, 10);
Denys Vlasenko10ad6222017-04-17 16:13:32 +02003991 if (ofd >= 0) /* if it is "/dev/tty", close. If 0/1/2, don't */
Denis Vlasenkoed270a52007-11-26 05:37:07 +00003992 close(ofd);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003993 if (fd < 0)
Denys Vlasenko64774602016-10-26 15:24:30 +02003994 goto out; /* F_DUPFD failed */
Denys Vlasenko60fb98e2018-03-30 22:15:14 +02003995 if (F_DUPFD_CLOEXEC == F_DUPFD) /* if old libc (w/o F_DUPFD_CLOEXEC) */
3996 close_on_exec_on(fd);
Denys Vlasenko940c7202011-03-02 04:07:14 +01003997 while (1) { /* while we are in the background */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003998 pgrp = tcgetpgrp(fd);
3999 if (pgrp < 0) {
4000 out:
4001 ash_msg("can't access tty; job control turned off");
4002 mflag = on = 0;
4003 goto close;
4004 }
4005 if (pgrp == getpgrp())
4006 break;
4007 killpg(0, SIGTTIN);
Denys Vlasenko940c7202011-03-02 04:07:14 +01004008 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004009 initialpgrp = pgrp;
4010
4011 setsignal(SIGTSTP);
4012 setsignal(SIGTTOU);
4013 setsignal(SIGTTIN);
4014 pgrp = rootpid;
4015 setpgid(0, pgrp);
4016 xtcsetpgrp(fd, pgrp);
4017 } else {
4018 /* turning job control off */
4019 fd = ttyfd;
4020 pgrp = initialpgrp;
Denis Vlasenko08c8c1d2007-04-28 22:39:02 +00004021 /* was xtcsetpgrp, but this can make exiting ash
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004022 * loop forever if pty is already deleted */
Denis Vlasenko08c8c1d2007-04-28 22:39:02 +00004023 tcsetpgrp(fd, pgrp);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004024 setpgid(0, pgrp);
4025 setsignal(SIGTSTP);
4026 setsignal(SIGTTOU);
4027 setsignal(SIGTTIN);
4028 close:
Denis Vlasenkoed270a52007-11-26 05:37:07 +00004029 if (fd >= 0)
4030 close(fd);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004031 fd = -1;
4032 }
4033 ttyfd = fd;
Denis Vlasenkob07a4962008-06-22 13:16:23 +00004034 doing_jobctl = on;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004035}
4036
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02004037static int FAST_FUNC
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004038killcmd(int argc, char **argv)
4039{
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00004040 if (argv[1] && strcmp(argv[1], "-l") != 0) {
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004041 int i = 1;
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00004042 do {
4043 if (argv[i][0] == '%') {
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004044 /*
4045 * "kill %N" - job kill
4046 * Converting to pgrp / pid kill
4047 */
4048 struct job *jp;
4049 char *dst;
4050 int j, n;
4051
4052 jp = getjob(argv[i], 0);
4053 /*
4054 * In jobs started under job control, we signal
4055 * entire process group by kill -PGRP_ID.
4056 * This happens, f.e., in interactive shell.
4057 *
4058 * Otherwise, we signal each child via
4059 * kill PID1 PID2 PID3.
4060 * Testcases:
4061 * sh -c 'sleep 1|sleep 1 & kill %1'
4062 * sh -c 'true|sleep 2 & sleep 1; kill %1'
4063 * sh -c 'true|sleep 1 & sleep 2; kill %1'
4064 */
4065 n = jp->nprocs; /* can't be 0 (I hope) */
4066 if (jp->jobctl)
4067 n = 1;
4068 dst = alloca(n * sizeof(int)*4);
4069 argv[i] = dst;
4070 for (j = 0; j < n; j++) {
4071 struct procstat *ps = &jp->ps[j];
4072 /* Skip non-running and not-stopped members
4073 * (i.e. dead members) of the job
4074 */
4075 if (ps->ps_status != -1 && !WIFSTOPPED(ps->ps_status))
4076 continue;
4077 /*
4078 * kill_main has matching code to expect
4079 * leading space. Needed to not confuse
4080 * negative pids with "kill -SIGNAL_NO" syntax
4081 */
4082 dst += sprintf(dst, jp->jobctl ? " -%u" : " %u", (int)ps->ps_pid);
4083 }
4084 *dst = '\0';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004085 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00004086 } while (argv[++i]);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004087 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00004088 return kill_main(argc, argv);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004089}
4090
4091static void
Denys Vlasenko285ad152009-12-04 23:02:27 +01004092showpipe(struct job *jp /*, FILE *out*/)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004093{
Denys Vlasenko285ad152009-12-04 23:02:27 +01004094 struct procstat *ps;
4095 struct procstat *psend;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004096
Denys Vlasenko285ad152009-12-04 23:02:27 +01004097 psend = jp->ps + jp->nprocs;
4098 for (ps = jp->ps + 1; ps < psend; ps++)
4099 printf(" | %s", ps->ps_cmd);
Denys Vlasenko9c541002015-10-07 15:44:36 +02004100 newline_and_flush(stdout);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004101 flush_stdout_stderr();
4102}
4103
4104
4105static int
4106restartjob(struct job *jp, int mode)
4107{
4108 struct procstat *ps;
4109 int i;
4110 int status;
4111 pid_t pgid;
4112
4113 INT_OFF;
4114 if (jp->state == JOBDONE)
4115 goto out;
4116 jp->state = JOBRUNNING;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004117 pgid = jp->ps[0].ps_pid;
Denys Vlasenko098b7132017-01-11 19:59:03 +01004118 if (mode == FORK_FG) {
4119 get_tty_state();
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004120 xtcsetpgrp(ttyfd, pgid);
Denys Vlasenko098b7132017-01-11 19:59:03 +01004121 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004122 killpg(pgid, SIGCONT);
4123 ps = jp->ps;
4124 i = jp->nprocs;
4125 do {
Denys Vlasenko285ad152009-12-04 23:02:27 +01004126 if (WIFSTOPPED(ps->ps_status)) {
4127 ps->ps_status = -1;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004128 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00004129 ps++;
4130 } while (--i);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004131 out:
4132 status = (mode == FORK_FG) ? waitforjob(jp) : 0;
4133 INT_ON;
4134 return status;
4135}
4136
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02004137static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00004138fg_bgcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004139{
4140 struct job *jp;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004141 int mode;
4142 int retval;
4143
4144 mode = (**argv == 'f') ? FORK_FG : FORK_BG;
4145 nextopt(nullstr);
4146 argv = argptr;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004147 do {
4148 jp = getjob(*argv, 1);
4149 if (mode == FORK_BG) {
4150 set_curjob(jp, CUR_RUNNING);
Denys Vlasenko285ad152009-12-04 23:02:27 +01004151 printf("[%d] ", jobno(jp));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004152 }
Denys Vlasenko285ad152009-12-04 23:02:27 +01004153 out1str(jp->ps[0].ps_cmd);
4154 showpipe(jp /*, stdout*/);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004155 retval = restartjob(jp, mode);
4156 } while (*argv && *++argv);
4157 return retval;
4158}
4159#endif
4160
4161static int
Denys Vlasenko9c541002015-10-07 15:44:36 +02004162sprint_status48(char *s, int status, int sigonly)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004163{
4164 int col;
4165 int st;
4166
4167 col = 0;
4168 if (!WIFEXITED(status)) {
Johannes Schindelin9d4dc842017-07-14 22:25:58 +02004169#if JOBS
4170 if (WIFSTOPPED(status))
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004171 st = WSTOPSIG(status);
4172 else
Johannes Schindelin9d4dc842017-07-14 22:25:58 +02004173#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004174 st = WTERMSIG(status);
4175 if (sigonly) {
4176 if (st == SIGINT || st == SIGPIPE)
4177 goto out;
Johannes Schindelin9d4dc842017-07-14 22:25:58 +02004178#if JOBS
4179 if (WIFSTOPPED(status))
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004180 goto out;
Johannes Schindelin9d4dc842017-07-14 22:25:58 +02004181#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004182 }
4183 st &= 0x7f;
Denys Vlasenko7c6f2462011-02-14 17:17:10 +01004184//TODO: use bbox's get_signame? strsignal adds ~600 bytes to text+rodata
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004185 col = fmtstr(s, 32, strsignal(st));
4186 if (WCOREDUMP(status)) {
Denys Vlasenko9c541002015-10-07 15:44:36 +02004187 strcpy(s + col, " (core dumped)");
4188 col += sizeof(" (core dumped)")-1;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004189 }
4190 } else if (!sigonly) {
4191 st = WEXITSTATUS(status);
Denys Vlasenko9c541002015-10-07 15:44:36 +02004192 col = fmtstr(s, 16, (st ? "Done(%d)" : "Done"), st);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004193 }
4194 out:
4195 return col;
4196}
4197
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004198static int
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004199wait_block_or_sig(int *status)
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004200{
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004201 int pid;
4202
4203 do {
Denys Vlasenko1ab7c2f2016-11-03 20:17:23 +01004204 sigset_t mask;
4205
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004206 /* Poll all children for changes in their state */
4207 got_sigchld = 0;
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004208 /* if job control is active, accept stopped processes too */
4209 pid = waitpid(-1, status, doing_jobctl ? (WNOHANG|WUNTRACED) : WNOHANG);
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004210 if (pid != 0)
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004211 break; /* Error (e.g. EINTR, ECHILD) or pid */
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004212
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004213 /* Children exist, but none are ready. Sleep until interesting signal */
Denys Vlasenko1ab7c2f2016-11-03 20:17:23 +01004214#if 1
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004215 sigfillset(&mask);
4216 sigprocmask(SIG_SETMASK, &mask, &mask);
4217 while (!got_sigchld && !pending_sig)
4218 sigsuspend(&mask);
4219 sigprocmask(SIG_SETMASK, &mask, NULL);
Denys Vlasenko1ab7c2f2016-11-03 20:17:23 +01004220#else /* unsafe: a signal can set pending_sig after check, but before pause() */
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004221 while (!got_sigchld && !pending_sig)
4222 pause();
4223#endif
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004224
4225 /* If it was SIGCHLD, poll children again */
4226 } while (got_sigchld);
4227
4228 return pid;
4229}
4230
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004231#define DOWAIT_NONBLOCK 0
4232#define DOWAIT_BLOCK 1
4233#define DOWAIT_BLOCK_OR_SIG 2
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004234
4235static int
Denys Vlasenkob543bda2016-10-27 20:08:28 +02004236dowait(int block, struct job *job)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004237{
4238 int pid;
4239 int status;
4240 struct job *jp;
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004241 struct job *thisjob = NULL;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004242
Denys Vlasenkob543bda2016-10-27 20:08:28 +02004243 TRACE(("dowait(0x%x) called\n", block));
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +00004244
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004245 /* It's wrong to call waitpid() outside of INT_OFF region:
4246 * signal can arrive just after syscall return and handler can
4247 * longjmp away, losing stop/exit notification processing.
4248 * Thus, for "jobs" builtin, and for waiting for a fg job,
4249 * we call waitpid() (blocking or non-blocking) inside INT_OFF.
4250 *
4251 * However, for "wait" builtin it is wrong to simply call waitpid()
4252 * in INT_OFF region: "wait" needs to wait for any running job
4253 * to change state, but should exit on any trap too.
4254 * In INT_OFF region, a signal just before syscall entry can set
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004255 * pending_sig variables, but we can't check them, and we would
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004256 * either enter a sleeping waitpid() (BUG), or need to busy-loop.
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004257 *
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004258 * Because of this, we run inside INT_OFF, but use a special routine
Denys Vlasenko1ab7c2f2016-11-03 20:17:23 +01004259 * which combines waitpid() and sigsuspend().
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004260 * This is the reason why we need to have a handler for SIGCHLD:
Denys Vlasenko1ab7c2f2016-11-03 20:17:23 +01004261 * SIG_DFL handler does not wake sigsuspend().
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004262 */
4263 INT_OFF;
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004264 if (block == DOWAIT_BLOCK_OR_SIG) {
4265 pid = wait_block_or_sig(&status);
4266 } else {
4267 int wait_flags = 0;
4268 if (block == DOWAIT_NONBLOCK)
4269 wait_flags = WNOHANG;
4270 /* if job control is active, accept stopped processes too */
4271 if (doing_jobctl)
4272 wait_flags |= WUNTRACED;
4273 /* NB: _not_ safe_waitpid, we need to detect EINTR */
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004274 pid = waitpid(-1, &status, wait_flags);
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004275 }
Denis Vlasenkob21f3792009-03-19 23:09:58 +00004276 TRACE(("wait returns pid=%d, status=0x%x, errno=%d(%s)\n",
4277 pid, status, errno, strerror(errno)));
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004278 if (pid <= 0)
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004279 goto out;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004280
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004281 thisjob = NULL;
4282 for (jp = curjob; jp; jp = jp->prev_job) {
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004283 int jobstate;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004284 struct procstat *ps;
4285 struct procstat *psend;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004286 if (jp->state == JOBDONE)
4287 continue;
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004288 jobstate = JOBDONE;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004289 ps = jp->ps;
4290 psend = ps + jp->nprocs;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004291 do {
Denys Vlasenko285ad152009-12-04 23:02:27 +01004292 if (ps->ps_pid == pid) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004293 TRACE(("Job %d: changing status of proc %d "
4294 "from 0x%x to 0x%x\n",
Denys Vlasenko285ad152009-12-04 23:02:27 +01004295 jobno(jp), pid, ps->ps_status, status));
4296 ps->ps_status = status;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004297 thisjob = jp;
4298 }
Denys Vlasenko285ad152009-12-04 23:02:27 +01004299 if (ps->ps_status == -1)
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004300 jobstate = JOBRUNNING;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004301#if JOBS
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004302 if (jobstate == JOBRUNNING)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004303 continue;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004304 if (WIFSTOPPED(ps->ps_status)) {
4305 jp->stopstatus = ps->ps_status;
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004306 jobstate = JOBSTOPPED;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004307 }
4308#endif
Denys Vlasenko285ad152009-12-04 23:02:27 +01004309 } while (++ps < psend);
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004310 if (!thisjob)
4311 continue;
4312
4313 /* Found the job where one of its processes changed its state.
4314 * Is there at least one live and running process in this job? */
4315 if (jobstate != JOBRUNNING) {
4316 /* No. All live processes in the job are stopped
4317 * (JOBSTOPPED) or there are no live processes (JOBDONE)
4318 */
4319 thisjob->changed = 1;
4320 if (thisjob->state != jobstate) {
4321 TRACE(("Job %d: changing state from %d to %d\n",
4322 jobno(thisjob), thisjob->state, jobstate));
4323 thisjob->state = jobstate;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004324#if JOBS
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004325 if (jobstate == JOBSTOPPED)
4326 set_curjob(thisjob, CUR_STOPPED);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004327#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004328 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004329 }
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004330 goto out;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004331 }
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004332 /* The process wasn't found in job list */
Johannes Schindelin9d4dc842017-07-14 22:25:58 +02004333#if JOBS
4334 if (!WIFSTOPPED(status))
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004335 jobless--;
Johannes Schindelin9d4dc842017-07-14 22:25:58 +02004336#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004337 out:
4338 INT_ON;
4339
4340 if (thisjob && thisjob == job) {
4341 char s[48 + 1];
4342 int len;
4343
Denys Vlasenko9c541002015-10-07 15:44:36 +02004344 len = sprint_status48(s, status, 1);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004345 if (len) {
4346 s[len] = '\n';
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004347 s[len + 1] = '\0';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004348 out2str(s);
4349 }
4350 }
4351 return pid;
4352}
4353
4354#if JOBS
4355static void
Denys Vlasenko9c541002015-10-07 15:44:36 +02004356showjob(struct job *jp, int mode)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004357{
4358 struct procstat *ps;
4359 struct procstat *psend;
4360 int col;
Denis Vlasenko40ba9982007-07-14 00:48:29 +00004361 int indent_col;
Denys Vlasenko9c541002015-10-07 15:44:36 +02004362 char s[16 + 16 + 48];
4363 FILE *out = (mode & SHOW_STDERR ? stderr : stdout);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004364
4365 ps = jp->ps;
4366
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004367 if (mode & SHOW_ONLY_PGID) { /* jobs -p */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004368 /* just output process (group) id of pipeline */
Denys Vlasenko285ad152009-12-04 23:02:27 +01004369 fprintf(out, "%d\n", ps->ps_pid);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004370 return;
4371 }
4372
4373 col = fmtstr(s, 16, "[%d] ", jobno(jp));
Denis Vlasenko40ba9982007-07-14 00:48:29 +00004374 indent_col = col;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004375
4376 if (jp == curjob)
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004377 s[col - 3] = '+';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004378 else if (curjob && jp == curjob->prev_job)
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004379 s[col - 3] = '-';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004380
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004381 if (mode & SHOW_PIDS)
Denys Vlasenko285ad152009-12-04 23:02:27 +01004382 col += fmtstr(s + col, 16, "%d ", ps->ps_pid);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004383
4384 psend = ps + jp->nprocs;
4385
4386 if (jp->state == JOBRUNNING) {
4387 strcpy(s + col, "Running");
4388 col += sizeof("Running") - 1;
4389 } else {
Denys Vlasenko285ad152009-12-04 23:02:27 +01004390 int status = psend[-1].ps_status;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004391 if (jp->state == JOBSTOPPED)
4392 status = jp->stopstatus;
Denys Vlasenko9c541002015-10-07 15:44:36 +02004393 col += sprint_status48(s + col, status, 0);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004394 }
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004395 /* By now, "[JOBID]* [maybe PID] STATUS" is printed */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004396
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004397 /* This loop either prints "<cmd1> | <cmd2> | <cmd3>" line
4398 * or prints several "PID | <cmdN>" lines,
4399 * depending on SHOW_PIDS bit.
4400 * We do not print status of individual processes
4401 * between PID and <cmdN>. bash does it, but not very well:
4402 * first line shows overall job status, not process status,
4403 * making it impossible to know 1st process status.
4404 */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004405 goto start;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004406 do {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004407 /* for each process */
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004408 s[0] = '\0';
4409 col = 33;
4410 if (mode & SHOW_PIDS)
Denys Vlasenko285ad152009-12-04 23:02:27 +01004411 col = fmtstr(s, 48, "\n%*c%d ", indent_col, ' ', ps->ps_pid) - 1;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004412 start:
Denys Vlasenko285ad152009-12-04 23:02:27 +01004413 fprintf(out, "%s%*c%s%s",
4414 s,
4415 33 - col >= 0 ? 33 - col : 0, ' ',
4416 ps == jp->ps ? "" : "| ",
4417 ps->ps_cmd
4418 );
4419 } while (++ps != psend);
Denys Vlasenko9c541002015-10-07 15:44:36 +02004420 newline_and_flush(out);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004421
4422 jp->changed = 0;
4423
4424 if (jp->state == JOBDONE) {
4425 TRACE(("showjob: freeing job %d\n", jobno(jp)));
4426 freejob(jp);
4427 }
4428}
4429
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004430/*
4431 * Print a list of jobs. If "change" is nonzero, only print jobs whose
4432 * statuses have changed since the last call to showjobs.
4433 */
4434static void
Denys Vlasenko9c541002015-10-07 15:44:36 +02004435showjobs(int mode)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004436{
4437 struct job *jp;
4438
Denys Vlasenko883cea42009-07-11 15:31:59 +02004439 TRACE(("showjobs(0x%x) called\n", mode));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004440
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004441 /* Handle all finished jobs */
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004442 while (dowait(DOWAIT_NONBLOCK, NULL) > 0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004443 continue;
4444
4445 for (jp = curjob; jp; jp = jp->prev_job) {
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004446 if (!(mode & SHOW_CHANGED) || jp->changed) {
Denys Vlasenko9c541002015-10-07 15:44:36 +02004447 showjob(jp, mode);
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004448 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004449 }
4450}
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004451
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02004452static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00004453jobscmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004454{
4455 int mode, m;
4456
4457 mode = 0;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02004458 while ((m = nextopt("lp")) != '\0') {
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004459 if (m == 'l')
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004460 mode |= SHOW_PIDS;
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004461 else
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004462 mode |= SHOW_ONLY_PGID;
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004463 }
4464
4465 argv = argptr;
4466 if (*argv) {
4467 do
Denys Vlasenko9c541002015-10-07 15:44:36 +02004468 showjob(getjob(*argv, 0), mode);
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004469 while (*++argv);
Denys Vlasenko285ad152009-12-04 23:02:27 +01004470 } else {
Denys Vlasenko9c541002015-10-07 15:44:36 +02004471 showjobs(mode);
Denys Vlasenko285ad152009-12-04 23:02:27 +01004472 }
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004473
4474 return 0;
4475}
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004476#endif /* JOBS */
4477
Michael Abbott359da5e2009-12-04 23:03:29 +01004478/* Called only on finished or stopped jobs (no members are running) */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004479static int
4480getstatus(struct job *job)
4481{
4482 int status;
4483 int retval;
Michael Abbott359da5e2009-12-04 23:03:29 +01004484 struct procstat *ps;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004485
Michael Abbott359da5e2009-12-04 23:03:29 +01004486 /* Fetch last member's status */
4487 ps = job->ps + job->nprocs - 1;
4488 status = ps->ps_status;
4489 if (pipefail) {
4490 /* "set -o pipefail" mode: use last _nonzero_ status */
4491 while (status == 0 && --ps >= job->ps)
4492 status = ps->ps_status;
4493 }
4494
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004495 retval = WEXITSTATUS(status);
4496 if (!WIFEXITED(status)) {
4497#if JOBS
4498 retval = WSTOPSIG(status);
4499 if (!WIFSTOPPED(status))
4500#endif
4501 {
4502 /* XXX: limits number of signals */
4503 retval = WTERMSIG(status);
4504#if JOBS
4505 if (retval == SIGINT)
4506 job->sigint = 1;
4507#endif
4508 }
4509 retval += 128;
4510 }
Denys Vlasenko883cea42009-07-11 15:31:59 +02004511 TRACE(("getstatus: job %d, nproc %d, status 0x%x, retval 0x%x\n",
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004512 jobno(job), job->nprocs, status, retval));
4513 return retval;
4514}
4515
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02004516static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00004517waitcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004518{
4519 struct job *job;
4520 int retval;
4521 struct job *jp;
4522
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004523 nextopt(nullstr);
4524 retval = 0;
4525
4526 argv = argptr;
4527 if (!*argv) {
4528 /* wait for all jobs */
4529 for (;;) {
4530 jp = curjob;
4531 while (1) {
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004532 if (!jp) /* no running procs */
4533 goto ret;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004534 if (jp->state == JOBRUNNING)
4535 break;
4536 jp->waited = 1;
4537 jp = jp->prev_job;
4538 }
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004539 /* man bash:
4540 * "When bash is waiting for an asynchronous command via
4541 * the wait builtin, the reception of a signal for which a trap
4542 * has been set will cause the wait builtin to return immediately
4543 * with an exit status greater than 128, immediately after which
4544 * the trap is executed."
Denys Vlasenko69188112016-10-27 20:18:18 +02004545 */
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004546 dowait(DOWAIT_BLOCK_OR_SIG, NULL);
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02004547 /* if child sends us a signal *and immediately exits*,
4548 * dowait() returns pid > 0. Check this case,
4549 * not "if (dowait() < 0)"!
4550 */
Denys Vlasenko7c1ed9f2010-05-17 04:42:40 +02004551 if (pending_sig)
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02004552 goto sigout;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004553 }
4554 }
4555
4556 retval = 127;
4557 do {
4558 if (**argv != '%') {
4559 pid_t pid = number(*argv);
4560 job = curjob;
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004561 while (1) {
4562 if (!job)
4563 goto repeat;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004564 if (job->ps[job->nprocs - 1].ps_pid == pid)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004565 break;
4566 job = job->prev_job;
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004567 }
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004568 } else {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004569 job = getjob(*argv, 0);
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004570 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004571 /* loop until process terminated or stopped */
Denys Vlasenko69188112016-10-27 20:18:18 +02004572 while (job->state == JOBRUNNING) {
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004573 dowait(DOWAIT_BLOCK_OR_SIG, NULL);
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02004574 if (pending_sig)
4575 goto sigout;
Denys Vlasenko69188112016-10-27 20:18:18 +02004576 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004577 job->waited = 1;
4578 retval = getstatus(job);
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004579 repeat: ;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004580 } while (*++argv);
4581
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004582 ret:
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004583 return retval;
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02004584 sigout:
4585 retval = 128 + pending_sig;
4586 return retval;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004587}
4588
4589static struct job *
4590growjobtab(void)
4591{
4592 size_t len;
4593 ptrdiff_t offset;
4594 struct job *jp, *jq;
4595
4596 len = njobs * sizeof(*jp);
4597 jq = jobtab;
4598 jp = ckrealloc(jq, len + 4 * sizeof(*jp));
4599
4600 offset = (char *)jp - (char *)jq;
4601 if (offset) {
4602 /* Relocate pointers */
4603 size_t l = len;
4604
4605 jq = (struct job *)((char *)jq + l);
4606 while (l) {
4607 l -= sizeof(*jp);
4608 jq--;
4609#define joff(p) ((struct job *)((char *)(p) + l))
4610#define jmove(p) (p) = (void *)((char *)(p) + offset)
4611 if (joff(jp)->ps == &jq->ps0)
4612 jmove(joff(jp)->ps);
4613 if (joff(jp)->prev_job)
4614 jmove(joff(jp)->prev_job);
4615 }
4616 if (curjob)
4617 jmove(curjob);
4618#undef joff
4619#undef jmove
4620 }
4621
4622 njobs += 4;
4623 jobtab = jp;
4624 jp = (struct job *)((char *)jp + len);
4625 jq = jp + 3;
4626 do {
4627 jq->used = 0;
4628 } while (--jq >= jp);
4629 return jp;
4630}
4631
4632/*
4633 * Return a new job structure.
4634 * Called with interrupts off.
4635 */
4636static struct job *
Denis Vlasenko68404f12008-03-17 09:00:54 +00004637makejob(/*union node *node,*/ int nprocs)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004638{
4639 int i;
4640 struct job *jp;
4641
4642 for (i = njobs, jp = jobtab; ; jp++) {
4643 if (--i < 0) {
4644 jp = growjobtab();
4645 break;
4646 }
4647 if (jp->used == 0)
4648 break;
4649 if (jp->state != JOBDONE || !jp->waited)
4650 continue;
4651#if JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +00004652 if (doing_jobctl)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004653 continue;
4654#endif
4655 freejob(jp);
4656 break;
4657 }
4658 memset(jp, 0, sizeof(*jp));
4659#if JOBS
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004660 /* jp->jobctl is a bitfield.
Denys Vlasenko098b7132017-01-11 19:59:03 +01004661 * "jp->jobctl |= doing_jobctl" likely to give awful code */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00004662 if (doing_jobctl)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004663 jp->jobctl = 1;
4664#endif
4665 jp->prev_job = curjob;
4666 curjob = jp;
4667 jp->used = 1;
4668 jp->ps = &jp->ps0;
4669 if (nprocs > 1) {
4670 jp->ps = ckmalloc(nprocs * sizeof(struct procstat));
4671 }
Denis Vlasenko68404f12008-03-17 09:00:54 +00004672 TRACE(("makejob(%d) returns %%%d\n", nprocs,
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004673 jobno(jp)));
4674 return jp;
4675}
4676
4677#if JOBS
4678/*
4679 * Return a string identifying a command (to be printed by the
4680 * jobs command).
4681 */
4682static char *cmdnextc;
4683
4684static void
4685cmdputs(const char *s)
4686{
Denis Vlasenko92e13c22008-03-25 01:17:40 +00004687 static const char vstype[VSTYPE + 1][3] = {
4688 "", "}", "-", "+", "?", "=",
4689 "%", "%%", "#", "##"
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01004690 IF_BASH_SUBSTR(, ":")
4691 IF_BASH_PATTERN_SUBST(, "/", "//")
Denis Vlasenko92e13c22008-03-25 01:17:40 +00004692 };
4693
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004694 const char *p, *str;
Denys Vlasenko46a14772009-12-10 21:27:13 +01004695 char cc[2];
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004696 char *nextc;
Denys Vlasenkocd716832009-11-28 22:14:02 +01004697 unsigned char c;
4698 unsigned char subtype = 0;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004699 int quoted = 0;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004700
Denys Vlasenko46a14772009-12-10 21:27:13 +01004701 cc[1] = '\0';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004702 nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
4703 p = s;
Denys Vlasenko46a14772009-12-10 21:27:13 +01004704 while ((c = *p++) != '\0') {
Denis Vlasenkoef527f52008-06-23 01:52:30 +00004705 str = NULL;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004706 switch (c) {
4707 case CTLESC:
4708 c = *p++;
4709 break;
4710 case CTLVAR:
4711 subtype = *p++;
4712 if ((subtype & VSTYPE) == VSLENGTH)
4713 str = "${#";
4714 else
4715 str = "${";
Ron Yorston549deab2015-05-18 09:57:51 +02004716 goto dostr;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004717 case CTLENDVAR:
4718 str = "\"}" + !(quoted & 1);
4719 quoted >>= 1;
4720 subtype = 0;
4721 goto dostr;
4722 case CTLBACKQ:
4723 str = "$(...)";
4724 goto dostr;
Denys Vlasenko0b883582016-12-23 16:49:07 +01004725#if ENABLE_FEATURE_SH_MATH
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004726 case CTLARI:
4727 str = "$((";
4728 goto dostr;
4729 case CTLENDARI:
4730 str = "))";
4731 goto dostr;
4732#endif
4733 case CTLQUOTEMARK:
4734 quoted ^= 1;
4735 c = '"';
4736 break;
4737 case '=':
4738 if (subtype == 0)
4739 break;
4740 if ((subtype & VSTYPE) != VSNORMAL)
4741 quoted <<= 1;
4742 str = vstype[subtype & VSTYPE];
4743 if (subtype & VSNUL)
4744 c = ':';
4745 else
4746 goto checkstr;
4747 break;
4748 case '\'':
4749 case '\\':
4750 case '"':
4751 case '$':
4752 /* These can only happen inside quotes */
4753 cc[0] = c;
4754 str = cc;
Denys Vlasenkod0fff912017-07-31 14:32:18 +02004755//FIXME:
4756// $ true $$ &
4757// $ <cr>
4758// [1]+ Done true ${\$} <<=== BUG: ${\$} is not a valid way to write $$ (${$} would be ok)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004759 c = '\\';
4760 break;
4761 default:
4762 break;
4763 }
4764 USTPUTC(c, nextc);
4765 checkstr:
4766 if (!str)
4767 continue;
4768 dostr:
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02004769 while ((c = *str++) != '\0') {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004770 USTPUTC(c, nextc);
4771 }
Denys Vlasenko46a14772009-12-10 21:27:13 +01004772 } /* while *p++ not NUL */
4773
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004774 if (quoted & 1) {
4775 USTPUTC('"', nextc);
4776 }
4777 *nextc = 0;
4778 cmdnextc = nextc;
4779}
4780
4781/* cmdtxt() and cmdlist() call each other */
4782static void cmdtxt(union node *n);
4783
4784static void
4785cmdlist(union node *np, int sep)
4786{
4787 for (; np; np = np->narg.next) {
4788 if (!sep)
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00004789 cmdputs(" ");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004790 cmdtxt(np);
4791 if (sep && np->narg.next)
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00004792 cmdputs(" ");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004793 }
4794}
4795
4796static void
4797cmdtxt(union node *n)
4798{
4799 union node *np;
4800 struct nodelist *lp;
4801 const char *p;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004802
4803 if (!n)
4804 return;
4805 switch (n->type) {
4806 default:
4807#if DEBUG
4808 abort();
4809#endif
4810 case NPIPE:
4811 lp = n->npipe.cmdlist;
4812 for (;;) {
4813 cmdtxt(lp->n);
4814 lp = lp->next;
4815 if (!lp)
4816 break;
4817 cmdputs(" | ");
4818 }
4819 break;
4820 case NSEMI:
4821 p = "; ";
4822 goto binop;
4823 case NAND:
4824 p = " && ";
4825 goto binop;
4826 case NOR:
4827 p = " || ";
4828 binop:
4829 cmdtxt(n->nbinary.ch1);
4830 cmdputs(p);
4831 n = n->nbinary.ch2;
4832 goto donode;
4833 case NREDIR:
4834 case NBACKGND:
4835 n = n->nredir.n;
4836 goto donode;
4837 case NNOT:
4838 cmdputs("!");
4839 n = n->nnot.com;
4840 donode:
4841 cmdtxt(n);
4842 break;
4843 case NIF:
4844 cmdputs("if ");
4845 cmdtxt(n->nif.test);
4846 cmdputs("; then ");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004847 if (n->nif.elsepart) {
Denys Vlasenko7cee00e2009-07-24 01:08:03 +02004848 cmdtxt(n->nif.ifpart);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004849 cmdputs("; else ");
4850 n = n->nif.elsepart;
Denys Vlasenko7cee00e2009-07-24 01:08:03 +02004851 } else {
4852 n = n->nif.ifpart;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004853 }
4854 p = "; fi";
4855 goto dotail;
4856 case NSUBSHELL:
4857 cmdputs("(");
4858 n = n->nredir.n;
4859 p = ")";
4860 goto dotail;
4861 case NWHILE:
4862 p = "while ";
4863 goto until;
4864 case NUNTIL:
4865 p = "until ";
4866 until:
4867 cmdputs(p);
4868 cmdtxt(n->nbinary.ch1);
4869 n = n->nbinary.ch2;
4870 p = "; done";
4871 dodo:
4872 cmdputs("; do ");
4873 dotail:
4874 cmdtxt(n);
4875 goto dotail2;
4876 case NFOR:
4877 cmdputs("for ");
4878 cmdputs(n->nfor.var);
4879 cmdputs(" in ");
4880 cmdlist(n->nfor.args, 1);
4881 n = n->nfor.body;
4882 p = "; done";
4883 goto dodo;
4884 case NDEFUN:
Denys Vlasenko675d24a2018-01-27 22:02:05 +01004885 cmdputs(n->ndefun.text);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004886 p = "() { ... }";
4887 goto dotail2;
4888 case NCMD:
4889 cmdlist(n->ncmd.args, 1);
4890 cmdlist(n->ncmd.redirect, 0);
4891 break;
4892 case NARG:
4893 p = n->narg.text;
4894 dotail2:
4895 cmdputs(p);
4896 break;
4897 case NHERE:
4898 case NXHERE:
4899 p = "<<...";
4900 goto dotail2;
4901 case NCASE:
4902 cmdputs("case ");
4903 cmdputs(n->ncase.expr->narg.text);
4904 cmdputs(" in ");
4905 for (np = n->ncase.cases; np; np = np->nclist.next) {
4906 cmdtxt(np->nclist.pattern);
4907 cmdputs(") ");
4908 cmdtxt(np->nclist.body);
4909 cmdputs(";; ");
4910 }
4911 p = "esac";
4912 goto dotail2;
4913 case NTO:
4914 p = ">";
4915 goto redir;
4916 case NCLOBBER:
4917 p = ">|";
4918 goto redir;
4919 case NAPPEND:
4920 p = ">>";
4921 goto redir;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01004922#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00004923 case NTO2:
4924#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004925 case NTOFD:
4926 p = ">&";
4927 goto redir;
4928 case NFROM:
4929 p = "<";
4930 goto redir;
4931 case NFROMFD:
4932 p = "<&";
4933 goto redir;
4934 case NFROMTO:
4935 p = "<>";
4936 redir:
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00004937 cmdputs(utoa(n->nfile.fd));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004938 cmdputs(p);
4939 if (n->type == NTOFD || n->type == NFROMFD) {
Denys Vlasenkod0fff912017-07-31 14:32:18 +02004940 if (n->ndup.dupfd >= 0)
4941 cmdputs(utoa(n->ndup.dupfd));
4942 else
4943 cmdputs("-");
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00004944 break;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004945 }
4946 n = n->nfile.fname;
4947 goto donode;
4948 }
4949}
4950
4951static char *
4952commandtext(union node *n)
4953{
4954 char *name;
4955
4956 STARTSTACKSTR(cmdnextc);
4957 cmdtxt(n);
4958 name = stackblock();
Denys Vlasenko6a94cee2016-10-25 17:40:25 +02004959 TRACE(("commandtext: name %p, end %p\n", name, cmdnextc));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004960 return ckstrdup(name);
4961}
4962#endif /* JOBS */
4963
4964/*
4965 * Fork off a subshell. If we are doing job control, give the subshell its
4966 * own process group. Jp is a job structure that the job is to be added to.
4967 * N is the command that will be evaluated by the child. Both jp and n may
4968 * be NULL. The mode parameter can be one of the following:
4969 * FORK_FG - Fork off a foreground process.
4970 * FORK_BG - Fork off a background process.
4971 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
4972 * process group even if job control is on.
4973 *
4974 * When job control is turned off, background processes have their standard
4975 * input redirected to /dev/null (except for the second and later processes
4976 * in a pipeline).
4977 *
4978 * Called with interrupts off.
4979 */
4980/*
4981 * Clear traps on a fork.
4982 */
4983static void
4984clear_traps(void)
4985{
4986 char **tp;
4987
Denys Vlasenkob4f51d32016-10-27 12:55:09 +02004988 INT_OFF;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004989 for (tp = trap; tp < &trap[NSIG]; tp++) {
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004990 if (*tp && **tp) { /* trap not NULL or "" (SIG_IGN) */
Denys Vlasenkoe305c282009-09-25 02:12:27 +02004991 if (trap_ptr == trap)
4992 free(*tp);
4993 /* else: it "belongs" to trap_ptr vector, don't free */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004994 *tp = NULL;
Denys Vlasenko0800e3a2009-09-24 03:09:26 +02004995 if ((tp - trap) != 0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004996 setsignal(tp - trap);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004997 }
4998 }
Alexander Shishkinccb97712010-07-25 13:07:39 +02004999 may_have_traps = 0;
Denys Vlasenkob4f51d32016-10-27 12:55:09 +02005000 INT_ON;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005001}
Denis Vlasenkobdc406d2007-07-15 01:13:25 +00005002
5003/* Lives far away from here, needed for forkchild */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005004static void closescript(void);
Denis Vlasenko41770222007-10-07 18:02:52 +00005005
Denis Vlasenkobdc406d2007-07-15 01:13:25 +00005006/* Called after fork(), in child */
Denys Vlasenko70392332016-10-27 02:31:55 +02005007/* jp and n are NULL when called by openhere() for heredoc support */
Denys Vlasenko21d87d42009-09-25 00:06:51 +02005008static NOINLINE void
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02005009forkchild(struct job *jp, union node *n, int mode)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005010{
5011 int oldlvl;
5012
5013 TRACE(("Child shell %d\n", getpid()));
5014 oldlvl = shlvl;
5015 shlvl++;
5016
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005017 /* man bash: "Non-builtin commands run by bash have signal handlers
5018 * set to the values inherited by the shell from its parent".
5019 * Do we do it correctly? */
5020
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005021 closescript();
Denys Vlasenko844f9902009-09-23 03:25:52 +02005022
5023 if (mode == FORK_NOJOB /* is it `xxx` ? */
5024 && n && n->type == NCMD /* is it single cmd? */
5025 /* && n->ncmd.args->type == NARG - always true? */
Denys Vlasenko74269202010-02-21 01:26:42 +01005026 && n->ncmd.args && strcmp(n->ncmd.args->narg.text, "trap") == 0
Denys Vlasenko844f9902009-09-23 03:25:52 +02005027 && n->ncmd.args->narg.next == NULL /* "trap" with no arguments */
5028 /* && n->ncmd.args->narg.backquote == NULL - do we need to check this? */
5029 ) {
5030 TRACE(("Trap hack\n"));
5031 /* Awful hack for `trap` or $(trap).
5032 *
5033 * http://www.opengroup.org/onlinepubs/009695399/utilities/trap.html
5034 * contains an example where "trap" is executed in a subshell:
5035 *
5036 * save_traps=$(trap)
5037 * ...
5038 * eval "$save_traps"
5039 *
5040 * Standard does not say that "trap" in subshell shall print
5041 * parent shell's traps. It only says that its output
5042 * must have suitable form, but then, in the above example
5043 * (which is not supposed to be normative), it implies that.
5044 *
5045 * bash (and probably other shell) does implement it
5046 * (traps are reset to defaults, but "trap" still shows them),
5047 * but as a result, "trap" logic is hopelessly messed up:
5048 *
5049 * # trap
5050 * trap -- 'echo Ho' SIGWINCH <--- we have a handler
5051 * # (trap) <--- trap is in subshell - no output (correct, traps are reset)
5052 * # true | trap <--- trap is in subshell - no output (ditto)
5053 * # echo `true | trap` <--- in subshell - output (but traps are reset!)
5054 * trap -- 'echo Ho' SIGWINCH
5055 * # echo `(trap)` <--- in subshell in subshell - output
5056 * trap -- 'echo Ho' SIGWINCH
5057 * # echo `true | (trap)` <--- in subshell in subshell in subshell - output!
5058 * trap -- 'echo Ho' SIGWINCH
5059 *
5060 * The rules when to forget and when to not forget traps
5061 * get really complex and nonsensical.
5062 *
5063 * Our solution: ONLY bare $(trap) or `trap` is special.
5064 */
Denys Vlasenko8f88d852009-09-25 12:12:53 +02005065 /* Save trap handler strings for trap builtin to print */
Ron Yorstond840c5d2015-07-19 23:05:20 +02005066 trap_ptr = xmemdup(trap, sizeof(trap));
Denys Vlasenko8f88d852009-09-25 12:12:53 +02005067 /* Fall through into clearing traps */
Denys Vlasenko844f9902009-09-23 03:25:52 +02005068 }
Denys Vlasenkoe305c282009-09-25 02:12:27 +02005069 clear_traps();
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005070#if JOBS
5071 /* do job control only in root shell */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00005072 doing_jobctl = 0;
Denys Vlasenkob12553f2011-02-21 03:22:20 +01005073 if (mode != FORK_NOJOB && jp->jobctl && oldlvl == 0) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005074 pid_t pgrp;
5075
5076 if (jp->nprocs == 0)
5077 pgrp = getpid();
5078 else
Denys Vlasenko285ad152009-12-04 23:02:27 +01005079 pgrp = jp->ps[0].ps_pid;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005080 /* this can fail because we are doing it in the parent also */
5081 setpgid(0, pgrp);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005082 if (mode == FORK_FG)
5083 xtcsetpgrp(ttyfd, pgrp);
5084 setsignal(SIGTSTP);
5085 setsignal(SIGTTOU);
5086 } else
5087#endif
5088 if (mode == FORK_BG) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005089 /* man bash: "When job control is not in effect,
5090 * asynchronous commands ignore SIGINT and SIGQUIT" */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005091 ignoresig(SIGINT);
5092 ignoresig(SIGQUIT);
5093 if (jp->nprocs == 0) {
5094 close(0);
5095 if (open(bb_dev_null, O_RDONLY) != 0)
Denys Vlasenko12ffefb2017-08-23 14:52:56 +02005096 ash_msg_and_raise_perror("can't open '%s'", bb_dev_null);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005097 }
5098 }
Denys Vlasenkob12553f2011-02-21 03:22:20 +01005099 if (oldlvl == 0) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005100 if (iflag) { /* why if iflag only? */
5101 setsignal(SIGINT);
5102 setsignal(SIGTERM);
5103 }
5104 /* man bash:
5105 * "In all cases, bash ignores SIGQUIT. Non-builtin
5106 * commands run by bash have signal handlers
5107 * set to the values inherited by the shell
5108 * from its parent".
5109 * Take care of the second rule: */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005110 setsignal(SIGQUIT);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005111 }
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02005112#if JOBS
Denys Vlasenko844f9902009-09-23 03:25:52 +02005113 if (n && n->type == NCMD
Denys Vlasenko74269202010-02-21 01:26:42 +01005114 && n->ncmd.args && strcmp(n->ncmd.args->narg.text, "jobs") == 0
Denys Vlasenko844f9902009-09-23 03:25:52 +02005115 ) {
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02005116 TRACE(("Job hack\n"));
Denys Vlasenko844f9902009-09-23 03:25:52 +02005117 /* "jobs": we do not want to clear job list for it,
5118 * instead we remove only _its_ own_ job from job list.
5119 * This makes "jobs .... | cat" more useful.
5120 */
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02005121 freejob(curjob);
5122 return;
5123 }
5124#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005125 for (jp = curjob; jp; jp = jp->prev_job)
5126 freejob(jp);
5127 jobless = 0;
5128}
5129
Denis Vlasenkobdc406d2007-07-15 01:13:25 +00005130/* Called after fork(), in parent */
Denis Vlasenko85c24712008-03-17 09:04:04 +00005131#if !JOBS
5132#define forkparent(jp, n, mode, pid) forkparent(jp, mode, pid)
5133#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005134static void
5135forkparent(struct job *jp, union node *n, int mode, pid_t pid)
5136{
5137 TRACE(("In parent shell: child = %d\n", pid));
5138 if (!jp) {
Denys Vlasenko70392332016-10-27 02:31:55 +02005139 /* jp is NULL when called by openhere() for heredoc support */
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00005140 while (jobless && dowait(DOWAIT_NONBLOCK, NULL) > 0)
5141 continue;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005142 jobless++;
5143 return;
5144 }
5145#if JOBS
5146 if (mode != FORK_NOJOB && jp->jobctl) {
5147 int pgrp;
5148
5149 if (jp->nprocs == 0)
5150 pgrp = pid;
5151 else
Denys Vlasenko285ad152009-12-04 23:02:27 +01005152 pgrp = jp->ps[0].ps_pid;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005153 /* This can fail because we are doing it in the child also */
5154 setpgid(pid, pgrp);
5155 }
5156#endif
5157 if (mode == FORK_BG) {
5158 backgndpid = pid; /* set $! */
5159 set_curjob(jp, CUR_RUNNING);
5160 }
5161 if (jp) {
5162 struct procstat *ps = &jp->ps[jp->nprocs++];
Denys Vlasenko285ad152009-12-04 23:02:27 +01005163 ps->ps_pid = pid;
5164 ps->ps_status = -1;
5165 ps->ps_cmd = nullstr;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005166#if JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +00005167 if (doing_jobctl && n)
Denys Vlasenko285ad152009-12-04 23:02:27 +01005168 ps->ps_cmd = commandtext(n);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005169#endif
5170 }
5171}
5172
Denys Vlasenko70392332016-10-27 02:31:55 +02005173/* jp and n are NULL when called by openhere() for heredoc support */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005174static int
5175forkshell(struct job *jp, union node *n, int mode)
5176{
5177 int pid;
5178
5179 TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
5180 pid = fork();
5181 if (pid < 0) {
5182 TRACE(("Fork failed, errno=%d", errno));
5183 if (jp)
5184 freejob(jp);
Denys Vlasenko12ffefb2017-08-23 14:52:56 +02005185 ash_msg_and_raise_perror("can't fork");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005186 }
Denys Vlasenko76ace252009-10-12 15:25:01 +02005187 if (pid == 0) {
5188 CLEAR_RANDOM_T(&random_gen); /* or else $RANDOM repeats in child */
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02005189 forkchild(jp, n, mode);
Denys Vlasenko76ace252009-10-12 15:25:01 +02005190 } else {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005191 forkparent(jp, n, mode, pid);
Denys Vlasenko76ace252009-10-12 15:25:01 +02005192 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005193 return pid;
5194}
5195
5196/*
5197 * Wait for job to finish.
5198 *
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005199 * Under job control we have the problem that while a child process
5200 * is running interrupts generated by the user are sent to the child
5201 * but not to the shell. This means that an infinite loop started by
5202 * an interactive user may be hard to kill. With job control turned off,
5203 * an interactive user may place an interactive program inside a loop.
5204 * If the interactive program catches interrupts, the user doesn't want
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005205 * these interrupts to also abort the loop. The approach we take here
5206 * is to have the shell ignore interrupt signals while waiting for a
5207 * foreground process to terminate, and then send itself an interrupt
5208 * signal if the child process was terminated by an interrupt signal.
5209 * Unfortunately, some programs want to do a bit of cleanup and then
5210 * exit on interrupt; unless these processes terminate themselves by
5211 * sending a signal to themselves (instead of calling exit) they will
5212 * confuse this approach.
5213 *
5214 * Called with interrupts off.
5215 */
5216static int
5217waitforjob(struct job *jp)
5218{
5219 int st;
5220
5221 TRACE(("waitforjob(%%%d) called\n", jobno(jp)));
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005222
5223 INT_OFF;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005224 while (jp->state == JOBRUNNING) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005225 /* In non-interactive shells, we _can_ get
5226 * a keyboard signal here and be EINTRed,
5227 * but we just loop back, waiting for command to complete.
5228 *
5229 * man bash:
5230 * "If bash is waiting for a command to complete and receives
5231 * a signal for which a trap has been set, the trap
5232 * will not be executed until the command completes."
5233 *
5234 * Reality is that even if trap is not set, bash
5235 * will not act on the signal until command completes.
5236 * Try this. sleep5intoff.c:
5237 * #include <signal.h>
5238 * #include <unistd.h>
5239 * int main() {
5240 * sigset_t set;
5241 * sigemptyset(&set);
5242 * sigaddset(&set, SIGINT);
5243 * sigaddset(&set, SIGQUIT);
5244 * sigprocmask(SIG_BLOCK, &set, NULL);
5245 * sleep(5);
5246 * return 0;
5247 * }
5248 * $ bash -c './sleep5intoff; echo hi'
5249 * ^C^C^C^C <--- pressing ^C once a second
5250 * $ _
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005251 * $ bash -c './sleep5intoff; echo hi'
5252 * ^\^\^\^\hi <--- pressing ^\ (SIGQUIT)
5253 * $ _
5254 */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005255 dowait(DOWAIT_BLOCK, jp);
5256 }
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005257 INT_ON;
5258
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005259 st = getstatus(jp);
5260#if JOBS
5261 if (jp->jobctl) {
5262 xtcsetpgrp(ttyfd, rootpid);
Denys Vlasenko098b7132017-01-11 19:59:03 +01005263 restore_tty_if_stopped_or_signaled(jp);
5264
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005265 /*
5266 * This is truly gross.
5267 * If we're doing job control, then we did a TIOCSPGRP which
5268 * caused us (the shell) to no longer be in the controlling
5269 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
5270 * intuit from the subprocess exit status whether a SIGINT
5271 * occurred, and if so interrupt ourselves. Yuck. - mycroft
5272 */
Denis Vlasenko991a1da2008-02-10 19:02:53 +00005273 if (jp->sigint) /* TODO: do the same with all signals */
5274 raise(SIGINT); /* ... by raise(jp->sig) instead? */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005275 }
5276 if (jp->state == JOBDONE)
5277#endif
5278 freejob(jp);
5279 return st;
5280}
5281
5282/*
5283 * return 1 if there are stopped jobs, otherwise 0
5284 */
5285static int
5286stoppedjobs(void)
5287{
5288 struct job *jp;
5289 int retval;
5290
5291 retval = 0;
5292 if (job_warning)
5293 goto out;
5294 jp = curjob;
5295 if (jp && jp->state == JOBSTOPPED) {
5296 out2str("You have stopped jobs.\n");
5297 job_warning = 2;
5298 retval++;
5299 }
5300 out:
5301 return retval;
5302}
5303
5304
Denys Vlasenko70392332016-10-27 02:31:55 +02005305/*
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005306 * Code for dealing with input/output redirection.
5307 */
5308
Denys Vlasenko8d0e0cd2011-01-25 23:21:46 +01005309#undef EMPTY
5310#undef CLOSED
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005311#define EMPTY -2 /* marks an unused slot in redirtab */
Denys Vlasenko035486c2017-07-31 04:09:19 +02005312#define CLOSED -1 /* marks a slot of previously-closed fd */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005313
5314/*
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005315 * Handle here documents. Normally we fork off a process to write the
5316 * data to a pipe. If the document is short, we can stuff the data in
5317 * the pipe without forking.
5318 */
5319/* openhere needs this forward reference */
5320static void expandhere(union node *arg, int fd);
5321static int
5322openhere(union node *redir)
5323{
5324 int pip[2];
5325 size_t len = 0;
5326
5327 if (pipe(pip) < 0)
Denys Vlasenko12ffefb2017-08-23 14:52:56 +02005328 ash_msg_and_raise_perror("can't create pipe");
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005329 if (redir->type == NHERE) {
5330 len = strlen(redir->nhere.doc->narg.text);
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005331 if (len <= PIPE_BUF) {
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005332 full_write(pip[1], redir->nhere.doc->narg.text, len);
5333 goto out;
5334 }
5335 }
5336 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
Denis Vlasenko0b769642008-07-24 07:54:57 +00005337 /* child */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005338 close(pip[0]);
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005339 ignoresig(SIGINT); //signal(SIGINT, SIG_IGN);
5340 ignoresig(SIGQUIT); //signal(SIGQUIT, SIG_IGN);
5341 ignoresig(SIGHUP); //signal(SIGHUP, SIG_IGN);
5342 ignoresig(SIGTSTP); //signal(SIGTSTP, SIG_IGN);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005343 signal(SIGPIPE, SIG_DFL);
5344 if (redir->type == NHERE)
5345 full_write(pip[1], redir->nhere.doc->narg.text, len);
Denis Vlasenko0b769642008-07-24 07:54:57 +00005346 else /* NXHERE */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005347 expandhere(redir->nhere.doc, pip[1]);
Bernhard Reutner-Fischer636a1f82008-05-19 09:29:47 +00005348 _exit(EXIT_SUCCESS);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005349 }
5350 out:
5351 close(pip[1]);
5352 return pip[0];
5353}
5354
5355static int
5356openredirect(union node *redir)
5357{
Denys Vlasenkof1a5cb02017-07-25 17:47:48 +02005358 struct stat sb;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005359 char *fname;
5360 int f;
5361
5362 switch (redir->nfile.type) {
Denys Vlasenko557482c2016-09-25 21:24:04 +02005363/* Can't happen, our single caller does this itself */
5364// case NTOFD:
5365// case NFROMFD:
5366// return -1;
5367 case NHERE:
5368 case NXHERE:
5369 return openhere(redir);
5370 }
5371
5372 /* For N[X]HERE, reading redir->nfile.expfname would touch beyond
5373 * allocated space. Do it only when we know it is safe.
5374 */
5375 fname = redir->nfile.expfname;
5376
5377 switch (redir->nfile.type) {
5378 default:
5379#if DEBUG
5380 abort();
5381#endif
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005382 case NFROM:
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005383 f = open(fname, O_RDONLY);
5384 if (f < 0)
5385 goto eopen;
5386 break;
5387 case NFROMTO:
Andreas Bühmannda75f442010-06-24 04:32:37 +02005388 f = open(fname, O_RDWR|O_CREAT, 0666);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005389 if (f < 0)
5390 goto ecreate;
5391 break;
5392 case NTO:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01005393#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00005394 case NTO2:
5395#endif
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005396 /* Take care of noclobber mode. */
5397 if (Cflag) {
Denys Vlasenkof1a5cb02017-07-25 17:47:48 +02005398 if (stat(fname, &sb) < 0) {
5399 f = open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
5400 if (f < 0)
5401 goto ecreate;
5402 } else if (!S_ISREG(sb.st_mode)) {
5403 f = open(fname, O_WRONLY, 0666);
5404 if (f < 0)
5405 goto ecreate;
Denys Vlasenko355ec352018-04-02 13:34:57 +02005406 if (!fstat(f, &sb) && S_ISREG(sb.st_mode)) {
Denys Vlasenkof1a5cb02017-07-25 17:47:48 +02005407 close(f);
5408 errno = EEXIST;
5409 goto ecreate;
5410 }
5411 } else {
5412 errno = EEXIST;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005413 goto ecreate;
Denys Vlasenkof1a5cb02017-07-25 17:47:48 +02005414 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005415 break;
5416 }
5417 /* FALLTHROUGH */
5418 case NCLOBBER:
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005419 f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666);
5420 if (f < 0)
5421 goto ecreate;
5422 break;
5423 case NAPPEND:
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005424 f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666);
5425 if (f < 0)
5426 goto ecreate;
5427 break;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005428 }
5429
5430 return f;
5431 ecreate:
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +00005432 ash_msg_and_raise_error("can't create %s: %s", fname, errmsg(errno, "nonexistent directory"));
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005433 eopen:
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +00005434 ash_msg_and_raise_error("can't open %s: %s", fname, errmsg(errno, "no such file"));
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005435}
5436
5437/*
Denys Vlasenko64774602016-10-26 15:24:30 +02005438 * Copy a file descriptor to be >= 10. Throws exception on error.
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005439 */
5440static int
Denys Vlasenko64774602016-10-26 15:24:30 +02005441savefd(int from)
5442{
5443 int newfd;
5444 int err;
5445
Denys Vlasenko60fb98e2018-03-30 22:15:14 +02005446 newfd = fcntl(from, F_DUPFD_CLOEXEC, 10);
Denys Vlasenko64774602016-10-26 15:24:30 +02005447 err = newfd < 0 ? errno : 0;
5448 if (err != EBADF) {
5449 if (err)
Ron Yorstonbe366e52017-07-27 13:53:39 +01005450 ash_msg_and_raise_perror("%d", from);
Denys Vlasenko64774602016-10-26 15:24:30 +02005451 close(from);
Denys Vlasenko60fb98e2018-03-30 22:15:14 +02005452 if (F_DUPFD_CLOEXEC == F_DUPFD)
5453 close_on_exec_on(newfd);
Denys Vlasenko64774602016-10-26 15:24:30 +02005454 }
5455
5456 return newfd;
5457}
5458static int
5459dup2_or_raise(int from, int to)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005460{
5461 int newfd;
5462
Denys Vlasenko64774602016-10-26 15:24:30 +02005463 newfd = (from != to) ? dup2(from, to) : to;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005464 if (newfd < 0) {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005465 /* Happens when source fd is not open: try "echo >&99" */
Ron Yorstonbe366e52017-07-27 13:53:39 +01005466 ash_msg_and_raise_perror("%d", from);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005467 }
5468 return newfd;
5469}
Denys Vlasenko035486c2017-07-31 04:09:19 +02005470static int
Denys Vlasenko9acd63c2018-03-28 18:35:07 +02005471dup_CLOEXEC(int fd, int avoid_fd)
Denys Vlasenko035486c2017-07-31 04:09:19 +02005472{
5473 int newfd;
5474 repeat:
Denys Vlasenko9acd63c2018-03-28 18:35:07 +02005475 newfd = fcntl(fd, F_DUPFD_CLOEXEC, avoid_fd + 1);
5476 if (newfd >= 0) {
5477 if (F_DUPFD_CLOEXEC == F_DUPFD) /* if old libc (w/o F_DUPFD_CLOEXEC) */
Denys Vlasenko60fb98e2018-03-30 22:15:14 +02005478 close_on_exec_on(newfd);
Denys Vlasenko9acd63c2018-03-28 18:35:07 +02005479 } else { /* newfd < 0 */
Denys Vlasenko035486c2017-07-31 04:09:19 +02005480 if (errno == EBUSY)
5481 goto repeat;
5482 if (errno == EINTR)
5483 goto repeat;
5484 }
5485 return newfd;
5486}
5487static int
5488xdup_CLOEXEC_and_close(int fd, int avoid_fd)
5489{
5490 int newfd;
5491 repeat:
Denys Vlasenko60fb98e2018-03-30 22:15:14 +02005492 newfd = fcntl(fd, F_DUPFD_CLOEXEC, avoid_fd + 1);
Denys Vlasenko035486c2017-07-31 04:09:19 +02005493 if (newfd < 0) {
5494 if (errno == EBUSY)
5495 goto repeat;
5496 if (errno == EINTR)
5497 goto repeat;
5498 /* fd was not open? */
5499 if (errno == EBADF)
5500 return fd;
5501 ash_msg_and_raise_perror("%d", newfd);
5502 }
Denys Vlasenko60fb98e2018-03-30 22:15:14 +02005503 if (F_DUPFD_CLOEXEC == F_DUPFD)
5504 close_on_exec_on(newfd);
Denys Vlasenko035486c2017-07-31 04:09:19 +02005505 close(fd);
5506 return newfd;
5507}
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005508
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005509/* Struct def and variable are moved down to the first usage site */
Denys Vlasenko035486c2017-07-31 04:09:19 +02005510struct squirrel {
5511 int orig_fd;
5512 int moved_to;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005513};
Denis Vlasenko0b769642008-07-24 07:54:57 +00005514struct redirtab {
5515 struct redirtab *next;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005516 int pair_count;
Denys Vlasenko035486c2017-07-31 04:09:19 +02005517 struct squirrel two_fd[];
Denis Vlasenko0b769642008-07-24 07:54:57 +00005518};
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005519#define redirlist (G_var.redirlist)
Denis Vlasenko0b769642008-07-24 07:54:57 +00005520
Denys Vlasenko035486c2017-07-31 04:09:19 +02005521static void
5522add_squirrel_closed(struct redirtab *sq, int fd)
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005523{
5524 int i;
5525
Denys Vlasenko035486c2017-07-31 04:09:19 +02005526 if (!sq)
5527 return;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005528
Denys Vlasenko035486c2017-07-31 04:09:19 +02005529 for (i = 0; sq->two_fd[i].orig_fd != EMPTY; i++) {
5530 /* If we collide with an already moved fd... */
5531 if (fd == sq->two_fd[i].orig_fd) {
5532 /* Examples:
5533 * "echo 3>FILE 3>&- 3>FILE"
5534 * "echo 3>&- 3>FILE"
5535 * No need for last redirect to insert
5536 * another "need to close 3" indicator.
5537 */
5538 TRACE(("redirect_fd %d: already moved or closed\n", fd));
5539 return;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005540 }
5541 }
Denys Vlasenko035486c2017-07-31 04:09:19 +02005542 TRACE(("redirect_fd %d: previous fd was closed\n", fd));
5543 sq->two_fd[i].orig_fd = fd;
5544 sq->two_fd[i].moved_to = CLOSED;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005545}
5546
Denys Vlasenko37dc08b2016-10-02 04:38:07 +02005547static int
Denys Vlasenko035486c2017-07-31 04:09:19 +02005548save_fd_on_redirect(int fd, int avoid_fd, struct redirtab *sq)
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005549{
Denys Vlasenko035486c2017-07-31 04:09:19 +02005550 int i, new_fd;
Denis Vlasenko34c73c42008-08-16 11:48:02 +00005551
Denys Vlasenko035486c2017-07-31 04:09:19 +02005552 if (avoid_fd < 9) /* the important case here is that it can be -1 */
5553 avoid_fd = 9;
5554
5555#if JOBS
5556 if (fd == ttyfd) {
5557 /* Testcase: "ls -l /proc/$$/fd 10>&-" should work */
5558 ttyfd = xdup_CLOEXEC_and_close(ttyfd, avoid_fd);
5559 TRACE(("redirect_fd %d: matches ttyfd, moving it to %d\n", fd, ttyfd));
5560 return 1; /* "we closed fd" */
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005561 }
Denys Vlasenko035486c2017-07-31 04:09:19 +02005562#endif
5563 /* Are we called from redirect(0)? E.g. redirect
5564 * in a forked child. No need to save fds,
5565 * we aren't going to use them anymore, ok to trash.
5566 */
5567 if (!sq)
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005568 return 0;
Denys Vlasenko035486c2017-07-31 04:09:19 +02005569
5570 /* If this one of script's fds? */
5571 if (fd != 0) {
5572 struct parsefile *pf = g_parsefile;
5573 while (pf) {
5574 /* We skip fd == 0 case because of the following:
5575 * $ ash # running ash interactively
5576 * $ . ./script.sh
5577 * and in script.sh: "exec 9>&0".
5578 * Even though top-level pf_fd _is_ 0,
5579 * it's still ok to use it: "read" builtin uses it,
5580 * why should we cripple "exec" builtin?
5581 */
5582 if (fd == pf->pf_fd) {
5583 pf->pf_fd = xdup_CLOEXEC_and_close(fd, avoid_fd);
5584 return 1; /* "we closed fd" */
5585 }
5586 pf = pf->prev;
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005587 }
5588 }
Denys Vlasenko035486c2017-07-31 04:09:19 +02005589
5590 /* Check whether it collides with any open fds (e.g. stdio), save fds as needed */
5591
5592 /* First: do we collide with some already moved fds? */
5593 for (i = 0; sq->two_fd[i].orig_fd != EMPTY; i++) {
5594 /* If we collide with an already moved fd... */
5595 if (fd == sq->two_fd[i].moved_to) {
Denys Vlasenko9acd63c2018-03-28 18:35:07 +02005596 new_fd = dup_CLOEXEC(fd, avoid_fd);
Denys Vlasenko035486c2017-07-31 04:09:19 +02005597 sq->two_fd[i].moved_to = new_fd;
5598 TRACE(("redirect_fd %d: already busy, moving to %d\n", fd, new_fd));
5599 if (new_fd < 0) /* what? */
5600 xfunc_die();
5601 return 0; /* "we did not close fd" */
5602 }
5603 if (fd == sq->two_fd[i].orig_fd) {
5604 /* Example: echo Hello >/dev/null 1>&2 */
5605 TRACE(("redirect_fd %d: already moved\n", fd));
5606 return 0; /* "we did not close fd" */
5607 }
5608 }
5609
5610 /* 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 +02005611 new_fd = dup_CLOEXEC(fd, avoid_fd);
Denys Vlasenko035486c2017-07-31 04:09:19 +02005612 TRACE(("redirect_fd %d: previous fd is moved to %d (-1 if it was closed)\n", fd, new_fd));
5613 if (new_fd < 0) {
5614 if (errno != EBADF)
5615 xfunc_die();
5616 /* new_fd = CLOSED; - already is -1 */
5617 }
5618 sq->two_fd[i].moved_to = new_fd;
5619 sq->two_fd[i].orig_fd = fd;
5620
5621 /* if we move stderr, let "set -x" code know */
5622 if (fd == preverrout_fd)
5623 preverrout_fd = new_fd;
5624
5625 return 0; /* "we did not close fd" */
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005626}
5627
Denys Vlasenko32fdf2f2017-07-31 04:32:06 +02005628static int
5629internally_opened_fd(int fd, struct redirtab *sq)
5630{
5631 int i;
5632#if JOBS
5633 if (fd == ttyfd)
5634 return 1;
5635#endif
5636 /* If this one of script's fds? */
5637 if (fd != 0) {
5638 struct parsefile *pf = g_parsefile;
5639 while (pf) {
5640 if (fd == pf->pf_fd)
5641 return 1;
5642 pf = pf->prev;
5643 }
5644 }
5645
5646 if (sq) for (i = 0; i < sq->pair_count && sq->two_fd[i].orig_fd != EMPTY; i++) {
5647 if (fd == sq->two_fd[i].moved_to)
5648 return 1;
5649 }
5650 return 0;
5651}
5652
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005653/*
5654 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
5655 * old file descriptors are stashed away so that the redirection can be
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005656 * undone by calling popredir.
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005657 */
5658/* flags passed to redirect */
5659#define REDIR_PUSH 01 /* save previous values of file descriptors */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005660static void
5661redirect(union node *redir, int flags)
5662{
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005663 struct redirtab *sv;
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005664
Denys Vlasenko1c79aeb2017-07-29 22:51:52 +02005665 if (!redir)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005666 return;
Denys Vlasenko035486c2017-07-31 04:09:19 +02005667
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005668 sv = NULL;
5669 INT_OFF;
Denys Vlasenko1c79aeb2017-07-29 22:51:52 +02005670 if (flags & REDIR_PUSH)
5671 sv = redirlist;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005672 do {
Denys Vlasenko035486c2017-07-31 04:09:19 +02005673 int fd;
5674 int newfd;
5675 int close_fd;
5676 int closed;
5677
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00005678 fd = redir->nfile.fd;
Denis Vlasenko0b769642008-07-24 07:54:57 +00005679 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
Denys Vlasenko035486c2017-07-31 04:09:19 +02005680 //bb_error_msg("doing %d > %d", fd, newfd);
5681 newfd = redir->ndup.dupfd;
5682 close_fd = -1;
Denis Vlasenko0b769642008-07-24 07:54:57 +00005683 } else {
5684 newfd = openredirect(redir); /* always >= 0 */
5685 if (fd == newfd) {
Denys Vlasenko035486c2017-07-31 04:09:19 +02005686 /* open() gave us precisely the fd we wanted.
5687 * This means that this fd was not busy
5688 * (not opened to anywhere).
5689 * Remember to close it on restore:
5690 */
5691 add_squirrel_closed(sv, fd);
Denis Vlasenko0b769642008-07-24 07:54:57 +00005692 continue;
5693 }
Denys Vlasenko035486c2017-07-31 04:09:19 +02005694 close_fd = newfd;
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005695 }
Denys Vlasenko035486c2017-07-31 04:09:19 +02005696
5697 if (fd == newfd)
5698 continue;
5699
5700 /* if "N>FILE": move newfd to fd */
5701 /* if "N>&M": dup newfd to fd */
5702 /* if "N>&-": close fd (newfd is -1) */
5703
5704 IF_BASH_REDIR_OUTPUT(redirect_more:)
5705
5706 closed = save_fd_on_redirect(fd, /*avoid:*/ newfd, sv);
5707 if (newfd == -1) {
5708 /* "N>&-" means "close me" */
5709 if (!closed) {
5710 /* ^^^ optimization: saving may already
5711 * have closed it. If not... */
5712 close(fd);
Denis Vlasenko22f74142008-07-24 22:34:43 +00005713 }
Denys Vlasenko035486c2017-07-31 04:09:19 +02005714 } else {
Denys Vlasenko32fdf2f2017-07-31 04:32:06 +02005715 /* if newfd is a script fd or saved fd, simulate EBADF */
5716 if (internally_opened_fd(newfd, sv)) {
5717 errno = EBADF;
5718 ash_msg_and_raise_perror("%d", newfd);
5719 }
Denys Vlasenko64774602016-10-26 15:24:30 +02005720 dup2_or_raise(newfd, fd);
Denys Vlasenko035486c2017-07-31 04:09:19 +02005721 if (close_fd >= 0) /* "N>FILE" or ">&FILE" or heredoc? */
5722 close(close_fd);
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01005723#if BASH_REDIR_OUTPUT
Denys Vlasenko035486c2017-07-31 04:09:19 +02005724 if (redir->nfile.type == NTO2 && fd == 1) {
5725 /* ">&FILE". we already redirected to 1, now copy 1 to 2 */
5726 fd = 2;
5727 newfd = 1;
5728 close_fd = -1;
5729 goto redirect_more;
5730 }
Denis Vlasenko559691a2008-10-05 18:39:31 +00005731#endif
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005732 }
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00005733 } while ((redir = redir->nfile.next) != NULL);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005734 INT_ON;
Denys Vlasenkod07a15b2017-07-30 16:51:05 +02005735
5736//dash:#define REDIR_SAVEFD2 03 /* set preverrout */
5737#define REDIR_SAVEFD2 0
5738 // dash has a bug: since REDIR_SAVEFD2=3 and REDIR_PUSH=1, this test
5739 // triggers for pure REDIR_PUSH too. Thus, this is done almost always,
5740 // not only for calls with flags containing REDIR_SAVEFD2.
Denys Vlasenko035486c2017-07-31 04:09:19 +02005741 // We do this unconditionally (see save_fd_on_redirect()).
Denys Vlasenkod07a15b2017-07-30 16:51:05 +02005742 //if ((flags & REDIR_SAVEFD2) && copied_fd2 >= 0)
5743 // preverrout_fd = copied_fd2;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005744}
5745
Denys Vlasenko170f93e2017-07-29 18:54:53 +02005746static int
5747redirectsafe(union node *redir, int flags)
5748{
5749 int err;
5750 volatile int saveint;
5751 struct jmploc *volatile savehandler = exception_handler;
5752 struct jmploc jmploc;
5753
5754 SAVE_INT(saveint);
5755 /* "echo 9>/dev/null; echo >&9; echo result: $?" - result should be 1, not 2! */
Denys Vlasenko035486c2017-07-31 04:09:19 +02005756 err = setjmp(jmploc.loc); /* was = setjmp(jmploc.loc) * 2; */
Denys Vlasenko170f93e2017-07-29 18:54:53 +02005757 if (!err) {
5758 exception_handler = &jmploc;
5759 redirect(redir, flags);
5760 }
5761 exception_handler = savehandler;
5762 if (err && exception_type != EXERROR)
5763 longjmp(exception_handler->loc, 1);
5764 RESTORE_INT(saveint);
5765 return err;
5766}
5767
Denys Vlasenko1c79aeb2017-07-29 22:51:52 +02005768static struct redirtab*
5769pushredir(union node *redir)
5770{
5771 struct redirtab *sv;
5772 int i;
5773
5774 if (!redir)
5775 return redirlist;
5776
5777 i = 0;
5778 do {
5779 i++;
5780#if BASH_REDIR_OUTPUT
5781 if (redir->nfile.type == NTO2)
5782 i++;
5783#endif
5784 redir = redir->nfile.next;
5785 } while (redir);
5786
5787 sv = ckzalloc(sizeof(*sv) + i * sizeof(sv->two_fd[0]));
5788 sv->pair_count = i;
5789 while (--i >= 0)
Denys Vlasenko035486c2017-07-31 04:09:19 +02005790 sv->two_fd[i].orig_fd = sv->two_fd[i].moved_to = EMPTY;
Denys Vlasenko1c79aeb2017-07-29 22:51:52 +02005791 sv->next = redirlist;
5792 redirlist = sv;
5793 return sv->next;
5794}
5795
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005796/*
5797 * Undo the effects of the last redirection.
5798 */
5799static void
Denys Vlasenko035486c2017-07-31 04:09:19 +02005800popredir(int drop)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005801{
5802 struct redirtab *rp;
5803 int i;
5804
Denys Vlasenkoeaf94362016-10-25 21:46:03 +02005805 if (redirlist == NULL)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005806 return;
5807 INT_OFF;
5808 rp = redirlist;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005809 for (i = 0; i < rp->pair_count; i++) {
Denys Vlasenko035486c2017-07-31 04:09:19 +02005810 int fd = rp->two_fd[i].orig_fd;
5811 int copy = rp->two_fd[i].moved_to;
Denis Vlasenko22f74142008-07-24 22:34:43 +00005812 if (copy == CLOSED) {
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005813 if (!drop)
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005814 close(fd);
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005815 continue;
5816 }
Denis Vlasenko22f74142008-07-24 22:34:43 +00005817 if (copy != EMPTY) {
Denys Vlasenko035486c2017-07-31 04:09:19 +02005818 if (!drop) {
Denis Vlasenko5a867312008-07-24 19:46:38 +00005819 /*close(fd);*/
Denys Vlasenko64774602016-10-26 15:24:30 +02005820 dup2_or_raise(copy, fd);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005821 }
Denys Vlasenko035486c2017-07-31 04:09:19 +02005822 close(copy);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005823 }
5824 }
5825 redirlist = rp->next;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005826 free(rp);
5827 INT_ON;
5828}
5829
Denys Vlasenko1c79aeb2017-07-29 22:51:52 +02005830static void
5831unwindredir(struct redirtab *stop)
5832{
5833 while (redirlist != stop)
Denys Vlasenko035486c2017-07-31 04:09:19 +02005834 popredir(/*drop:*/ 0);
Denys Vlasenko1c79aeb2017-07-29 22:51:52 +02005835}
5836
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005837
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005838/* ============ Routines to expand arguments to commands
5839 *
5840 * We have to deal with backquotes, shell variables, and file metacharacters.
5841 */
5842
Denys Vlasenko0b883582016-12-23 16:49:07 +01005843#if ENABLE_FEATURE_SH_MATH
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005844static arith_t
5845ash_arith(const char *s)
5846{
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005847 arith_state_t math_state;
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005848 arith_t result;
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005849
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005850 math_state.lookupvar = lookupvar;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02005851 math_state.setvar = setvar0;
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005852 //math_state.endofname = endofname;
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005853
5854 INT_OFF;
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005855 result = arith(&math_state, s);
Denys Vlasenko063847d2010-09-15 13:33:02 +02005856 if (math_state.errmsg)
5857 ash_msg_and_raise_error(math_state.errmsg);
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005858 INT_ON;
5859
5860 return result;
5861}
Denis Vlasenko448d30e2008-06-27 00:24:11 +00005862#endif
Denys Vlasenkobaa41c72018-01-10 13:22:25 +01005863#if BASH_SUBSTR
5864# if ENABLE_FEATURE_SH_MATH
5865static int substr_atoi(const char *s)
5866{
5867 arith_t t = ash_arith(s);
5868 if (sizeof(t) > sizeof(int)) {
5869 /* clamp very large or very large negative nums for ${v:N:M}:
5870 * else "${v:0:0x100000001}" would work as "${v:0:1}"
5871 */
5872 if (t > INT_MAX)
5873 t = INT_MAX;
5874 if (t < INT_MIN)
5875 t = INT_MIN;
5876 }
5877 return t;
5878}
5879# else
5880# define substr_atoi(s) number(s)
5881# endif
5882#endif
Denis Vlasenko448d30e2008-06-27 00:24:11 +00005883
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005884/*
5885 * expandarg flags
5886 */
5887#define EXP_FULL 0x1 /* perform word splitting & file globbing */
5888#define EXP_TILDE 0x2 /* do normal tilde expansion */
5889#define EXP_VARTILDE 0x4 /* expand tildes in an assignment */
5890#define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */
Denys Vlasenkodb74c6c2016-10-24 21:12:33 +02005891/* ^^^^^^^^^^^^^^ this is meant to support constructs such as "cmd >file*.txt"
5892 * POSIX says for this case:
5893 * Pathname expansion shall not be performed on the word by a
5894 * non-interactive shell; an interactive shell may perform it, but shall
5895 * do so only when the expansion would result in one word.
5896 * Currently, our code complies to the above rule by never globbing
5897 * redirection filenames.
5898 * Bash performs globbing, unless it is non-interactive and in POSIX mode.
5899 * (this means that on a typical Linux distro, bash almost always
5900 * performs globbing, and thus diverges from what we do).
5901 */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005902#define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */
Denys Vlasenko216913c2018-04-02 12:35:04 +02005903#define EXP_VARTILDE2 0x20 /* expand tildes after colons only */
5904#define EXP_WORD 0x40 /* expand word in parameter expansion */
5905#define EXP_QUOTED 0x80 /* expand word in double quotes */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005906/*
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005907 * rmescape() flags
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005908 */
5909#define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
5910#define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005911#define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */
5912#define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */
5913
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005914/* Add CTLESC when necessary. */
Denys Vlasenko216913c2018-04-02 12:35:04 +02005915#define QUOTES_ESC (EXP_FULL | EXP_CASE)
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005916/* Do not skip NUL characters. */
5917#define QUOTES_KEEPNUL EXP_TILDE
5918
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005919/*
5920 * Structure specifying which parts of the string should be searched
5921 * for IFS characters.
5922 */
5923struct ifsregion {
5924 struct ifsregion *next; /* next region in list */
5925 int begoff; /* offset of start of region */
5926 int endoff; /* offset of end of region */
5927 int nulonly; /* search for nul bytes only */
5928};
5929
5930struct arglist {
5931 struct strlist *list;
5932 struct strlist **lastp;
5933};
5934
5935/* output of current string */
5936static char *expdest;
5937/* list of back quote expressions */
5938static struct nodelist *argbackq;
5939/* first struct in list of ifs regions */
5940static struct ifsregion ifsfirst;
5941/* last struct in list */
5942static struct ifsregion *ifslastp;
5943/* holds expanded arg list */
5944static struct arglist exparg;
5945
5946/*
5947 * Our own itoa().
Denys Vlasenkocf3a7962017-07-26 14:38:19 +02005948 * cvtnum() is used even if math support is off (to prepare $? values and such).
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005949 */
5950static int
5951cvtnum(arith_t num)
5952{
5953 int len;
5954
Denys Vlasenkocf3a7962017-07-26 14:38:19 +02005955 /* 32-bit and wider ints require buffer size of bytes*3 (or less) */
5956 len = sizeof(arith_t) * 3;
5957 /* If narrower: worst case, 1-byte ints: need 5 bytes: "-127<NUL>" */
5958 if (sizeof(arith_t) < 4) len += 2;
5959
5960 expdest = makestrspace(len, expdest);
5961 len = fmtstr(expdest, len, ARITH_FMT, num);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005962 STADJUST(len, expdest);
5963 return len;
5964}
5965
Denys Vlasenko455e4222016-10-27 14:45:13 +02005966/*
5967 * Break the argument string into pieces based upon IFS and add the
5968 * strings to the argument list. The regions of the string to be
5969 * searched for IFS characters have been stored by recordregion.
5970 */
5971static void
5972ifsbreakup(char *string, struct arglist *arglist)
5973{
5974 struct ifsregion *ifsp;
5975 struct strlist *sp;
5976 char *start;
5977 char *p;
5978 char *q;
5979 const char *ifs, *realifs;
5980 int ifsspc;
5981 int nulonly;
5982
5983 start = string;
5984 if (ifslastp != NULL) {
5985 ifsspc = 0;
5986 nulonly = 0;
5987 realifs = ifsset() ? ifsval() : defifs;
5988 ifsp = &ifsfirst;
5989 do {
Denys Vlasenko9a95df92018-04-02 14:27:50 +02005990 int afternul;
5991
Denys Vlasenko455e4222016-10-27 14:45:13 +02005992 p = string + ifsp->begoff;
Denys Vlasenko9a95df92018-04-02 14:27:50 +02005993 afternul = nulonly;
Denys Vlasenko455e4222016-10-27 14:45:13 +02005994 nulonly = ifsp->nulonly;
5995 ifs = nulonly ? nullstr : realifs;
5996 ifsspc = 0;
5997 while (p < string + ifsp->endoff) {
5998 q = p;
5999 if ((unsigned char)*p == CTLESC)
6000 p++;
6001 if (!strchr(ifs, *p)) {
6002 p++;
6003 continue;
6004 }
Denys Vlasenko9a95df92018-04-02 14:27:50 +02006005 if (!(afternul || nulonly))
Denys Vlasenko455e4222016-10-27 14:45:13 +02006006 ifsspc = (strchr(defifs, *p) != NULL);
6007 /* Ignore IFS whitespace at start */
6008 if (q == start && ifsspc) {
6009 p++;
6010 start = p;
6011 continue;
6012 }
6013 *q = '\0';
6014 sp = stzalloc(sizeof(*sp));
6015 sp->text = start;
6016 *arglist->lastp = sp;
6017 arglist->lastp = &sp->next;
6018 p++;
6019 if (!nulonly) {
6020 for (;;) {
6021 if (p >= string + ifsp->endoff) {
6022 break;
6023 }
6024 q = p;
6025 if ((unsigned char)*p == CTLESC)
6026 p++;
6027 if (strchr(ifs, *p) == NULL) {
6028 p = q;
6029 break;
6030 }
6031 if (strchr(defifs, *p) == NULL) {
6032 if (ifsspc) {
6033 p++;
6034 ifsspc = 0;
6035 } else {
6036 p = q;
6037 break;
6038 }
6039 } else
6040 p++;
6041 }
6042 }
6043 start = p;
6044 } /* while */
6045 ifsp = ifsp->next;
6046 } while (ifsp != NULL);
6047 if (nulonly)
6048 goto add;
6049 }
6050
6051 if (!*start)
6052 return;
6053
6054 add:
6055 sp = stzalloc(sizeof(*sp));
6056 sp->text = start;
6057 *arglist->lastp = sp;
6058 arglist->lastp = &sp->next;
6059}
6060
6061static void
6062ifsfree(void)
6063{
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02006064 struct ifsregion *p = ifsfirst.next;
6065
6066 if (!p)
6067 goto out;
Denys Vlasenko455e4222016-10-27 14:45:13 +02006068
6069 INT_OFF;
Denys Vlasenko455e4222016-10-27 14:45:13 +02006070 do {
6071 struct ifsregion *ifsp;
6072 ifsp = p->next;
6073 free(p);
6074 p = ifsp;
6075 } while (p);
Denys Vlasenko455e4222016-10-27 14:45:13 +02006076 ifsfirst.next = NULL;
6077 INT_ON;
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02006078 out:
6079 ifslastp = NULL;
Denys Vlasenko455e4222016-10-27 14:45:13 +02006080}
6081
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006082static size_t
6083esclen(const char *start, const char *p)
6084{
6085 size_t esc = 0;
6086
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006087 while (p > start && (unsigned char)*--p == CTLESC) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006088 esc++;
6089 }
6090 return esc;
6091}
6092
6093/*
6094 * Remove any CTLESC characters from a string.
6095 */
Denys Vlasenko740058b2018-01-09 17:01:00 +01006096#if !BASH_PATTERN_SUBST
6097#define rmescapes(str, flag, slash_position) \
6098 rmescapes(str, flag)
6099#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006100static char *
Denys Vlasenko740058b2018-01-09 17:01:00 +01006101rmescapes(char *str, int flag, int *slash_position)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006102{
Ron Yorston417622c2015-05-18 09:59:14 +02006103 static const char qchars[] ALIGN1 = {
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006104 IF_BASH_PATTERN_SUBST('/',) CTLESC, CTLQUOTEMARK, '\0' };
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00006105
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006106 char *p, *q, *r;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006107 unsigned protect_against_glob;
6108 unsigned globbing;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006109
Denys Vlasenko740058b2018-01-09 17:01:00 +01006110 p = strpbrk(str, qchars IF_BASH_PATTERN_SUBST(+ !slash_position));
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006111 if (!p)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006112 return str;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006113
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006114 q = p;
6115 r = str;
6116 if (flag & RMESCAPE_ALLOC) {
6117 size_t len = p - str;
6118 size_t fulllen = len + strlen(p) + 1;
6119
6120 if (flag & RMESCAPE_GROW) {
Colin Watson3963d942010-04-26 14:21:27 +02006121 int strloc = str - (char *)stackblock();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006122 r = makestrspace(fulllen, expdest);
Colin Watson3963d942010-04-26 14:21:27 +02006123 /* p and str may be invalidated by makestrspace */
6124 str = (char *)stackblock() + strloc;
6125 p = str + len;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006126 } else if (flag & RMESCAPE_HEAP) {
6127 r = ckmalloc(fulllen);
6128 } else {
6129 r = stalloc(fulllen);
6130 }
6131 q = r;
6132 if (len > 0) {
Denys Vlasenko5ace96a2017-07-23 21:46:02 +02006133 q = (char *)mempcpy(q, str, len);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006134 }
6135 }
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006136
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006137 globbing = flag & RMESCAPE_GLOB;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006138 protect_against_glob = globbing;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006139 while (*p) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006140 if ((unsigned char)*p == CTLQUOTEMARK) {
Denys Vlasenko216913c2018-04-02 12:35:04 +02006141// Note: protect_against_glob only affect whether
Denys Vlasenkofda9faf2017-07-05 19:10:21 +02006142// CTLESC,<ch> gets converted to <ch> or to \<ch>
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006143 p++;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006144 protect_against_glob = globbing;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006145 continue;
6146 }
Denys Vlasenko216913c2018-04-02 12:35:04 +02006147 if (*p == '\\') {
6148 /* naked back slash */
6149 protect_against_glob = 0;
6150 goto copy;
6151 }
Ron Yorston549deab2015-05-18 09:57:51 +02006152 if ((unsigned char)*p == CTLESC) {
6153 p++;
Denys Vlasenko13f20912016-09-25 20:54:25 +02006154#if DEBUG
6155 if (*p == '\0')
6156 ash_msg_and_raise_error("CTLESC at EOL (shouldn't happen)");
6157#endif
Ron Yorston549deab2015-05-18 09:57:51 +02006158 if (protect_against_glob) {
Denys Vlasenkofda9faf2017-07-05 19:10:21 +02006159 /*
6160 * We used to trust glob() and fnmatch() to eat
6161 * superfluous escapes (\z where z has no
6162 * special meaning anyway). But this causes
6163 * bugs such as string of one greek letter rho
Denys Vlasenkoed79a632017-07-05 19:20:43 +02006164 * (unicode-encoded as two bytes "cf,81")
Denys Vlasenkofda9faf2017-07-05 19:10:21 +02006165 * getting encoded as "cf,CTLESC,81"
6166 * and here, converted to "cf,\,81" -
6167 * which does not go well with some flavors
Denys Vlasenko92b8d9c2017-07-05 19:13:44 +02006168 * of fnmatch() in unicode locales
6169 * (for example, glibc <= 2.22).
Denys Vlasenkofda9faf2017-07-05 19:10:21 +02006170 *
6171 * Lets add "\" only on the chars which need it.
Denys Vlasenko4142f012017-07-05 22:19:28 +02006172 * Testcases for less obvious chars are shown.
Denys Vlasenkofda9faf2017-07-05 19:10:21 +02006173 */
6174 if (*p == '*'
6175 || *p == '?'
6176 || *p == '['
Denys Vlasenko8de5b9f2018-02-13 14:43:29 +01006177 || *p == '\\' /* case '\' in \\ ) echo ok;; *) echo WRONG;; esac */
6178 || *p == ']' /* case ']' in [a\]] ) echo ok;; *) echo WRONG;; esac */
6179 || *p == '-' /* case '-' in [a\-c]) echo ok;; *) echo WRONG;; esac */
6180 || *p == '!' /* case '!' in [\!] ) echo ok;; *) echo WRONG;; esac */
Denys Vlasenko4142f012017-07-05 22:19:28 +02006181 /* Some libc support [^negate], that's why "^" also needs love */
Denys Vlasenko8de5b9f2018-02-13 14:43:29 +01006182 || *p == '^' /* case '^' in [\^] ) echo ok;; *) echo WRONG;; esac */
Denys Vlasenkofda9faf2017-07-05 19:10:21 +02006183 ) {
6184 *q++ = '\\';
6185 }
Ron Yorston549deab2015-05-18 09:57:51 +02006186 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006187 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006188#if BASH_PATTERN_SUBST
Denys Vlasenko740058b2018-01-09 17:01:00 +01006189 else if (slash_position && p == str + *slash_position) {
6190 /* stop handling globbing */
6191 globbing = 0;
6192 *slash_position = q - r;
6193 slash_position = NULL;
Ron Yorston417622c2015-05-18 09:59:14 +02006194 }
6195#endif
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006196 protect_against_glob = globbing;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006197 copy:
6198 *q++ = *p++;
6199 }
6200 *q = '\0';
6201 if (flag & RMESCAPE_GROW) {
6202 expdest = r;
6203 STADJUST(q - r + 1, expdest);
6204 }
6205 return r;
6206}
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006207#define pmatch(a, b) !fnmatch((a), (b), 0)
6208
6209/*
6210 * Prepare a pattern for a expmeta (internal glob(3)) call.
6211 *
6212 * Returns an stalloced string.
6213 */
6214static char *
Ron Yorston549deab2015-05-18 09:57:51 +02006215preglob(const char *pattern, int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006216{
Denys Vlasenko740058b2018-01-09 17:01:00 +01006217 return rmescapes((char *)pattern, flag | RMESCAPE_GLOB, NULL);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006218}
6219
6220/*
6221 * Put a string on the stack.
6222 */
6223static void
6224memtodest(const char *p, size_t len, int syntax, int quotes)
6225{
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006226 char *q;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006227
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006228 if (!len)
6229 return;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006230
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006231 q = makestrspace((quotes & QUOTES_ESC) ? len * 2 : len, expdest);
6232
6233 do {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006234 unsigned char c = *p++;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006235 if (c) {
Denys Vlasenko2fe66b12016-12-12 17:39:12 +01006236 if (quotes & QUOTES_ESC) {
6237 int n = SIT(c, syntax);
6238 if (n == CCTL
6239 || (((quotes & EXP_FULL) || syntax != BASESYNTAX)
6240 && n == CBACK
6241 )
6242 ) {
6243 USTPUTC(CTLESC, q);
6244 }
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02006245 }
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006246 } else if (!(quotes & QUOTES_KEEPNUL))
6247 continue;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006248 USTPUTC(c, q);
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006249 } while (--len);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006250
6251 expdest = q;
6252}
6253
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006254static size_t
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006255strtodest(const char *p, int syntax, int quotes)
6256{
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006257 size_t len = strlen(p);
6258 memtodest(p, len, syntax, quotes);
6259 return len;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006260}
6261
6262/*
6263 * Record the fact that we have to scan this region of the
6264 * string for IFS characters.
6265 */
6266static void
6267recordregion(int start, int end, int nulonly)
6268{
6269 struct ifsregion *ifsp;
6270
6271 if (ifslastp == NULL) {
6272 ifsp = &ifsfirst;
6273 } else {
6274 INT_OFF;
Denis Vlasenko597906c2008-02-20 16:38:54 +00006275 ifsp = ckzalloc(sizeof(*ifsp));
6276 /*ifsp->next = NULL; - ckzalloc did it */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006277 ifslastp->next = ifsp;
6278 INT_ON;
6279 }
6280 ifslastp = ifsp;
6281 ifslastp->begoff = start;
6282 ifslastp->endoff = end;
6283 ifslastp->nulonly = nulonly;
6284}
6285
6286static void
6287removerecordregions(int endoff)
6288{
6289 if (ifslastp == NULL)
6290 return;
6291
6292 if (ifsfirst.endoff > endoff) {
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006293 while (ifsfirst.next) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006294 struct ifsregion *ifsp;
6295 INT_OFF;
6296 ifsp = ifsfirst.next->next;
6297 free(ifsfirst.next);
6298 ifsfirst.next = ifsp;
6299 INT_ON;
6300 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006301 if (ifsfirst.begoff > endoff) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006302 ifslastp = NULL;
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006303 } else {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006304 ifslastp = &ifsfirst;
6305 ifsfirst.endoff = endoff;
6306 }
6307 return;
6308 }
6309
6310 ifslastp = &ifsfirst;
6311 while (ifslastp->next && ifslastp->next->begoff < endoff)
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006312 ifslastp = ifslastp->next;
6313 while (ifslastp->next) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006314 struct ifsregion *ifsp;
6315 INT_OFF;
6316 ifsp = ifslastp->next->next;
6317 free(ifslastp->next);
6318 ifslastp->next = ifsp;
6319 INT_ON;
6320 }
6321 if (ifslastp->endoff > endoff)
6322 ifslastp->endoff = endoff;
6323}
6324
6325static char *
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006326exptilde(char *startp, char *p, int flags)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006327{
Denys Vlasenkocd716832009-11-28 22:14:02 +01006328 unsigned char c;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006329 char *name;
6330 struct passwd *pw;
6331 const char *home;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006332 int quotes = flags & QUOTES_ESC;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006333
6334 name = p + 1;
6335
6336 while ((c = *++p) != '\0') {
6337 switch (c) {
6338 case CTLESC:
6339 return startp;
6340 case CTLQUOTEMARK:
6341 return startp;
6342 case ':':
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006343 if (flags & EXP_VARTILDE)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006344 goto done;
6345 break;
6346 case '/':
6347 case CTLENDVAR:
6348 goto done;
6349 }
6350 }
6351 done:
6352 *p = '\0';
6353 if (*name == '\0') {
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02006354 home = lookupvar("HOME");
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006355 } else {
6356 pw = getpwnam(name);
6357 if (pw == NULL)
6358 goto lose;
6359 home = pw->pw_dir;
6360 }
6361 if (!home || !*home)
6362 goto lose;
6363 *p = c;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006364 strtodest(home, SQSYNTAX, quotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006365 return p;
6366 lose:
6367 *p = c;
6368 return startp;
6369}
6370
6371/*
6372 * Execute a command inside back quotes. If it's a builtin command, we
6373 * want to save its output in a block obtained from malloc. Otherwise
6374 * we fork off a subprocess and get the output of the command via a pipe.
6375 * Should be called with interrupts off.
6376 */
6377struct backcmd { /* result of evalbackcmd */
6378 int fd; /* file descriptor to read from */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006379 int nleft; /* number of chars in buffer */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00006380 char *buf; /* buffer */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006381 struct job *jp; /* job structure for command */
6382};
6383
6384/* These forward decls are needed to use "eval" code for backticks handling: */
Denys Vlasenko1e3e2cc2017-07-25 20:31:14 +02006385/* flags in argument to evaltree */
6386#define EV_EXIT 01 /* exit after evaluating tree */
6387#define EV_TESTED 02 /* exit status is checked; ignore -e flag */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02006388static int evaltree(union node *, int);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006389
Denys Vlasenko619d9b52017-07-28 15:28:33 +02006390/* An evaltree() which is known to never return.
6391 * Used to use an alias:
6392 * static int evaltreenr(union node *, int) __attribute__((alias("evaltree"),__noreturn__));
6393 * but clang was reported to "transfer" noreturn-ness to evaltree() as well.
6394 */
6395static ALWAYS_INLINE NORETURN void
6396evaltreenr(union node *n, int flags)
6397{
6398 evaltree(n, flags);
6399 bb_unreachable(abort());
6400 /* NOTREACHED */
6401}
6402
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02006403static void FAST_FUNC
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006404evalbackcmd(union node *n, struct backcmd *result)
6405{
Denys Vlasenko579ad102016-10-25 21:10:20 +02006406 int pip[2];
6407 struct job *jp;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006408
6409 result->fd = -1;
6410 result->buf = NULL;
6411 result->nleft = 0;
6412 result->jp = NULL;
Denys Vlasenko579ad102016-10-25 21:10:20 +02006413 if (n == NULL) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006414 goto out;
Denys Vlasenko579ad102016-10-25 21:10:20 +02006415 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006416
Denys Vlasenko579ad102016-10-25 21:10:20 +02006417 if (pipe(pip) < 0)
Denys Vlasenko12ffefb2017-08-23 14:52:56 +02006418 ash_msg_and_raise_perror("can't create pipe");
Denys Vlasenko579ad102016-10-25 21:10:20 +02006419 jp = makejob(/*n,*/ 1);
6420 if (forkshell(jp, n, FORK_NOJOB) == 0) {
Denys Vlasenko70392332016-10-27 02:31:55 +02006421 /* child */
Denys Vlasenko579ad102016-10-25 21:10:20 +02006422 FORCE_INT_ON;
6423 close(pip[0]);
6424 if (pip[1] != 1) {
6425 /*close(1);*/
Denys Vlasenko64774602016-10-26 15:24:30 +02006426 dup2_or_raise(pip[1], 1);
Denys Vlasenko579ad102016-10-25 21:10:20 +02006427 close(pip[1]);
6428 }
Denys Vlasenko960ca382016-10-25 18:12:15 +02006429/* TODO: eflag clearing makes the following not abort:
6430 * ash -c 'set -e; z=$(false;echo foo); echo $z'
6431 * which is what bash does (unless it is in POSIX mode).
6432 * dash deleted "eflag = 0" line in the commit
6433 * Date: Mon, 28 Jun 2010 17:11:58 +1000
6434 * [EVAL] Don't clear eflag in evalbackcmd
6435 * For now, preserve bash-like behavior, it seems to be somewhat more useful:
6436 */
Denys Vlasenko579ad102016-10-25 21:10:20 +02006437 eflag = 0;
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02006438 ifsfree();
Denys Vlasenko619d9b52017-07-28 15:28:33 +02006439 evaltreenr(n, EV_EXIT);
Denys Vlasenko579ad102016-10-25 21:10:20 +02006440 /* NOTREACHED */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006441 }
Denys Vlasenko70392332016-10-27 02:31:55 +02006442 /* parent */
Denys Vlasenko579ad102016-10-25 21:10:20 +02006443 close(pip[1]);
6444 result->fd = pip[0];
6445 result->jp = jp;
6446
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006447 out:
6448 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
6449 result->fd, result->buf, result->nleft, result->jp));
6450}
6451
6452/*
6453 * Expand stuff in backwards quotes.
6454 */
6455static void
Ron Yorston549deab2015-05-18 09:57:51 +02006456expbackq(union node *cmd, int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006457{
6458 struct backcmd in;
6459 int i;
6460 char buf[128];
6461 char *p;
6462 char *dest;
6463 int startloc;
Ron Yorston549deab2015-05-18 09:57:51 +02006464 int syntax = flag & EXP_QUOTED ? DQSYNTAX : BASESYNTAX;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006465 struct stackmark smark;
6466
6467 INT_OFF;
Denys Vlasenko60ca8342016-09-30 11:21:21 +02006468 startloc = expdest - (char *)stackblock();
6469 pushstackmark(&smark, startloc);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006470 evalbackcmd(cmd, &in);
6471 popstackmark(&smark);
6472
6473 p = in.buf;
6474 i = in.nleft;
6475 if (i == 0)
6476 goto read;
6477 for (;;) {
Ron Yorston549deab2015-05-18 09:57:51 +02006478 memtodest(p, i, syntax, flag & QUOTES_ESC);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006479 read:
6480 if (in.fd < 0)
6481 break;
Ron Yorston61d6ae22015-04-19 10:50:25 +01006482 i = nonblock_immune_read(in.fd, buf, sizeof(buf));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006483 TRACE(("expbackq: read returns %d\n", i));
6484 if (i <= 0)
6485 break;
6486 p = buf;
6487 }
6488
Denis Vlasenko60818682007-09-28 22:07:23 +00006489 free(in.buf);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006490 if (in.fd >= 0) {
6491 close(in.fd);
6492 back_exitstatus = waitforjob(in.jp);
6493 }
6494 INT_ON;
6495
6496 /* Eat all trailing newlines */
6497 dest = expdest;
6498 for (; dest > (char *)stackblock() && dest[-1] == '\n';)
6499 STUNPUTC(dest);
6500 expdest = dest;
6501
Ron Yorston549deab2015-05-18 09:57:51 +02006502 if (!(flag & EXP_QUOTED))
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006503 recordregion(startloc, dest - (char *)stackblock(), 0);
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006504 TRACE(("evalbackq: size:%d:'%.*s'\n",
6505 (int)((dest - (char *)stackblock()) - startloc),
6506 (int)((dest - (char *)stackblock()) - startloc),
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006507 stackblock() + startloc));
6508}
6509
Denys Vlasenko0b883582016-12-23 16:49:07 +01006510#if ENABLE_FEATURE_SH_MATH
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006511/*
6512 * Expand arithmetic expression. Backup to start of expression,
6513 * evaluate, place result in (backed up) result, adjust string position.
6514 */
6515static void
Ron Yorston549deab2015-05-18 09:57:51 +02006516expari(int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006517{
6518 char *p, *start;
6519 int begoff;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006520 int len;
6521
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006522 /* ifsfree(); */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006523
6524 /*
6525 * This routine is slightly over-complicated for
6526 * efficiency. Next we scan backwards looking for the
6527 * start of arithmetic.
6528 */
6529 start = stackblock();
6530 p = expdest - 1;
6531 *p = '\0';
6532 p--;
Denys Vlasenko940c7202011-03-02 04:07:14 +01006533 while (1) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006534 int esc;
6535
Denys Vlasenkocd716832009-11-28 22:14:02 +01006536 while ((unsigned char)*p != CTLARI) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006537 p--;
6538#if DEBUG
6539 if (p < start) {
6540 ash_msg_and_raise_error("missing CTLARI (shouldn't happen)");
6541 }
6542#endif
6543 }
6544
6545 esc = esclen(start, p);
6546 if (!(esc % 2)) {
6547 break;
6548 }
6549
6550 p -= esc + 1;
Denys Vlasenko940c7202011-03-02 04:07:14 +01006551 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006552
6553 begoff = p - start;
6554
6555 removerecordregions(begoff);
6556
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006557 expdest = p;
6558
Ron Yorston549deab2015-05-18 09:57:51 +02006559 if (flag & QUOTES_ESC)
Denys Vlasenko740058b2018-01-09 17:01:00 +01006560 rmescapes(p + 1, 0, NULL);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006561
Ron Yorston549deab2015-05-18 09:57:51 +02006562 len = cvtnum(ash_arith(p + 1));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006563
Ron Yorston549deab2015-05-18 09:57:51 +02006564 if (!(flag & EXP_QUOTED))
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006565 recordregion(begoff, begoff + len, 0);
6566}
6567#endif
6568
6569/* argstr needs it */
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02006570static char *evalvar(char *p, int flags);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006571
6572/*
6573 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
6574 * characters to allow for further processing. Otherwise treat
6575 * $@ like $* since no splitting will be performed.
6576 */
6577static void
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02006578argstr(char *p, int flags)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006579{
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00006580 static const char spclchars[] ALIGN1 = {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006581 '=',
6582 ':',
6583 CTLQUOTEMARK,
6584 CTLENDVAR,
6585 CTLESC,
6586 CTLVAR,
6587 CTLBACKQ,
Denys Vlasenko0b883582016-12-23 16:49:07 +01006588#if ENABLE_FEATURE_SH_MATH
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006589 CTLENDARI,
6590#endif
Denys Vlasenkocd716832009-11-28 22:14:02 +01006591 '\0'
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006592 };
6593 const char *reject = spclchars;
Ron Yorston3df47f92015-05-18 09:53:26 +02006594 int breakall = (flags & (EXP_WORD | EXP_QUOTED)) == EXP_WORD;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006595 int inquotes;
6596 size_t length;
6597 int startloc;
6598
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006599 if (!(flags & EXP_VARTILDE)) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006600 reject += 2;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006601 } else if (flags & EXP_VARTILDE2) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006602 reject++;
6603 }
6604 inquotes = 0;
6605 length = 0;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006606 if (flags & EXP_TILDE) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006607 char *q;
6608
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006609 flags &= ~EXP_TILDE;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006610 tilde:
6611 q = p;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006612 if (*q == '~')
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006613 p = exptilde(p, q, flags);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006614 }
6615 start:
6616 startloc = expdest - (char *)stackblock();
6617 for (;;) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006618 unsigned char c;
6619
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006620 length += strcspn(p + length, reject);
Denys Vlasenkocd716832009-11-28 22:14:02 +01006621 c = p[length];
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006622 if (c) {
6623 if (!(c & 0x80)
Denys Vlasenko0b883582016-12-23 16:49:07 +01006624 IF_FEATURE_SH_MATH(|| c == CTLENDARI)
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006625 ) {
6626 /* c == '=' || c == ':' || c == CTLENDARI */
6627 length++;
6628 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006629 }
6630 if (length > 0) {
6631 int newloc;
6632 expdest = stack_nputstr(p, length, expdest);
6633 newloc = expdest - (char *)stackblock();
6634 if (breakall && !inquotes && newloc > startloc) {
6635 recordregion(startloc, newloc, 0);
6636 }
6637 startloc = newloc;
6638 }
6639 p += length + 1;
6640 length = 0;
6641
6642 switch (c) {
6643 case '\0':
6644 goto breakloop;
6645 case '=':
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006646 if (flags & EXP_VARTILDE2) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006647 p--;
6648 continue;
6649 }
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006650 flags |= EXP_VARTILDE2;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006651 reject++;
6652 /* fall through */
6653 case ':':
6654 /*
6655 * sort of a hack - expand tildes in variable
6656 * assignments (after the first '=' and after ':'s).
6657 */
6658 if (*--p == '~') {
6659 goto tilde;
6660 }
6661 continue;
6662 }
6663
6664 switch (c) {
6665 case CTLENDVAR: /* ??? */
6666 goto breakloop;
6667 case CTLQUOTEMARK:
6668 /* "$@" syntax adherence hack */
Denys Vlasenko9a95df92018-04-02 14:27:50 +02006669 if (!inquotes && !memcmp(p, dolatstr + 1, DOLATSTRLEN - 1)) {
6670 p = evalvar(p + 1, flags | EXP_QUOTED) + 1;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006671 goto start;
6672 }
Denys Vlasenko9a95df92018-04-02 14:27:50 +02006673 inquotes ^= EXP_QUOTED;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006674 addquote:
Ron Yorston549deab2015-05-18 09:57:51 +02006675 if (flags & QUOTES_ESC) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006676 p--;
6677 length++;
6678 startloc++;
6679 }
6680 break;
6681 case CTLESC:
6682 startloc++;
6683 length++;
6684 goto addquote;
6685 case CTLVAR:
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02006686 TRACE(("argstr: evalvar('%s')\n", p));
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02006687 p = evalvar(p, flags | inquotes);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02006688 TRACE(("argstr: evalvar:'%s'\n", (char *)stackblock()));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006689 goto start;
6690 case CTLBACKQ:
Ron Yorston549deab2015-05-18 09:57:51 +02006691 expbackq(argbackq->n, flags | inquotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006692 argbackq = argbackq->next;
6693 goto start;
Denys Vlasenko0b883582016-12-23 16:49:07 +01006694#if ENABLE_FEATURE_SH_MATH
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006695 case CTLENDARI:
6696 p--;
Ron Yorston549deab2015-05-18 09:57:51 +02006697 expari(flags | inquotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006698 goto start;
6699#endif
6700 }
6701 }
Denys Vlasenko958581a2010-09-12 15:04:27 +02006702 breakloop: ;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006703}
6704
6705static char *
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006706scanleft(char *startp, char *rmesc, char *rmescend UNUSED_PARAM,
6707 char *pattern, int quotes, int zero)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006708{
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006709 char *loc, *loc2;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006710 char c;
6711
6712 loc = startp;
6713 loc2 = rmesc;
6714 do {
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006715 int match;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006716 const char *s = loc2;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006717
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006718 c = *loc2;
6719 if (zero) {
6720 *loc2 = '\0';
6721 s = rmesc;
6722 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006723 match = pmatch(pattern, s);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006724
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006725 *loc2 = c;
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006726 if (match)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006727 return loc;
Denys Vlasenkocd716832009-11-28 22:14:02 +01006728 if (quotes && (unsigned char)*loc == CTLESC)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006729 loc++;
6730 loc++;
6731 loc2++;
6732 } while (c);
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006733 return NULL;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006734}
6735
6736static char *
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006737scanright(char *startp, char *rmesc, char *rmescend,
6738 char *pattern, int quotes, int match_at_start)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006739{
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006740#if !ENABLE_ASH_OPTIMIZE_FOR_SIZE
6741 int try2optimize = match_at_start;
6742#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006743 int esc = 0;
6744 char *loc;
6745 char *loc2;
6746
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006747 /* If we called by "${v/pattern/repl}" or "${v//pattern/repl}":
6748 * startp="escaped_value_of_v" rmesc="raw_value_of_v"
6749 * rmescend=""(ptr to NUL in rmesc) pattern="pattern" quotes=match_at_start=1
6750 * Logic:
6751 * loc starts at NUL at the end of startp, loc2 starts at the end of rmesc,
6752 * and on each iteration they go back two/one char until they reach the beginning.
6753 * We try to find a match in "raw_value_of_v", "raw_value_of_", "raw_value_of" etc.
6754 */
6755 /* TODO: document in what other circumstances we are called. */
6756
6757 for (loc = pattern - 1, loc2 = rmescend; loc >= startp; loc2--) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006758 int match;
6759 char c = *loc2;
6760 const char *s = loc2;
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006761 if (match_at_start) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006762 *loc2 = '\0';
6763 s = rmesc;
6764 }
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006765 match = pmatch(pattern, s);
6766 //bb_error_msg("pmatch(pattern:'%s',s:'%s'):%d", pattern, s, match);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006767 *loc2 = c;
6768 if (match)
6769 return loc;
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006770#if !ENABLE_ASH_OPTIMIZE_FOR_SIZE
6771 if (try2optimize) {
6772 /* Maybe we can optimize this:
6773 * if pattern ends with unescaped *, we can avoid checking
Denys Vlasenko10ad6222017-04-17 16:13:32 +02006774 * shorter strings: if "foo*" doesn't match "raw_value_of_v",
6775 * it won't match truncated "raw_value_of_" strings too.
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006776 */
6777 unsigned plen = strlen(pattern);
6778 /* Does it end with "*"? */
6779 if (plen != 0 && pattern[--plen] == '*') {
6780 /* "xxxx*" is not escaped */
6781 /* "xxx\*" is escaped */
6782 /* "xx\\*" is not escaped */
6783 /* "x\\\*" is escaped */
6784 int slashes = 0;
6785 while (plen != 0 && pattern[--plen] == '\\')
6786 slashes++;
6787 if (!(slashes & 1))
6788 break; /* ends with unescaped "*" */
6789 }
6790 try2optimize = 0;
6791 }
6792#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006793 loc--;
6794 if (quotes) {
6795 if (--esc < 0) {
6796 esc = esclen(startp, loc);
6797 }
6798 if (esc % 2) {
6799 esc--;
6800 loc--;
6801 }
6802 }
6803 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006804 return NULL;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006805}
6806
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00006807static void varunset(const char *, const char *, const char *, int) NORETURN;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006808static void
6809varunset(const char *end, const char *var, const char *umsg, int varflags)
6810{
6811 const char *msg;
6812 const char *tail;
6813
6814 tail = nullstr;
6815 msg = "parameter not set";
6816 if (umsg) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006817 if ((unsigned char)*end == CTLENDVAR) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006818 if (varflags & VSNUL)
6819 tail = " or null";
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006820 } else {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006821 msg = umsg;
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006822 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006823 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006824 ash_msg_and_raise_error("%.*s: %s%s", (int)(end - var - 1), var, msg, tail);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006825}
6826
6827static const char *
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006828subevalvar(char *p, char *varname, int strloc, int subtype,
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02006829 int startloc, int varflags, int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006830{
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006831 struct nodelist *saveargbackq = argbackq;
Ron Yorston549deab2015-05-18 09:57:51 +02006832 int quotes = flag & QUOTES_ESC;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006833 char *startp;
6834 char *loc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006835 char *rmesc, *rmescend;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006836 char *str;
Denys Vlasenko0b4980c2012-09-25 12:49:29 +02006837 int amount, resetloc;
Denys Vlasenko740058b2018-01-09 17:01:00 +01006838 int argstr_flags;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006839 IF_BASH_PATTERN_SUBST(int workloc;)
Denys Vlasenko740058b2018-01-09 17:01:00 +01006840 IF_BASH_PATTERN_SUBST(int slash_pos;)
6841 IF_BASH_PATTERN_SUBST(char *repl;)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006842 int zero;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006843 char *(*scan)(char*, char*, char*, char*, int, int);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006844
Denys Vlasenko6040fe82010-09-12 15:03:16 +02006845 //bb_error_msg("subevalvar(p:'%s',varname:'%s',strloc:%d,subtype:%d,startloc:%d,varflags:%x,quotes:%d)",
6846 // p, varname, strloc, subtype, startloc, varflags, quotes);
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006847
Denys Vlasenko740058b2018-01-09 17:01:00 +01006848#if BASH_PATTERN_SUBST
Denys Vlasenkod1df1a72018-01-09 17:25:58 +01006849 /* For "${v/pattern/repl}", we must find the delimiter _before_
6850 * argstr() call expands possible variable references in pattern:
6851 * think about "v=a; a=a/; echo ${v/$a/r}" case.
6852 */
Denys Vlasenko740058b2018-01-09 17:01:00 +01006853 repl = NULL;
6854 if (subtype == VSREPLACE || subtype == VSREPLACEALL) {
6855 /* Find '/' and replace with NUL */
6856 repl = p;
6857 for (;;) {
6858 /* Handle escaped slashes, e.g. "${v/\//_}" (they are CTLESC'ed by this point) */
6859 if (*repl == '\0') {
6860 repl = NULL;
6861 break;
6862 }
6863 if (*repl == '/') {
6864 *repl = '\0';
6865 break;
6866 }
Denys Vlasenkod1df1a72018-01-09 17:25:58 +01006867 if ((unsigned char)*repl == CTLESC && repl[1])
Denys Vlasenko740058b2018-01-09 17:01:00 +01006868 repl++;
Denys Vlasenko740058b2018-01-09 17:01:00 +01006869 repl++;
6870 }
6871 }
6872#endif
6873 argstr_flags = EXP_TILDE;
Denys Vlasenko216913c2018-04-02 12:35:04 +02006874 if (subtype != VSASSIGN
6875 && subtype != VSQUESTION
6876#if BASH_SUBSTR
6877 && subtype != VSSUBSTR
6878#endif
6879 ) {
6880 /* EXP_CASE keeps CTLESC's */
6881 argstr_flags = EXP_TILDE | EXP_CASE;
6882 }
Denys Vlasenko740058b2018-01-09 17:01:00 +01006883 argstr(p, argstr_flags);
Denys Vlasenko216913c2018-04-02 12:35:04 +02006884 //bb_error_msg("str0:'%s'", (char *)stackblock() + strloc);
Denys Vlasenko740058b2018-01-09 17:01:00 +01006885#if BASH_PATTERN_SUBST
6886 slash_pos = -1;
6887 if (repl) {
6888 slash_pos = expdest - ((char *)stackblock() + strloc);
6889 STPUTC('/', expdest);
Denys Vlasenko216913c2018-04-02 12:35:04 +02006890 //bb_error_msg("repl+1:'%s'", repl + 1);
6891 argstr(repl + 1, EXP_TILDE); /* EXP_TILDE: echo "${v/x/~}" expands ~ ! */
Denys Vlasenko740058b2018-01-09 17:01:00 +01006892 *repl = '/';
6893 }
6894#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006895 STPUTC('\0', expdest);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006896 argbackq = saveargbackq;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006897 startp = (char *)stackblock() + startloc;
Denys Vlasenko740058b2018-01-09 17:01:00 +01006898 //bb_error_msg("str1:'%s'", (char *)stackblock() + strloc);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006899
6900 switch (subtype) {
6901 case VSASSIGN:
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02006902 setvar0(varname, startp);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006903 amount = startp - expdest;
6904 STADJUST(amount, expdest);
6905 return startp;
6906
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006907 case VSQUESTION:
6908 varunset(p, varname, startp, varflags);
6909 /* NOTREACHED */
6910
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006911#if BASH_SUBSTR
Denys Vlasenko826360f2017-07-17 17:49:11 +02006912 case VSSUBSTR: {
6913 int pos, len, orig_len;
6914 char *colon;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006915
Denys Vlasenko826360f2017-07-17 17:49:11 +02006916 loc = str = stackblock() + strloc;
6917
Denys Vlasenko826360f2017-07-17 17:49:11 +02006918 /* Read POS in ${var:POS:LEN} */
6919 colon = strchr(loc, ':');
6920 if (colon) *colon = '\0';
Denys Vlasenkobaa41c72018-01-10 13:22:25 +01006921 pos = substr_atoi(loc);
Denys Vlasenko826360f2017-07-17 17:49:11 +02006922 if (colon) *colon = ':';
6923
6924 /* Read LEN in ${var:POS:LEN} */
6925 len = str - startp - 1;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006926 /* *loc != '\0', guaranteed by parser */
6927 if (quotes) {
6928 char *ptr;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006929 /* Adjust the length by the number of escapes */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006930 for (ptr = startp; ptr < (str - 1); ptr++) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006931 if ((unsigned char)*ptr == CTLESC) {
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006932 len--;
6933 ptr++;
6934 }
6935 }
6936 }
6937 orig_len = len;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006938 if (*loc++ == ':') {
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006939 /* ${var::LEN} */
Denys Vlasenkobaa41c72018-01-10 13:22:25 +01006940 len = substr_atoi(loc);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006941 } else {
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006942 /* Skip POS in ${var:POS:LEN} */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006943 len = orig_len;
Denys Vlasenkobaa41c72018-01-10 13:22:25 +01006944 while (*loc && *loc != ':')
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006945 loc++;
Denys Vlasenkobaa41c72018-01-10 13:22:25 +01006946 if (*loc++ == ':')
6947 len = substr_atoi(loc);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006948 }
Denys Vlasenko08a5dab2014-11-17 20:27:18 +01006949 if (pos < 0) {
6950 /* ${VAR:$((-n)):l} starts n chars from the end */
6951 pos = orig_len + pos;
6952 }
6953 if ((unsigned)pos >= orig_len) {
6954 /* apart from obvious ${VAR:999999:l},
6955 * covers ${VAR:$((-9999999)):l} - result is ""
Denys Vlasenko826360f2017-07-17 17:49:11 +02006956 * (bash compat)
Denys Vlasenko08a5dab2014-11-17 20:27:18 +01006957 */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006958 pos = 0;
6959 len = 0;
6960 }
Denys Vlasenko826360f2017-07-17 17:49:11 +02006961 if (len < 0) {
6962 /* ${VAR:N:-M} sets LEN to strlen()-M */
6963 len = (orig_len - pos) + len;
6964 }
6965 if ((unsigned)len > (orig_len - pos))
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006966 len = orig_len - pos;
6967
6968 for (str = startp; pos; str++, pos--) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006969 if (quotes && (unsigned char)*str == CTLESC)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006970 str++;
6971 }
6972 for (loc = startp; len; len--) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006973 if (quotes && (unsigned char)*str == CTLESC)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006974 *loc++ = *str++;
6975 *loc++ = *str++;
6976 }
6977 *loc = '\0';
6978 amount = loc - expdest;
6979 STADJUST(amount, expdest);
6980 return loc;
Denys Vlasenko826360f2017-07-17 17:49:11 +02006981 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006982#endif /* BASH_SUBSTR */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006983 }
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006984
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006985 resetloc = expdest - (char *)stackblock();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006986
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006987#if BASH_PATTERN_SUBST
Denys Vlasenko740058b2018-01-09 17:01:00 +01006988 repl = NULL;
6989
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006990 /* We'll comeback here if we grow the stack while handling
6991 * a VSREPLACE or VSREPLACEALL, since our pointers into the
6992 * stack will need rebasing, and we'll need to remove our work
6993 * areas each time
6994 */
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006995 restart:
6996#endif
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006997
6998 amount = expdest - ((char *)stackblock() + resetloc);
6999 STADJUST(-amount, expdest);
Denis Vlasenko29eb3592008-05-18 14:06:08 +00007000 startp = (char *)stackblock() + startloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007001
7002 rmesc = startp;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00007003 rmescend = (char *)stackblock() + strloc;
Denys Vlasenko740058b2018-01-09 17:01:00 +01007004 //bb_error_msg("str7:'%s'", rmescend);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007005 if (quotes) {
Denys Vlasenko740058b2018-01-09 17:01:00 +01007006//TODO: how to handle slash_pos here if string changes (shortens?)
7007 rmesc = rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW, NULL);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007008 if (rmesc != startp) {
7009 rmescend = expdest;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00007010 startp = (char *)stackblock() + startloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007011 }
7012 }
7013 rmescend--;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00007014 str = (char *)stackblock() + strloc;
Ron Yorston417622c2015-05-18 09:59:14 +02007015 /*
7016 * Example: v='a\bc'; echo ${v/\\b/_\\_\z_}
7017 * The result is a_\_z_c (not a\_\_z_c)!
7018 *
7019 * The search pattern and replace string treat backslashes differently!
Denys Vlasenko740058b2018-01-09 17:01:00 +01007020 * "&slash_pos" causes rmescapes() to work differently on the pattern
Ron Yorston417622c2015-05-18 09:59:14 +02007021 * and string. It's only used on the first call.
7022 */
Denys Vlasenko740058b2018-01-09 17:01:00 +01007023 //bb_error_msg("str8:'%s' slash_pos:%d", str, slash_pos);
7024 rmescapes(str, RMESCAPE_GLOB,
7025 repl ? NULL : (slash_pos < 0 ? NULL : &slash_pos)
7026 );
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007027
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01007028#if BASH_PATTERN_SUBST
Denys Vlasenko0b4980c2012-09-25 12:49:29 +02007029 workloc = expdest - (char *)stackblock();
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007030 if (subtype == VSREPLACE || subtype == VSREPLACEALL) {
Denys Vlasenko826360f2017-07-17 17:49:11 +02007031 int len;
Denys Vlasenkob76356b2010-03-13 16:19:04 +01007032 char *idx, *end;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007033
Denis Vlasenkod6855d12008-09-27 14:03:25 +00007034 if (!repl) {
Denys Vlasenko740058b2018-01-09 17:01:00 +01007035 //bb_error_msg("str9:'%s' slash_pos:%d", str, slash_pos);
Denys Vlasenkod1df1a72018-01-09 17:25:58 +01007036 repl = nullstr;
Denys Vlasenko740058b2018-01-09 17:01:00 +01007037 if (slash_pos >= 0) {
7038 repl = str + slash_pos;
Ron Yorston417622c2015-05-18 09:59:14 +02007039 *repl++ = '\0';
Denys Vlasenko740058b2018-01-09 17:01:00 +01007040 }
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007041 }
Ron Yorston417622c2015-05-18 09:59:14 +02007042 //bb_error_msg("str:'%s' repl:'%s'", str, repl);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007043
7044 /* If there's no pattern to match, return the expansion unmolested */
Denys Vlasenkob76356b2010-03-13 16:19:04 +01007045 if (str[0] == '\0')
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02007046 return NULL;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007047
7048 len = 0;
7049 idx = startp;
7050 end = str - 1;
7051 while (idx < end) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01007052 try_to_match:
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007053 loc = scanright(idx, rmesc, rmescend, str, quotes, 1);
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02007054 //bb_error_msg("scanright('%s'):'%s'", str, loc);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007055 if (!loc) {
7056 /* No match, advance */
Denys Vlasenkob76356b2010-03-13 16:19:04 +01007057 char *restart_detect = stackblock();
7058 skip_matching:
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007059 STPUTC(*idx, expdest);
Denys Vlasenkocd716832009-11-28 22:14:02 +01007060 if (quotes && (unsigned char)*idx == CTLESC) {
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007061 idx++;
7062 len++;
7063 STPUTC(*idx, expdest);
7064 }
7065 if (stackblock() != restart_detect)
7066 goto restart;
7067 idx++;
7068 len++;
7069 rmesc++;
Denys Vlasenkob76356b2010-03-13 16:19:04 +01007070 /* continue; - prone to quadratic behavior, smarter code: */
7071 if (idx >= end)
7072 break;
7073 if (str[0] == '*') {
7074 /* Pattern is "*foo". If "*foo" does not match "long_string",
7075 * it would never match "ong_string" etc, no point in trying.
7076 */
7077 goto skip_matching;
7078 }
7079 goto try_to_match;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007080 }
7081
7082 if (subtype == VSREPLACEALL) {
7083 while (idx < loc) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01007084 if (quotes && (unsigned char)*idx == CTLESC)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007085 idx++;
7086 idx++;
7087 rmesc++;
7088 }
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00007089 } else {
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007090 idx = loc;
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00007091 }
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007092
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02007093 //bb_error_msg("repl:'%s'", repl);
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007094 for (loc = (char*)repl; *loc; loc++) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01007095 char *restart_detect = stackblock();
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007096 if (quotes && *loc == '\\') {
7097 STPUTC(CTLESC, expdest);
7098 len++;
7099 }
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007100 STPUTC(*loc, expdest);
7101 if (stackblock() != restart_detect)
7102 goto restart;
7103 len++;
7104 }
7105
7106 if (subtype == VSREPLACE) {
Denys Vlasenkof02c82f2010-08-06 19:14:47 +02007107 //bb_error_msg("tail:'%s', quotes:%x", idx, quotes);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007108 while (*idx) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01007109 char *restart_detect = stackblock();
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007110 STPUTC(*idx, expdest);
7111 if (stackblock() != restart_detect)
7112 goto restart;
7113 len++;
7114 idx++;
7115 }
7116 break;
7117 }
7118 }
7119
7120 /* We've put the replaced text into a buffer at workloc, now
7121 * move it to the right place and adjust the stack.
7122 */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007123 STPUTC('\0', expdest);
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007124 startp = (char *)stackblock() + startloc;
7125 memmove(startp, (char *)stackblock() + workloc, len + 1);
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02007126 //bb_error_msg("startp:'%s'", startp);
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007127 amount = expdest - (startp + len);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007128 STADJUST(-amount, expdest);
7129 return startp;
7130 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01007131#endif /* BASH_PATTERN_SUBST */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007132
7133 subtype -= VSTRIMRIGHT;
7134#if DEBUG
7135 if (subtype < 0 || subtype > 7)
7136 abort();
7137#endif
Denys Vlasenkob76356b2010-03-13 16:19:04 +01007138 /* zero = (subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX) */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007139 zero = subtype >> 1;
7140 /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */
7141 scan = (subtype & 1) ^ zero ? scanleft : scanright;
7142
7143 loc = scan(startp, rmesc, rmescend, str, quotes, zero);
7144 if (loc) {
7145 if (zero) {
7146 memmove(startp, loc, str - loc);
7147 loc = startp + (str - loc) - 1;
7148 }
7149 *loc = '\0';
7150 amount = loc - expdest;
7151 STADJUST(amount, expdest);
7152 }
7153 return loc;
7154}
7155
7156/*
7157 * Add the value of a specialized variable to the stack string.
Denys Vlasenko4d8873f2009-10-04 03:14:41 +02007158 * name parameter (examples):
7159 * ash -c 'echo $1' name:'1='
7160 * ash -c 'echo $qwe' name:'qwe='
7161 * ash -c 'echo $$' name:'$='
7162 * ash -c 'echo ${$}' name:'$='
7163 * ash -c 'echo ${$##q}' name:'$=q'
7164 * ash -c 'echo ${#$}' name:'$='
7165 * note: examples with bad shell syntax:
7166 * ash -c 'echo ${#$1}' name:'$=1'
7167 * ash -c 'echo ${#1#}' name:'1=#'
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007168 */
Denys Vlasenkoadf922e2009-10-08 14:35:37 +02007169static NOINLINE ssize_t
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02007170varvalue(char *name, int varflags, int flags, int *quotedp)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007171{
Mike Frysinger98c52642009-04-02 10:02:37 +00007172 const char *p;
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01007173 int num;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007174 int i;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007175 ssize_t len = 0;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007176 int sep;
Denys Vlasenko0dd8e452016-10-01 21:02:06 +02007177 int quoted = *quotedp;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007178 int subtype = varflags & VSTYPE;
7179 int discard = subtype == VSPLUS || subtype == VSLENGTH;
7180 int quotes = (discard ? 0 : (flags & QUOTES_ESC)) | QUOTES_KEEPNUL;
Denys Vlasenko0aaaa502016-10-02 02:46:56 +02007181 int syntax;
7182
7183 sep = (flags & EXP_FULL) << CHAR_BIT;
7184 syntax = quoted ? DQSYNTAX : BASESYNTAX;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007185
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007186 switch (*name) {
7187 case '$':
7188 num = rootpid;
7189 goto numvar;
7190 case '?':
7191 num = exitstatus;
7192 goto numvar;
7193 case '#':
7194 num = shellparam.nparam;
7195 goto numvar;
7196 case '!':
7197 num = backgndpid;
7198 if (num == 0)
7199 return -1;
7200 numvar:
7201 len = cvtnum(num);
Denys Vlasenko4d8873f2009-10-04 03:14:41 +02007202 goto check_1char_name;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007203 case '-':
Mike Frysinger98c52642009-04-02 10:02:37 +00007204 expdest = makestrspace(NOPTS, expdest);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007205 for (i = NOPTS - 1; i >= 0; i--) {
Martijn Dekkerad4e9612018-03-31 18:15:59 +02007206 if (optlist[i] && optletters(i)) {
Mike Frysinger98c52642009-04-02 10:02:37 +00007207 USTPUTC(optletters(i), expdest);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007208 len++;
7209 }
7210 }
Denys Vlasenko4d8873f2009-10-04 03:14:41 +02007211 check_1char_name:
7212#if 0
7213 /* handles cases similar to ${#$1} */
7214 if (name[2] != '\0')
7215 raise_error_syntax("bad substitution");
7216#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007217 break;
Denys Vlasenko0aaaa502016-10-02 02:46:56 +02007218 case '@':
7219 if (quoted && sep)
7220 goto param;
7221 /* fall through */
7222 case '*': {
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01007223 char **ap;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007224 char sepc;
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01007225
Denys Vlasenko0aaaa502016-10-02 02:46:56 +02007226 if (quoted)
7227 sep = 0;
7228 sep |= ifsset() ? ifsval()[0] : ' ';
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007229 param:
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007230 sepc = sep;
Denys Vlasenko0dd8e452016-10-01 21:02:06 +02007231 *quotedp = !sepc;
7232 ap = shellparam.p;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007233 if (!ap)
7234 return -1;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02007235 while ((p = *ap++) != NULL) {
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007236 len += strtodest(p, syntax, quotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007237
7238 if (*ap && sep) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007239 len++;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007240 memtodest(&sepc, 1, syntax, quotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007241 }
7242 }
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007243 break;
Denys Vlasenko0aaaa502016-10-02 02:46:56 +02007244 } /* case '*' */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007245 case '0':
7246 case '1':
7247 case '2':
7248 case '3':
7249 case '4':
7250 case '5':
7251 case '6':
7252 case '7':
7253 case '8':
7254 case '9':
Denys Vlasenkoa00329c2009-08-30 20:05:10 +02007255 num = atoi(name); /* number(name) fails on ${N#str} etc */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007256 if (num < 0 || num > shellparam.nparam)
7257 return -1;
7258 p = num ? shellparam.p[num - 1] : arg0;
7259 goto value;
7260 default:
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00007261 /* NB: name has form "VAR=..." */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007262 p = lookupvar(name);
7263 value:
7264 if (!p)
7265 return -1;
7266
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007267 len = strtodest(p, syntax, quotes);
Denys Vlasenkoc76236f2014-12-29 00:04:18 +01007268#if ENABLE_UNICODE_SUPPORT
7269 if (subtype == VSLENGTH && len > 0) {
7270 reinit_unicode_for_ash();
7271 if (unicode_status == UNICODE_ON) {
Ron Yorston3e3bfb82016-03-18 11:29:19 +00007272 STADJUST(-len, expdest);
7273 discard = 0;
Denys Vlasenkoc76236f2014-12-29 00:04:18 +01007274 len = unicode_strlen(p);
7275 }
7276 }
7277#endif
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007278 break;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007279 }
7280
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007281 if (discard)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007282 STADJUST(-len, expdest);
7283 return len;
7284}
7285
7286/*
7287 * Expand a variable, and return a pointer to the next character in the
7288 * input string.
7289 */
7290static char *
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02007291evalvar(char *p, int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007292{
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00007293 char varflags;
7294 char subtype;
Ron Yorston549deab2015-05-18 09:57:51 +02007295 int quoted;
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00007296 char easy;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007297 char *var;
7298 int patloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007299 int startloc;
7300 ssize_t varlen;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007301
Denys Vlasenkob0d63382009-09-16 16:18:32 +02007302 varflags = (unsigned char) *p++;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007303 subtype = varflags & VSTYPE;
Denys Vlasenko88e15702016-10-26 01:55:56 +02007304
7305 if (!subtype)
7306 raise_error_syntax("bad substitution");
7307
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007308 quoted = flag & EXP_QUOTED;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007309 var = p;
7310 easy = (!quoted || (*var == '@' && shellparam.nparam));
7311 startloc = expdest - (char *)stackblock();
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02007312 p = strchr(p, '=') + 1; //TODO: use var_end(p)?
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007313
7314 again:
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02007315 varlen = varvalue(var, varflags, flag, &quoted);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007316 if (varflags & VSNUL)
7317 varlen--;
7318
7319 if (subtype == VSPLUS) {
7320 varlen = -1 - varlen;
7321 goto vsplus;
7322 }
7323
7324 if (subtype == VSMINUS) {
7325 vsplus:
7326 if (varlen < 0) {
7327 argstr(
Denys Vlasenko6040fe82010-09-12 15:03:16 +02007328 p,
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02007329 flag | EXP_TILDE | EXP_WORD
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007330 );
7331 goto end;
7332 }
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007333 goto record;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007334 }
7335
7336 if (subtype == VSASSIGN || subtype == VSQUESTION) {
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007337 if (varlen >= 0)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007338 goto record;
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007339
7340 subevalvar(p, var, 0, subtype, startloc, varflags,
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02007341 flag & ~QUOTES_ESC);
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007342 varflags &= ~VSNUL;
7343 /*
7344 * Remove any recorded regions beyond
7345 * start of variable
7346 */
7347 removerecordregions(startloc);
7348 goto again;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007349 }
7350
7351 if (varlen < 0 && uflag)
7352 varunset(p, var, 0, 0);
7353
7354 if (subtype == VSLENGTH) {
Denys Vlasenkoc76236f2014-12-29 00:04:18 +01007355 cvtnum(varlen > 0 ? varlen : 0);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007356 goto record;
7357 }
7358
7359 if (subtype == VSNORMAL) {
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007360 record:
7361 if (!easy)
7362 goto end;
Denys Vlasenko0dd8e452016-10-01 21:02:06 +02007363 recordregion(startloc, expdest - (char *)stackblock(), quoted);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007364 goto end;
7365 }
7366
7367#if DEBUG
7368 switch (subtype) {
7369 case VSTRIMLEFT:
7370 case VSTRIMLEFTMAX:
7371 case VSTRIMRIGHT:
7372 case VSTRIMRIGHTMAX:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01007373#if BASH_SUBSTR
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007374 case VSSUBSTR:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01007375#endif
7376#if BASH_PATTERN_SUBST
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007377 case VSREPLACE:
7378 case VSREPLACEALL:
7379#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007380 break;
7381 default:
7382 abort();
7383 }
7384#endif
7385
7386 if (varlen >= 0) {
7387 /*
7388 * Terminate the string and start recording the pattern
7389 * right after it
7390 */
7391 STPUTC('\0', expdest);
7392 patloc = expdest - (char *)stackblock();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02007393 if (NULL == subevalvar(p, /* varname: */ NULL, patloc, subtype,
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02007394 startloc, varflags, flag)) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007395 int amount = expdest - (
7396 (char *)stackblock() + patloc - 1
7397 );
7398 STADJUST(-amount, expdest);
7399 }
7400 /* Remove any recorded regions beyond start of variable */
7401 removerecordregions(startloc);
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007402 goto record;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007403 }
7404
7405 end:
7406 if (subtype != VSNORMAL) { /* skip to end of alternative */
7407 int nesting = 1;
7408 for (;;) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01007409 unsigned char c = *p++;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007410 if (c == CTLESC)
7411 p++;
Ron Yorston549deab2015-05-18 09:57:51 +02007412 else if (c == CTLBACKQ) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007413 if (varlen >= 0)
7414 argbackq = argbackq->next;
7415 } else if (c == CTLVAR) {
7416 if ((*p++ & VSTYPE) != VSNORMAL)
7417 nesting++;
7418 } else if (c == CTLENDVAR) {
7419 if (--nesting == 0)
7420 break;
7421 }
7422 }
7423 }
7424 return p;
7425}
7426
7427/*
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007428 * Add a file name to the list.
7429 */
7430static void
7431addfname(const char *name)
7432{
7433 struct strlist *sp;
7434
Denis Vlasenko597906c2008-02-20 16:38:54 +00007435 sp = stzalloc(sizeof(*sp));
Denys Vlasenko8e2bc472016-09-28 23:02:57 +02007436 sp->text = sstrdup(name);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007437 *exparg.lastp = sp;
7438 exparg.lastp = &sp->next;
7439}
7440
Felix Fietkaub5b21122017-01-31 21:58:55 +01007441/* Avoid glob() (and thus, stat() et al) for words like "echo" */
7442static int
7443hasmeta(const char *p)
7444{
7445 static const char chars[] ALIGN1 = {
7446 '*', '?', '[', '\\', CTLQUOTEMARK, CTLESC, 0
7447 };
7448
7449 for (;;) {
7450 p = strpbrk(p, chars);
7451 if (!p)
7452 break;
Denys Vlasenkoac61f442018-03-30 23:03:29 +02007453 switch ((unsigned char)*p) {
Felix Fietkaub5b21122017-01-31 21:58:55 +01007454 case CTLQUOTEMARK:
7455 for (;;) {
7456 p++;
Denys Vlasenkoac61f442018-03-30 23:03:29 +02007457 if ((unsigned char)*p == CTLQUOTEMARK)
Felix Fietkaub5b21122017-01-31 21:58:55 +01007458 break;
Denys Vlasenkoac61f442018-03-30 23:03:29 +02007459 if ((unsigned char)*p == CTLESC)
Felix Fietkaub5b21122017-01-31 21:58:55 +01007460 p++;
7461 if (*p == '\0') /* huh? */
7462 return 0;
7463 }
7464 break;
7465 case '\\':
7466 case CTLESC:
7467 p++;
7468 if (*p == '\0')
7469 return 0;
7470 break;
7471 case '[':
7472 if (!strchr(p + 1, ']')) {
7473 /* It's not a properly closed [] pattern,
7474 * but other metas may follow. Continue checking.
7475 * my[file* _is_ globbed by bash
7476 * and matches filenames like "my[file1".
7477 */
7478 break;
7479 }
7480 /* fallthrough */
7481 default:
7482 /* case '*': */
7483 /* case '?': */
7484 return 1;
7485 }
7486 p++;
7487 }
7488
7489 return 0;
7490}
7491
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007492/* If we want to use glob() from libc... */
Denys Vlasenko514b51d2016-10-01 14:33:08 +02007493#if !ENABLE_ASH_INTERNAL_GLOB
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007494
7495/* Add the result of glob() to the list */
7496static void
7497addglob(const glob_t *pglob)
7498{
7499 char **p = pglob->gl_pathv;
7500
7501 do {
7502 addfname(*p);
7503 } while (*++p);
7504}
7505static void
7506expandmeta(struct strlist *str /*, int flag*/)
7507{
7508 /* TODO - EXP_REDIR */
7509
7510 while (str) {
7511 char *p;
7512 glob_t pglob;
7513 int i;
7514
7515 if (fflag)
7516 goto nometa;
Denys Vlasenkod4f3db92016-10-30 18:41:01 +01007517
Felix Fietkaub5b21122017-01-31 21:58:55 +01007518 if (!hasmeta(str->text))
7519 goto nometa;
Denys Vlasenkod4f3db92016-10-30 18:41:01 +01007520
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007521 INT_OFF;
7522 p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP);
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007523// GLOB_NOMAGIC (GNU): if no *?[ chars in pattern, return it even if no match
7524// GLOB_NOCHECK: if no match, return unchanged pattern (sans \* escapes?)
7525//
7526// glibc 2.24.90 glob(GLOB_NOMAGIC) does not remove backslashes used for escaping:
7527// if you pass it "file\?", it returns "file\?", not "file?", if no match.
7528// Which means you need to unescape the string, right? Not so fast:
7529// if there _is_ a file named "file\?" (with backslash), it is returned
7530// as "file\?" too (whichever pattern you used to find it, say, "file*").
Denys Vlasenko10ad6222017-04-17 16:13:32 +02007531// You DON'T KNOW by looking at the result whether you need to unescape it.
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007532//
7533// Worse, globbing of "file\?" in a directory with two files, "file?" and "file\?",
7534// returns "file\?" - which is WRONG: "file\?" pattern matches "file?" file.
7535// Without GLOB_NOMAGIC, this works correctly ("file?" is returned as a match).
7536// With GLOB_NOMAGIC | GLOB_NOCHECK, this also works correctly.
7537// i = glob(p, GLOB_NOMAGIC | GLOB_NOCHECK, NULL, &pglob);
7538// i = glob(p, GLOB_NOMAGIC, NULL, &pglob);
7539 i = glob(p, 0, NULL, &pglob);
7540 //bb_error_msg("glob('%s'):%d '%s'...", p, i, pglob.gl_pathv ? pglob.gl_pathv[0] : "-");
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007541 if (p != str->text)
7542 free(p);
7543 switch (i) {
7544 case 0:
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007545#if 0 // glibc 2.24.90 bug? Patterns like "*/file", when match, don't set GLOB_MAGCHAR
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007546 /* GLOB_MAGCHAR is set if *?[ chars were seen (GNU) */
7547 if (!(pglob.gl_flags & GLOB_MAGCHAR))
7548 goto nometa2;
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007549#endif
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007550 addglob(&pglob);
7551 globfree(&pglob);
7552 INT_ON;
7553 break;
7554 case GLOB_NOMATCH:
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007555 //nometa2:
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007556 globfree(&pglob);
7557 INT_ON;
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007558 nometa:
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007559 *exparg.lastp = str;
Denys Vlasenko740058b2018-01-09 17:01:00 +01007560 rmescapes(str->text, 0, NULL);
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007561 exparg.lastp = &str->next;
7562 break;
7563 default: /* GLOB_NOSPACE */
7564 globfree(&pglob);
7565 INT_ON;
7566 ash_msg_and_raise_error(bb_msg_memory_exhausted);
7567 }
7568 str = str->next;
7569 }
7570}
7571
7572#else
Denys Vlasenko514b51d2016-10-01 14:33:08 +02007573/* ENABLE_ASH_INTERNAL_GLOB: Homegrown globbing code. (dash also has both, uses homegrown one.) */
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007574
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007575/*
7576 * Do metacharacter (i.e. *, ?, [...]) expansion.
7577 */
Denys Vlasenkod5f50452018-04-14 14:50:47 +02007578typedef struct exp_t {
7579 char *dir;
7580 unsigned dir_max;
7581} exp_t;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007582static void
Denys Vlasenkod5f50452018-04-14 14:50:47 +02007583expmeta(exp_t *exp, char *name, unsigned name_len, unsigned expdir_len)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007584{
Denys Vlasenkod5f50452018-04-14 14:50:47 +02007585#define expdir exp->dir
7586#define expdir_max exp->dir_max
7587 char *enddir = expdir + expdir_len;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007588 char *p;
7589 const char *cp;
7590 char *start;
7591 char *endname;
7592 int metaflag;
7593 struct stat statb;
7594 DIR *dirp;
7595 struct dirent *dp;
7596 int atend;
7597 int matchdot;
Ron Yorstonca25af92015-09-04 10:32:41 +01007598 int esc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007599
7600 metaflag = 0;
7601 start = name;
Ron Yorstonca25af92015-09-04 10:32:41 +01007602 for (p = name; esc = 0, *p; p += esc + 1) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007603 if (*p == '*' || *p == '?')
7604 metaflag = 1;
7605 else if (*p == '[') {
7606 char *q = p + 1;
7607 if (*q == '!')
7608 q++;
7609 for (;;) {
7610 if (*q == '\\')
7611 q++;
7612 if (*q == '/' || *q == '\0')
7613 break;
7614 if (*++q == ']') {
7615 metaflag = 1;
7616 break;
7617 }
7618 }
Ron Yorstonca25af92015-09-04 10:32:41 +01007619 } else {
7620 if (*p == '\\')
7621 esc++;
7622 if (p[esc] == '/') {
7623 if (metaflag)
7624 break;
7625 start = p + esc + 1;
7626 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007627 }
7628 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007629 if (metaflag == 0) { /* we've reached the end of the file name */
Denys Vlasenkod5f50452018-04-14 14:50:47 +02007630 if (!expdir_len)
7631 return;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007632 p = name;
7633 do {
7634 if (*p == '\\')
7635 p++;
7636 *enddir++ = *p;
7637 } while (*p++);
Denys Vlasenkod5f50452018-04-14 14:50:47 +02007638 if (lstat(expdir, &statb) == 0)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007639 addfname(expdir);
7640 return;
7641 }
7642 endname = p;
7643 if (name < start) {
7644 p = name;
7645 do {
7646 if (*p == '\\')
7647 p++;
7648 *enddir++ = *p++;
7649 } while (p < start);
7650 }
Denys Vlasenkod5f50452018-04-14 14:50:47 +02007651 *enddir = '\0';
7652 cp = expdir;
7653 expdir_len = enddir - cp;
7654 if (!expdir_len)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007655 cp = ".";
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007656 dirp = opendir(cp);
7657 if (dirp == NULL)
7658 return;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007659 if (*endname == 0) {
7660 atend = 1;
7661 } else {
7662 atend = 0;
Ron Yorstonca25af92015-09-04 10:32:41 +01007663 *endname = '\0';
7664 endname += esc + 1;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007665 }
Denys Vlasenkod5f50452018-04-14 14:50:47 +02007666 name_len -= endname - name;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007667 matchdot = 0;
7668 p = start;
7669 if (*p == '\\')
7670 p++;
7671 if (*p == '.')
7672 matchdot++;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02007673 while (!pending_int && (dp = readdir(dirp)) != NULL) {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00007674 if (dp->d_name[0] == '.' && !matchdot)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007675 continue;
7676 if (pmatch(start, dp->d_name)) {
7677 if (atend) {
7678 strcpy(enddir, dp->d_name);
7679 addfname(expdir);
7680 } else {
Denys Vlasenkod5f50452018-04-14 14:50:47 +02007681 unsigned offset;
7682 unsigned len;
7683
7684 p = stpcpy(enddir, dp->d_name);
7685 *p = '/';
7686
7687 offset = p - expdir + 1;
7688 len = offset + name_len + NAME_MAX;
7689 if (len > expdir_max) {
7690 len += PATH_MAX;
7691 expdir = ckrealloc(expdir, len);
7692 expdir_max = len;
7693 }
7694
7695 expmeta(exp, endname, name_len, offset);
7696 enddir = expdir + expdir_len;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007697 }
7698 }
7699 }
7700 closedir(dirp);
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00007701 if (!atend)
Ron Yorstonca25af92015-09-04 10:32:41 +01007702 endname[-esc - 1] = esc ? '\\' : '/';
Denys Vlasenkod5f50452018-04-14 14:50:47 +02007703#undef expdir
7704#undef expdir_max
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007705}
7706
7707static struct strlist *
7708msort(struct strlist *list, int len)
7709{
7710 struct strlist *p, *q = NULL;
7711 struct strlist **lpp;
7712 int half;
7713 int n;
7714
7715 if (len <= 1)
7716 return list;
7717 half = len >> 1;
7718 p = list;
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +00007719 for (n = half; --n >= 0;) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007720 q = p;
7721 p = p->next;
7722 }
7723 q->next = NULL; /* terminate first half of list */
7724 q = msort(list, half); /* sort first half of list */
7725 p = msort(p, len - half); /* sort second half */
7726 lpp = &list;
7727 for (;;) {
7728#if ENABLE_LOCALE_SUPPORT
7729 if (strcoll(p->text, q->text) < 0)
7730#else
7731 if (strcmp(p->text, q->text) < 0)
7732#endif
7733 {
7734 *lpp = p;
7735 lpp = &p->next;
7736 p = *lpp;
7737 if (p == NULL) {
7738 *lpp = q;
7739 break;
7740 }
7741 } else {
7742 *lpp = q;
7743 lpp = &q->next;
7744 q = *lpp;
7745 if (q == NULL) {
7746 *lpp = p;
7747 break;
7748 }
7749 }
7750 }
7751 return list;
7752}
7753
7754/*
7755 * Sort the results of file name expansion. It calculates the number of
7756 * strings to sort and then calls msort (short for merge sort) to do the
7757 * work.
7758 */
7759static struct strlist *
7760expsort(struct strlist *str)
7761{
7762 int len;
7763 struct strlist *sp;
7764
7765 len = 0;
7766 for (sp = str; sp; sp = sp->next)
7767 len++;
7768 return msort(str, len);
7769}
7770
7771static void
Denis Vlasenko68404f12008-03-17 09:00:54 +00007772expandmeta(struct strlist *str /*, int flag*/)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007773{
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007774 /* TODO - EXP_REDIR */
7775
7776 while (str) {
Denys Vlasenkod5f50452018-04-14 14:50:47 +02007777 exp_t exp;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007778 struct strlist **savelastp;
7779 struct strlist *sp;
7780 char *p;
Denys Vlasenkod5f50452018-04-14 14:50:47 +02007781 unsigned len;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007782
7783 if (fflag)
7784 goto nometa;
Felix Fietkaub5b21122017-01-31 21:58:55 +01007785 if (!hasmeta(str->text))
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007786 goto nometa;
7787 savelastp = exparg.lastp;
7788
7789 INT_OFF;
Ron Yorston549deab2015-05-18 09:57:51 +02007790 p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP);
Denys Vlasenkod5f50452018-04-14 14:50:47 +02007791 len = strlen(p);
7792 exp.dir_max = len + PATH_MAX;
7793 exp.dir = ckmalloc(exp.dir_max);
7794
7795 expmeta(&exp, p, len, 0);
7796 free(exp.dir);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007797 if (p != str->text)
7798 free(p);
7799 INT_ON;
7800 if (exparg.lastp == savelastp) {
7801 /*
7802 * no matches
7803 */
7804 nometa:
7805 *exparg.lastp = str;
Denys Vlasenko740058b2018-01-09 17:01:00 +01007806 rmescapes(str->text, 0, NULL);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007807 exparg.lastp = &str->next;
7808 } else {
7809 *exparg.lastp = NULL;
7810 *savelastp = sp = expsort(*savelastp);
7811 while (sp->next != NULL)
7812 sp = sp->next;
7813 exparg.lastp = &sp->next;
7814 }
7815 str = str->next;
7816 }
7817}
Denys Vlasenko514b51d2016-10-01 14:33:08 +02007818#endif /* ENABLE_ASH_INTERNAL_GLOB */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007819
7820/*
7821 * Perform variable substitution and command substitution on an argument,
7822 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
7823 * perform splitting and file name expansion. When arglist is NULL, perform
7824 * here document expansion.
7825 */
7826static void
7827expandarg(union node *arg, struct arglist *arglist, int flag)
7828{
7829 struct strlist *sp;
7830 char *p;
7831
7832 argbackq = arg->narg.backquote;
7833 STARTSTACKSTR(expdest);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02007834 TRACE(("expandarg: argstr('%s',flags:%x)\n", arg->narg.text, flag));
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02007835 argstr(arg->narg.text, flag);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007836 p = _STPUTC('\0', expdest);
7837 expdest = p - 1;
7838 if (arglist == NULL) {
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02007839 /* here document expanded */
7840 goto out;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007841 }
7842 p = grabstackstr(p);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02007843 TRACE(("expandarg: p:'%s'\n", p));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007844 exparg.lastp = &exparg.list;
7845 /*
7846 * TODO - EXP_REDIR
7847 */
7848 if (flag & EXP_FULL) {
7849 ifsbreakup(p, &exparg);
7850 *exparg.lastp = NULL;
7851 exparg.lastp = &exparg.list;
Denis Vlasenko68404f12008-03-17 09:00:54 +00007852 expandmeta(exparg.list /*, flag*/);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007853 } else {
Denis Vlasenko597906c2008-02-20 16:38:54 +00007854 sp = stzalloc(sizeof(*sp));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007855 sp->text = p;
7856 *exparg.lastp = sp;
7857 exparg.lastp = &sp->next;
7858 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007859 *exparg.lastp = NULL;
7860 if (exparg.list) {
7861 *arglist->lastp = exparg.list;
7862 arglist->lastp = exparg.lastp;
7863 }
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02007864
7865 out:
7866 ifsfree();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007867}
7868
7869/*
7870 * Expand shell variables and backquotes inside a here document.
7871 */
7872static void
7873expandhere(union node *arg, int fd)
7874{
Ron Yorston549deab2015-05-18 09:57:51 +02007875 expandarg(arg, (struct arglist *)NULL, EXP_QUOTED);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007876 full_write(fd, stackblock(), expdest - (char *)stackblock());
7877}
7878
7879/*
7880 * Returns true if the pattern matches the string.
7881 */
7882static int
7883patmatch(char *pattern, const char *string)
7884{
Denys Vlasenkobd43c672017-07-05 23:12:15 +02007885 char *p = preglob(pattern, 0);
Denys Vlasenko4476c702017-08-15 15:27:41 +02007886 int r = pmatch(p, string);
7887 //bb_error_msg("!fnmatch(pattern:'%s',str:'%s',0):%d", p, string, r);
7888 return r;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007889}
7890
7891/*
7892 * See if a pattern matches in a case statement.
7893 */
7894static int
7895casematch(union node *pattern, char *val)
7896{
7897 struct stackmark smark;
7898 int result;
7899
7900 setstackmark(&smark);
7901 argbackq = pattern->narg.backquote;
7902 STARTSTACKSTR(expdest);
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02007903 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007904 STACKSTRNUL(expdest);
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02007905 ifsfree();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007906 result = patmatch(stackblock(), val);
7907 popstackmark(&smark);
7908 return result;
7909}
7910
7911
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007912/* ============ find_command */
7913
7914struct builtincmd {
7915 const char *name;
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02007916 int (*builtin)(int, char **) FAST_FUNC;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007917 /* unsigned flags; */
7918};
7919#define IS_BUILTIN_SPECIAL(b) ((b)->name[0] & 1)
Denis Vlasenkoe26b2782008-02-12 07:40:29 +00007920/* "regular" builtins always take precedence over commands,
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007921 * regardless of PATH=....%builtin... position */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007922#define IS_BUILTIN_REGULAR(b) ((b)->name[0] & 2)
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007923#define IS_BUILTIN_ASSIGN(b) ((b)->name[0] & 4)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007924
7925struct cmdentry {
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00007926 smallint cmdtype; /* CMDxxx */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007927 union param {
7928 int index;
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00007929 /* index >= 0 for commands without path (slashes) */
7930 /* (TODO: what exactly does the value mean? PATH position?) */
7931 /* index == -1 for commands with slashes */
7932 /* index == (-2 - applet_no) for NOFORK applets */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007933 const struct builtincmd *cmd;
7934 struct funcnode *func;
7935 } u;
7936};
7937/* values of cmdtype */
7938#define CMDUNKNOWN -1 /* no entry in table for command */
7939#define CMDNORMAL 0 /* command is an executable program */
7940#define CMDFUNCTION 1 /* command is a shell function */
7941#define CMDBUILTIN 2 /* command is a shell builtin */
7942
7943/* action to find_command() */
7944#define DO_ERR 0x01 /* prints errors */
7945#define DO_ABS 0x02 /* checks absolute paths */
7946#define DO_NOFUNC 0x04 /* don't return shell functions, for command */
7947#define DO_ALTPATH 0x08 /* using alternate path */
7948#define DO_ALTBLTIN 0x20 /* %builtin in alt. path */
7949
7950static void find_command(char *, struct cmdentry *, int, const char *);
7951
7952
7953/* ============ Hashing commands */
7954
7955/*
7956 * When commands are first encountered, they are entered in a hash table.
7957 * This ensures that a full path search will not have to be done for them
7958 * on each invocation.
7959 *
7960 * We should investigate converting to a linear search, even though that
7961 * would make the command name "hash" a misnomer.
7962 */
7963
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007964struct tblentry {
7965 struct tblentry *next; /* next entry in hash chain */
7966 union param param; /* definition of builtin function */
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00007967 smallint cmdtype; /* CMDxxx */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007968 char rehash; /* if set, cd done since entry created */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00007969 char cmdname[1]; /* name of command */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007970};
7971
Denis Vlasenko01631112007-12-16 17:20:38 +00007972static struct tblentry **cmdtable;
7973#define INIT_G_cmdtable() do { \
7974 cmdtable = xzalloc(CMDTABLESIZE * sizeof(cmdtable[0])); \
7975} while (0)
7976
7977static int builtinloc = -1; /* index in path of %builtin, or -1 */
7978
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007979
7980static void
Denys Vlasenko00a1dbd2017-07-29 01:20:53 +02007981tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) const char *cmd, char **argv, char **envp)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007982{
Denis Vlasenko80d14be2007-04-10 23:03:30 +00007983#if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007984 if (applet_no >= 0) {
Denis Vlasenkob7304742008-10-20 08:15:51 +00007985 if (APPLET_IS_NOEXEC(applet_no)) {
Denys Vlasenko7df28bb2010-06-18 14:23:47 +02007986 clearenv();
Denis Vlasenkob7304742008-10-20 08:15:51 +00007987 while (*envp)
7988 putenv(*envp++);
Denys Vlasenko035486c2017-07-31 04:09:19 +02007989 popredir(/*drop:*/ 1);
Denys Vlasenko80e8e3c2017-08-07 19:24:57 +02007990 run_noexec_applet_and_exit(applet_no, cmd, argv);
Denis Vlasenkob7304742008-10-20 08:15:51 +00007991 }
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007992 /* re-exec ourselves with the new arguments */
7993 execve(bb_busybox_exec_path, argv, envp);
7994 /* If they called chroot or otherwise made the binary no longer
7995 * executable, fall through */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007996 }
7997#endif
7998
7999 repeat:
8000#ifdef SYSV
8001 do {
8002 execve(cmd, argv, envp);
8003 } while (errno == EINTR);
8004#else
8005 execve(cmd, argv, envp);
8006#endif
Denys Vlasenko00a1dbd2017-07-29 01:20:53 +02008007 if (cmd != bb_busybox_exec_path && errno == ENOEXEC) {
Denys Vlasenkoaefe1c22011-03-07 12:02:40 +01008008 /* Run "cmd" as a shell script:
8009 * http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html
8010 * "If the execve() function fails with ENOEXEC, the shell
8011 * shall execute a command equivalent to having a shell invoked
8012 * with the command name as its first operand,
8013 * with any remaining arguments passed to the new shell"
8014 *
8015 * That is, do not use $SHELL, user's shell, or /bin/sh;
8016 * just call ourselves.
Denys Vlasenko2bef5262011-12-16 00:25:17 +01008017 *
8018 * Note that bash reads ~80 chars of the file, and if it sees
8019 * a zero byte before it sees newline, it doesn't try to
8020 * interpret it, but fails with "cannot execute binary file"
Denys Vlasenkocda6ea92011-12-16 00:44:36 +01008021 * message and exit code 126. For one, this prevents attempts
8022 * to interpret foreign ELF binaries as shell scripts.
Denys Vlasenkoaefe1c22011-03-07 12:02:40 +01008023 */
Denys Vlasenko00a1dbd2017-07-29 01:20:53 +02008024 argv[0] = (char*) cmd;
8025 cmd = bb_busybox_exec_path;
Denys Vlasenko65a8b852016-10-26 22:29:11 +02008026 /* NB: this is only possible because all callers of shellexec()
8027 * ensure that the argv[-1] slot exists!
8028 */
8029 argv--;
8030 argv[0] = (char*) "ash";
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008031 goto repeat;
8032 }
8033}
8034
8035/*
8036 * Exec a program. Never returns. If you change this routine, you may
8037 * have to change the find_command routine as well.
Denys Vlasenko65a8b852016-10-26 22:29:11 +02008038 * argv[-1] must exist and be writable! See tryexec() for why.
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008039 */
Denys Vlasenkoe139ae32017-04-12 21:02:33 +02008040static void shellexec(char *prog, char **argv, const char *path, int idx) NORETURN;
8041static void shellexec(char *prog, char **argv, const char *path, int idx)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008042{
8043 char *cmdname;
8044 int e;
8045 char **envp;
8046 int exerrno;
Denys Vlasenko83f103b2011-12-20 06:10:35 +01008047 int applet_no = -1; /* used only by FEATURE_SH_STANDALONE */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008048
Denys Vlasenkoa5060b82017-11-03 14:16:25 +01008049 envp = listvars(VEXPORT, VUNSET, /*strlist:*/ NULL, /*end:*/ NULL);
Denys Vlasenkoe139ae32017-04-12 21:02:33 +02008050 if (strchr(prog, '/') != NULL
Denis Vlasenko80d14be2007-04-10 23:03:30 +00008051#if ENABLE_FEATURE_SH_STANDALONE
Denys Vlasenkoe139ae32017-04-12 21:02:33 +02008052 || (applet_no = find_applet_by_name(prog)) >= 0
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008053#endif
8054 ) {
Denys Vlasenkoe139ae32017-04-12 21:02:33 +02008055 tryexec(IF_FEATURE_SH_STANDALONE(applet_no,) prog, argv, envp);
Denys Vlasenko83f103b2011-12-20 06:10:35 +01008056 if (applet_no >= 0) {
8057 /* We tried execing ourself, but it didn't work.
8058 * Maybe /proc/self/exe doesn't exist?
8059 * Try $PATH search.
8060 */
8061 goto try_PATH;
8062 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008063 e = errno;
8064 } else {
Denys Vlasenko83f103b2011-12-20 06:10:35 +01008065 try_PATH:
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008066 e = ENOENT;
Denys Vlasenkoe139ae32017-04-12 21:02:33 +02008067 while ((cmdname = path_advance(&path, prog)) != NULL) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008068 if (--idx < 0 && pathopt == NULL) {
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00008069 tryexec(IF_FEATURE_SH_STANDALONE(-1,) cmdname, argv, envp);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008070 if (errno != ENOENT && errno != ENOTDIR)
8071 e = errno;
8072 }
8073 stunalloc(cmdname);
8074 }
8075 }
8076
8077 /* Map to POSIX errors */
8078 switch (e) {
8079 case EACCES:
8080 exerrno = 126;
8081 break;
8082 case ENOENT:
8083 exerrno = 127;
8084 break;
8085 default:
8086 exerrno = 2;
8087 break;
8088 }
8089 exitstatus = exerrno;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02008090 TRACE(("shellexec failed for %s, errno %d, suppress_int %d\n",
Denys Vlasenkoe139ae32017-04-12 21:02:33 +02008091 prog, e, suppress_int));
8092 ash_msg_and_raise(EXEXIT, "%s: %s", prog, errmsg(e, "not found"));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008093 /* NOTREACHED */
8094}
8095
8096static void
8097printentry(struct tblentry *cmdp)
8098{
8099 int idx;
8100 const char *path;
8101 char *name;
8102
8103 idx = cmdp->param.index;
8104 path = pathval();
8105 do {
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02008106 name = path_advance(&path, cmdp->cmdname);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008107 stunalloc(name);
8108 } while (--idx >= 0);
8109 out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr));
8110}
8111
8112/*
8113 * Clear out command entries. The argument specifies the first entry in
8114 * PATH which has changed.
8115 */
8116static void
8117clearcmdentry(int firstchange)
8118{
8119 struct tblentry **tblp;
8120 struct tblentry **pp;
8121 struct tblentry *cmdp;
8122
8123 INT_OFF;
8124 for (tblp = cmdtable; tblp < &cmdtable[CMDTABLESIZE]; tblp++) {
8125 pp = tblp;
8126 while ((cmdp = *pp) != NULL) {
8127 if ((cmdp->cmdtype == CMDNORMAL &&
8128 cmdp->param.index >= firstchange)
8129 || (cmdp->cmdtype == CMDBUILTIN &&
8130 builtinloc >= firstchange)
8131 ) {
8132 *pp = cmdp->next;
8133 free(cmdp);
8134 } else {
8135 pp = &cmdp->next;
8136 }
8137 }
8138 }
8139 INT_ON;
8140}
8141
8142/*
8143 * Locate a command in the command hash table. If "add" is nonzero,
8144 * add the command to the table if it is not already present. The
8145 * variable "lastcmdentry" is set to point to the address of the link
8146 * pointing to the entry, so that delete_cmd_entry can delete the
8147 * entry.
8148 *
8149 * Interrupts must be off if called with add != 0.
8150 */
8151static struct tblentry **lastcmdentry;
8152
8153static struct tblentry *
8154cmdlookup(const char *name, int add)
8155{
8156 unsigned int hashval;
8157 const char *p;
8158 struct tblentry *cmdp;
8159 struct tblentry **pp;
8160
8161 p = name;
8162 hashval = (unsigned char)*p << 4;
8163 while (*p)
8164 hashval += (unsigned char)*p++;
8165 hashval &= 0x7FFF;
8166 pp = &cmdtable[hashval % CMDTABLESIZE];
8167 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
8168 if (strcmp(cmdp->cmdname, name) == 0)
8169 break;
8170 pp = &cmdp->next;
8171 }
8172 if (add && cmdp == NULL) {
Denis Vlasenkob07a4962008-06-22 13:16:23 +00008173 cmdp = *pp = ckzalloc(sizeof(struct tblentry)
8174 + strlen(name)
8175 /* + 1 - already done because
8176 * tblentry::cmdname is char[1] */);
Denis Vlasenko597906c2008-02-20 16:38:54 +00008177 /*cmdp->next = NULL; - ckzalloc did it */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008178 cmdp->cmdtype = CMDUNKNOWN;
8179 strcpy(cmdp->cmdname, name);
8180 }
8181 lastcmdentry = pp;
8182 return cmdp;
8183}
8184
8185/*
8186 * Delete the command entry returned on the last lookup.
8187 */
8188static void
8189delete_cmd_entry(void)
8190{
8191 struct tblentry *cmdp;
8192
8193 INT_OFF;
8194 cmdp = *lastcmdentry;
8195 *lastcmdentry = cmdp->next;
8196 if (cmdp->cmdtype == CMDFUNCTION)
8197 freefunc(cmdp->param.func);
8198 free(cmdp);
8199 INT_ON;
8200}
8201
8202/*
8203 * Add a new command entry, replacing any existing command entry for
8204 * the same name - except special builtins.
8205 */
8206static void
8207addcmdentry(char *name, struct cmdentry *entry)
8208{
8209 struct tblentry *cmdp;
8210
8211 cmdp = cmdlookup(name, 1);
8212 if (cmdp->cmdtype == CMDFUNCTION) {
8213 freefunc(cmdp->param.func);
8214 }
8215 cmdp->cmdtype = entry->cmdtype;
8216 cmdp->param = entry->u;
8217 cmdp->rehash = 0;
8218}
8219
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02008220static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00008221hashcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008222{
8223 struct tblentry **pp;
8224 struct tblentry *cmdp;
8225 int c;
8226 struct cmdentry entry;
8227 char *name;
8228
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008229 if (nextopt("r") != '\0') {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008230 clearcmdentry(0);
8231 return 0;
8232 }
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008233
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008234 if (*argptr == NULL) {
8235 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
8236 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
8237 if (cmdp->cmdtype == CMDNORMAL)
8238 printentry(cmdp);
8239 }
8240 }
8241 return 0;
8242 }
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008243
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008244 c = 0;
8245 while ((name = *argptr) != NULL) {
8246 cmdp = cmdlookup(name, 0);
8247 if (cmdp != NULL
8248 && (cmdp->cmdtype == CMDNORMAL
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008249 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))
8250 ) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008251 delete_cmd_entry();
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008252 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008253 find_command(name, &entry, DO_ERR, pathval());
8254 if (entry.cmdtype == CMDUNKNOWN)
8255 c = 1;
8256 argptr++;
8257 }
8258 return c;
8259}
8260
8261/*
8262 * Called when a cd is done. Marks all commands so the next time they
8263 * are executed they will be rehashed.
8264 */
8265static void
8266hashcd(void)
8267{
8268 struct tblentry **pp;
8269 struct tblentry *cmdp;
8270
8271 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
8272 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008273 if (cmdp->cmdtype == CMDNORMAL
8274 || (cmdp->cmdtype == CMDBUILTIN
Denys Vlasenkoe4dcba12010-10-28 18:57:19 +02008275 && !IS_BUILTIN_REGULAR(cmdp->param.cmd)
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008276 && builtinloc > 0)
8277 ) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008278 cmdp->rehash = 1;
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008279 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008280 }
8281 }
8282}
8283
8284/*
8285 * Fix command hash table when PATH changed.
8286 * Called before PATH is changed. The argument is the new value of PATH;
8287 * pathval() still returns the old value at this point.
8288 * Called with interrupts off.
8289 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02008290static void FAST_FUNC
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008291changepath(const char *new)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008292{
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008293 const char *old;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008294 int firstchange;
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008295 int idx;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008296 int idx_bltin;
8297
8298 old = pathval();
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008299 firstchange = 9999; /* assume no change */
8300 idx = 0;
8301 idx_bltin = -1;
8302 for (;;) {
8303 if (*old != *new) {
8304 firstchange = idx;
8305 if ((*old == '\0' && *new == ':')
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +02008306 || (*old == ':' && *new == '\0')
8307 ) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008308 firstchange++;
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +02008309 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008310 old = new; /* ignore subsequent differences */
8311 }
8312 if (*new == '\0')
8313 break;
8314 if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin"))
8315 idx_bltin = idx;
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008316 if (*new == ':')
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008317 idx++;
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +02008318 new++;
8319 old++;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008320 }
8321 if (builtinloc < 0 && idx_bltin >= 0)
8322 builtinloc = idx_bltin; /* zap builtins */
8323 if (builtinloc >= 0 && idx_bltin < 0)
8324 firstchange = 0;
8325 clearcmdentry(firstchange);
8326 builtinloc = idx_bltin;
8327}
Ron Yorston95ebcf72015-11-03 09:42:23 +00008328enum {
8329 TEOF,
8330 TNL,
8331 TREDIR,
8332 TWORD,
8333 TSEMI,
8334 TBACKGND,
8335 TAND,
8336 TOR,
8337 TPIPE,
8338 TLP,
8339 TRP,
8340 TENDCASE,
8341 TENDBQUOTE,
8342 TNOT,
8343 TCASE,
8344 TDO,
8345 TDONE,
8346 TELIF,
8347 TELSE,
8348 TESAC,
8349 TFI,
8350 TFOR,
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01008351#if BASH_FUNCTION
Ron Yorston95ebcf72015-11-03 09:42:23 +00008352 TFUNCTION,
8353#endif
8354 TIF,
8355 TIN,
8356 TTHEN,
8357 TUNTIL,
8358 TWHILE,
8359 TBEGIN,
8360 TEND
8361};
Denis Vlasenkob07a4962008-06-22 13:16:23 +00008362typedef smallint token_id_t;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008363
Denys Vlasenko888527c2016-10-02 16:54:17 +02008364/* Nth bit indicates if token marks the end of a list */
8365enum {
8366 tokendlist = 0
8367 /* 0 */ | (1u << TEOF)
8368 /* 1 */ | (0u << TNL)
8369 /* 2 */ | (0u << TREDIR)
8370 /* 3 */ | (0u << TWORD)
8371 /* 4 */ | (0u << TSEMI)
8372 /* 5 */ | (0u << TBACKGND)
8373 /* 6 */ | (0u << TAND)
8374 /* 7 */ | (0u << TOR)
8375 /* 8 */ | (0u << TPIPE)
8376 /* 9 */ | (0u << TLP)
8377 /* 10 */ | (1u << TRP)
8378 /* 11 */ | (1u << TENDCASE)
8379 /* 12 */ | (1u << TENDBQUOTE)
8380 /* 13 */ | (0u << TNOT)
8381 /* 14 */ | (0u << TCASE)
8382 /* 15 */ | (1u << TDO)
8383 /* 16 */ | (1u << TDONE)
8384 /* 17 */ | (1u << TELIF)
8385 /* 18 */ | (1u << TELSE)
8386 /* 19 */ | (1u << TESAC)
8387 /* 20 */ | (1u << TFI)
8388 /* 21 */ | (0u << TFOR)
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01008389#if BASH_FUNCTION
Denys Vlasenko888527c2016-10-02 16:54:17 +02008390 /* 22 */ | (0u << TFUNCTION)
Denys Vlasenko80729a42016-10-02 22:33:15 +02008391#endif
Denys Vlasenko888527c2016-10-02 16:54:17 +02008392 /* 23 */ | (0u << TIF)
8393 /* 24 */ | (0u << TIN)
8394 /* 25 */ | (1u << TTHEN)
8395 /* 26 */ | (0u << TUNTIL)
8396 /* 27 */ | (0u << TWHILE)
8397 /* 28 */ | (0u << TBEGIN)
8398 /* 29 */ | (1u << TEND)
8399 , /* thus far 29 bits used */
8400};
8401
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008402static const char *const tokname_array[] = {
Denys Vlasenko888527c2016-10-02 16:54:17 +02008403 "end of file",
8404 "newline",
8405 "redirection",
8406 "word",
8407 ";",
8408 "&",
8409 "&&",
8410 "||",
8411 "|",
8412 "(",
8413 ")",
8414 ";;",
8415 "`",
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008416#define KWDOFFSET 13
8417 /* the following are keywords */
Denys Vlasenko888527c2016-10-02 16:54:17 +02008418 "!",
8419 "case",
8420 "do",
8421 "done",
8422 "elif",
8423 "else",
8424 "esac",
8425 "fi",
8426 "for",
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01008427#if BASH_FUNCTION
Denys Vlasenko888527c2016-10-02 16:54:17 +02008428 "function",
Ron Yorston95ebcf72015-11-03 09:42:23 +00008429#endif
Denys Vlasenko888527c2016-10-02 16:54:17 +02008430 "if",
8431 "in",
8432 "then",
8433 "until",
8434 "while",
8435 "{",
8436 "}",
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008437};
8438
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008439/* Wrapper around strcmp for qsort/bsearch/... */
8440static int
8441pstrcmp(const void *a, const void *b)
8442{
Denys Vlasenko888527c2016-10-02 16:54:17 +02008443 return strcmp((char*)a, *(char**)b);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008444}
8445
8446static const char *const *
8447findkwd(const char *s)
8448{
8449 return bsearch(s, tokname_array + KWDOFFSET,
Denis Vlasenko80b8b392007-06-25 10:55:35 +00008450 ARRAY_SIZE(tokname_array) - KWDOFFSET,
8451 sizeof(tokname_array[0]), pstrcmp);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008452}
8453
8454/*
8455 * Locate and print what a word is...
8456 */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008457static int
Ron Yorston3f221112015-08-03 13:47:33 +01008458describe_command(char *command, const char *path, int describe_command_verbose)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008459{
8460 struct cmdentry entry;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008461#if ENABLE_ASH_ALIAS
8462 const struct alias *ap;
8463#endif
Ron Yorston3f221112015-08-03 13:47:33 +01008464
8465 path = path ? path : pathval();
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008466
8467 if (describe_command_verbose) {
8468 out1str(command);
8469 }
8470
8471 /* First look at the keywords */
8472 if (findkwd(command)) {
8473 out1str(describe_command_verbose ? " is a shell keyword" : command);
8474 goto out;
8475 }
8476
8477#if ENABLE_ASH_ALIAS
8478 /* Then look at the aliases */
8479 ap = lookupalias(command, 0);
8480 if (ap != NULL) {
Denis Vlasenko46846e22007-05-20 13:08:31 +00008481 if (!describe_command_verbose) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008482 out1str("alias ");
8483 printalias(ap);
8484 return 0;
8485 }
Denis Vlasenko46846e22007-05-20 13:08:31 +00008486 out1fmt(" is an alias for %s", ap->val);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008487 goto out;
8488 }
8489#endif
Youfu Zhang6683d1c2017-05-26 15:31:29 +08008490 /* Brute force */
8491 find_command(command, &entry, DO_ABS, path);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008492
8493 switch (entry.cmdtype) {
8494 case CMDNORMAL: {
8495 int j = entry.u.index;
8496 char *p;
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00008497 if (j < 0) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008498 p = command;
8499 } else {
8500 do {
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02008501 p = path_advance(&path, command);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008502 stunalloc(p);
8503 } while (--j >= 0);
8504 }
8505 if (describe_command_verbose) {
Youfu Zhang6683d1c2017-05-26 15:31:29 +08008506 out1fmt(" is %s", p);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008507 } else {
8508 out1str(p);
8509 }
8510 break;
8511 }
8512
8513 case CMDFUNCTION:
8514 if (describe_command_verbose) {
8515 out1str(" is a shell function");
8516 } else {
8517 out1str(command);
8518 }
8519 break;
8520
8521 case CMDBUILTIN:
8522 if (describe_command_verbose) {
8523 out1fmt(" is a %sshell builtin",
8524 IS_BUILTIN_SPECIAL(entry.u.cmd) ?
8525 "special " : nullstr
8526 );
8527 } else {
8528 out1str(command);
8529 }
8530 break;
8531
8532 default:
8533 if (describe_command_verbose) {
8534 out1str(": not found\n");
8535 }
8536 return 127;
8537 }
8538 out:
Denys Vlasenko285ad152009-12-04 23:02:27 +01008539 out1str("\n");
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008540 return 0;
8541}
8542
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02008543static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00008544typecmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008545{
Denis Vlasenko46846e22007-05-20 13:08:31 +00008546 int i = 1;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008547 int err = 0;
Denis Vlasenko46846e22007-05-20 13:08:31 +00008548 int verbose = 1;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008549
Denis Vlasenko46846e22007-05-20 13:08:31 +00008550 /* type -p ... ? (we don't bother checking for 'p') */
Denis Vlasenko1fc62382007-06-25 22:55:34 +00008551 if (argv[1] && argv[1][0] == '-') {
Denis Vlasenko46846e22007-05-20 13:08:31 +00008552 i++;
8553 verbose = 0;
8554 }
Denis Vlasenko68404f12008-03-17 09:00:54 +00008555 while (argv[i]) {
Ron Yorston3f221112015-08-03 13:47:33 +01008556 err |= describe_command(argv[i++], NULL, verbose);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008557 }
8558 return err;
8559}
8560
8561#if ENABLE_ASH_CMDCMD
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008562/* Is it "command [-p] PROG ARGS" bltin, no other opts? Return ptr to "PROG" if yes */
8563static char **
8564parse_command_args(char **argv, const char **path)
8565{
8566 char *cp, c;
8567
8568 for (;;) {
8569 cp = *++argv;
8570 if (!cp)
8571 return NULL;
8572 if (*cp++ != '-')
8573 break;
8574 c = *cp++;
8575 if (!c)
8576 break;
8577 if (c == '-' && !*cp) {
8578 if (!*++argv)
8579 return NULL;
8580 break;
8581 }
8582 do {
8583 switch (c) {
8584 case 'p':
8585 *path = bb_default_path;
8586 break;
8587 default:
8588 /* run 'typecmd' for other options */
8589 return NULL;
8590 }
8591 c = *cp++;
8592 } while (c);
8593 }
8594 return argv;
8595}
8596
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02008597static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00008598commandcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008599{
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008600 char *cmd;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008601 int c;
8602 enum {
8603 VERIFY_BRIEF = 1,
8604 VERIFY_VERBOSE = 2,
8605 } verify = 0;
Ron Yorston3f221112015-08-03 13:47:33 +01008606 const char *path = NULL;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008607
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008608 /* "command [-p] PROG ARGS" (that is, without -V or -v)
8609 * never reaches this function.
8610 */
8611
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008612 while ((c = nextopt("pvV")) != '\0')
8613 if (c == 'V')
8614 verify |= VERIFY_VERBOSE;
8615 else if (c == 'v')
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008616 /*verify |= VERIFY_BRIEF*/;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008617#if DEBUG
8618 else if (c != 'p')
8619 abort();
8620#endif
Ron Yorston3f221112015-08-03 13:47:33 +01008621 else
8622 path = bb_default_path;
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008623
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00008624 /* Mimic bash: just "command -v" doesn't complain, it's a nop */
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008625 cmd = *argptr;
8626 if (/*verify && */ cmd)
8627 return describe_command(cmd, path, verify /* - VERIFY_BRIEF*/);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008628
8629 return 0;
8630}
8631#endif
8632
8633
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008634/*static int funcblocksize; // size of structures in function */
8635/*static int funcstringsize; // size of strings in node */
Denis Vlasenko340299a2008-11-21 10:36:36 +00008636static void *funcblock; /* block to allocate function from */
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008637static char *funcstring_end; /* end of block to allocate strings from */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008638
Denys Vlasenko3e134eb2016-04-22 18:09:21 +02008639static const uint8_t nodesize[N_NUMBER] ALIGN1 = {
Denis Vlasenko340299a2008-11-21 10:36:36 +00008640 [NCMD ] = SHELL_ALIGN(sizeof(struct ncmd)),
8641 [NPIPE ] = SHELL_ALIGN(sizeof(struct npipe)),
8642 [NREDIR ] = SHELL_ALIGN(sizeof(struct nredir)),
8643 [NBACKGND ] = SHELL_ALIGN(sizeof(struct nredir)),
8644 [NSUBSHELL] = SHELL_ALIGN(sizeof(struct nredir)),
8645 [NAND ] = SHELL_ALIGN(sizeof(struct nbinary)),
8646 [NOR ] = SHELL_ALIGN(sizeof(struct nbinary)),
8647 [NSEMI ] = SHELL_ALIGN(sizeof(struct nbinary)),
8648 [NIF ] = SHELL_ALIGN(sizeof(struct nif)),
8649 [NWHILE ] = SHELL_ALIGN(sizeof(struct nbinary)),
8650 [NUNTIL ] = SHELL_ALIGN(sizeof(struct nbinary)),
8651 [NFOR ] = SHELL_ALIGN(sizeof(struct nfor)),
8652 [NCASE ] = SHELL_ALIGN(sizeof(struct ncase)),
8653 [NCLIST ] = SHELL_ALIGN(sizeof(struct nclist)),
8654 [NDEFUN ] = SHELL_ALIGN(sizeof(struct narg)),
8655 [NARG ] = SHELL_ALIGN(sizeof(struct narg)),
8656 [NTO ] = SHELL_ALIGN(sizeof(struct nfile)),
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01008657#if BASH_REDIR_OUTPUT
Denis Vlasenko340299a2008-11-21 10:36:36 +00008658 [NTO2 ] = SHELL_ALIGN(sizeof(struct nfile)),
Denis Vlasenkocc5feab2008-11-22 01:32:40 +00008659#endif
Denis Vlasenko340299a2008-11-21 10:36:36 +00008660 [NCLOBBER ] = SHELL_ALIGN(sizeof(struct nfile)),
8661 [NFROM ] = SHELL_ALIGN(sizeof(struct nfile)),
8662 [NFROMTO ] = SHELL_ALIGN(sizeof(struct nfile)),
8663 [NAPPEND ] = SHELL_ALIGN(sizeof(struct nfile)),
8664 [NTOFD ] = SHELL_ALIGN(sizeof(struct ndup)),
8665 [NFROMFD ] = SHELL_ALIGN(sizeof(struct ndup)),
8666 [NHERE ] = SHELL_ALIGN(sizeof(struct nhere)),
8667 [NXHERE ] = SHELL_ALIGN(sizeof(struct nhere)),
8668 [NNOT ] = SHELL_ALIGN(sizeof(struct nnot)),
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008669};
8670
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008671static int calcsize(int funcblocksize, union node *n);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008672
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008673static int
8674sizenodelist(int funcblocksize, struct nodelist *lp)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008675{
8676 while (lp) {
8677 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008678 funcblocksize = calcsize(funcblocksize, lp->n);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008679 lp = lp->next;
8680 }
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008681 return funcblocksize;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008682}
8683
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008684static int
8685calcsize(int funcblocksize, union node *n)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008686{
8687 if (n == NULL)
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008688 return funcblocksize;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008689 funcblocksize += nodesize[n->type];
8690 switch (n->type) {
8691 case NCMD:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008692 funcblocksize = calcsize(funcblocksize, n->ncmd.redirect);
8693 funcblocksize = calcsize(funcblocksize, n->ncmd.args);
8694 funcblocksize = calcsize(funcblocksize, n->ncmd.assign);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008695 break;
8696 case NPIPE:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008697 funcblocksize = sizenodelist(funcblocksize, n->npipe.cmdlist);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008698 break;
8699 case NREDIR:
8700 case NBACKGND:
8701 case NSUBSHELL:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008702 funcblocksize = calcsize(funcblocksize, n->nredir.redirect);
8703 funcblocksize = calcsize(funcblocksize, n->nredir.n);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008704 break;
8705 case NAND:
8706 case NOR:
8707 case NSEMI:
8708 case NWHILE:
8709 case NUNTIL:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008710 funcblocksize = calcsize(funcblocksize, n->nbinary.ch2);
8711 funcblocksize = calcsize(funcblocksize, n->nbinary.ch1);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008712 break;
8713 case NIF:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008714 funcblocksize = calcsize(funcblocksize, n->nif.elsepart);
8715 funcblocksize = calcsize(funcblocksize, n->nif.ifpart);
8716 funcblocksize = calcsize(funcblocksize, n->nif.test);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008717 break;
8718 case NFOR:
Denys Vlasenko561639a2016-10-07 04:28:33 +02008719 funcblocksize += SHELL_ALIGN(strlen(n->nfor.var) + 1); /* was funcstringsize += ... */
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008720 funcblocksize = calcsize(funcblocksize, n->nfor.body);
8721 funcblocksize = calcsize(funcblocksize, n->nfor.args);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008722 break;
8723 case NCASE:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008724 funcblocksize = calcsize(funcblocksize, n->ncase.cases);
8725 funcblocksize = calcsize(funcblocksize, n->ncase.expr);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008726 break;
8727 case NCLIST:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008728 funcblocksize = calcsize(funcblocksize, n->nclist.body);
8729 funcblocksize = calcsize(funcblocksize, n->nclist.pattern);
8730 funcblocksize = calcsize(funcblocksize, n->nclist.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008731 break;
8732 case NDEFUN:
Denys Vlasenko675d24a2018-01-27 22:02:05 +01008733 funcblocksize = calcsize(funcblocksize, n->ndefun.body);
8734 funcblocksize += SHELL_ALIGN(strlen(n->ndefun.text) + 1);
8735 break;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008736 case NARG:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008737 funcblocksize = sizenodelist(funcblocksize, n->narg.backquote);
Denys Vlasenko561639a2016-10-07 04:28:33 +02008738 funcblocksize += SHELL_ALIGN(strlen(n->narg.text) + 1); /* was funcstringsize += ... */
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008739 funcblocksize = calcsize(funcblocksize, n->narg.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008740 break;
8741 case NTO:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01008742#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00008743 case NTO2:
8744#endif
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008745 case NCLOBBER:
8746 case NFROM:
8747 case NFROMTO:
8748 case NAPPEND:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008749 funcblocksize = calcsize(funcblocksize, n->nfile.fname);
8750 funcblocksize = calcsize(funcblocksize, n->nfile.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008751 break;
8752 case NTOFD:
8753 case NFROMFD:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008754 funcblocksize = calcsize(funcblocksize, n->ndup.vname);
8755 funcblocksize = calcsize(funcblocksize, n->ndup.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008756 break;
8757 case NHERE:
8758 case NXHERE:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008759 funcblocksize = calcsize(funcblocksize, n->nhere.doc);
8760 funcblocksize = calcsize(funcblocksize, n->nhere.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008761 break;
8762 case NNOT:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008763 funcblocksize = calcsize(funcblocksize, n->nnot.com);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008764 break;
8765 };
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008766 return funcblocksize;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008767}
8768
8769static char *
8770nodeckstrdup(char *s)
8771{
Denys Vlasenko561639a2016-10-07 04:28:33 +02008772 funcstring_end -= SHELL_ALIGN(strlen(s) + 1);
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008773 return strcpy(funcstring_end, s);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008774}
8775
8776static union node *copynode(union node *);
8777
8778static struct nodelist *
8779copynodelist(struct nodelist *lp)
8780{
8781 struct nodelist *start;
8782 struct nodelist **lpp;
8783
8784 lpp = &start;
8785 while (lp) {
8786 *lpp = funcblock;
8787 funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist));
8788 (*lpp)->n = copynode(lp->n);
8789 lp = lp->next;
8790 lpp = &(*lpp)->next;
8791 }
8792 *lpp = NULL;
8793 return start;
8794}
8795
8796static union node *
8797copynode(union node *n)
8798{
8799 union node *new;
8800
8801 if (n == NULL)
8802 return NULL;
8803 new = funcblock;
8804 funcblock = (char *) funcblock + nodesize[n->type];
8805
8806 switch (n->type) {
8807 case NCMD:
8808 new->ncmd.redirect = copynode(n->ncmd.redirect);
8809 new->ncmd.args = copynode(n->ncmd.args);
8810 new->ncmd.assign = copynode(n->ncmd.assign);
Denys Vlasenko675d24a2018-01-27 22:02:05 +01008811 new->ncmd.linno = n->ncmd.linno;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008812 break;
8813 case NPIPE:
8814 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00008815 new->npipe.pipe_backgnd = n->npipe.pipe_backgnd;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008816 break;
8817 case NREDIR:
8818 case NBACKGND:
8819 case NSUBSHELL:
8820 new->nredir.redirect = copynode(n->nredir.redirect);
8821 new->nredir.n = copynode(n->nredir.n);
Denys Vlasenko675d24a2018-01-27 22:02:05 +01008822 new->nredir.linno = n->nredir.linno;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008823 break;
8824 case NAND:
8825 case NOR:
8826 case NSEMI:
8827 case NWHILE:
8828 case NUNTIL:
8829 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8830 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8831 break;
8832 case NIF:
8833 new->nif.elsepart = copynode(n->nif.elsepart);
8834 new->nif.ifpart = copynode(n->nif.ifpart);
8835 new->nif.test = copynode(n->nif.test);
8836 break;
8837 case NFOR:
8838 new->nfor.var = nodeckstrdup(n->nfor.var);
8839 new->nfor.body = copynode(n->nfor.body);
8840 new->nfor.args = copynode(n->nfor.args);
Denys Vlasenko675d24a2018-01-27 22:02:05 +01008841 new->nfor.linno = n->nfor.linno;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008842 break;
8843 case NCASE:
8844 new->ncase.cases = copynode(n->ncase.cases);
8845 new->ncase.expr = copynode(n->ncase.expr);
Denys Vlasenko675d24a2018-01-27 22:02:05 +01008846 new->ncase.linno = n->ncase.linno;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008847 break;
8848 case NCLIST:
8849 new->nclist.body = copynode(n->nclist.body);
8850 new->nclist.pattern = copynode(n->nclist.pattern);
8851 new->nclist.next = copynode(n->nclist.next);
8852 break;
8853 case NDEFUN:
Denys Vlasenko675d24a2018-01-27 22:02:05 +01008854 new->ndefun.body = copynode(n->ndefun.body);
8855 new->ndefun.text = nodeckstrdup(n->ndefun.text);
8856 new->ndefun.linno = n->ndefun.linno;
8857 break;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008858 case NARG:
8859 new->narg.backquote = copynodelist(n->narg.backquote);
8860 new->narg.text = nodeckstrdup(n->narg.text);
8861 new->narg.next = copynode(n->narg.next);
8862 break;
8863 case NTO:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01008864#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00008865 case NTO2:
8866#endif
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008867 case NCLOBBER:
8868 case NFROM:
8869 case NFROMTO:
8870 case NAPPEND:
8871 new->nfile.fname = copynode(n->nfile.fname);
8872 new->nfile.fd = n->nfile.fd;
8873 new->nfile.next = copynode(n->nfile.next);
8874 break;
8875 case NTOFD:
8876 case NFROMFD:
8877 new->ndup.vname = copynode(n->ndup.vname);
8878 new->ndup.dupfd = n->ndup.dupfd;
8879 new->ndup.fd = n->ndup.fd;
8880 new->ndup.next = copynode(n->ndup.next);
8881 break;
8882 case NHERE:
8883 case NXHERE:
8884 new->nhere.doc = copynode(n->nhere.doc);
8885 new->nhere.fd = n->nhere.fd;
8886 new->nhere.next = copynode(n->nhere.next);
8887 break;
8888 case NNOT:
8889 new->nnot.com = copynode(n->nnot.com);
8890 break;
8891 };
8892 new->type = n->type;
8893 return new;
8894}
8895
8896/*
8897 * Make a copy of a parse tree.
8898 */
8899static struct funcnode *
8900copyfunc(union node *n)
8901{
8902 struct funcnode *f;
8903 size_t blocksize;
8904
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008905 /*funcstringsize = 0;*/
8906 blocksize = offsetof(struct funcnode, n) + calcsize(0, n);
8907 f = ckzalloc(blocksize /* + funcstringsize */);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008908 funcblock = (char *) f + offsetof(struct funcnode, n);
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008909 funcstring_end = (char *) f + blocksize;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008910 copynode(n);
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008911 /* f->count = 0; - ckzalloc did it */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008912 return f;
8913}
8914
8915/*
8916 * Define a shell function.
8917 */
8918static void
Denys Vlasenko7aec8682016-10-25 20:26:02 +02008919defun(union node *func)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008920{
8921 struct cmdentry entry;
8922
8923 INT_OFF;
8924 entry.cmdtype = CMDFUNCTION;
8925 entry.u.func = copyfunc(func);
Denys Vlasenko675d24a2018-01-27 22:02:05 +01008926 addcmdentry(func->ndefun.text, &entry);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008927 INT_ON;
8928}
8929
Denis Vlasenko4b875702009-03-19 13:30:04 +00008930/* Reasons for skipping commands (see comment on breakcmd routine) */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008931#define SKIPBREAK (1 << 0)
8932#define SKIPCONT (1 << 1)
8933#define SKIPFUNC (1 << 2)
Denis Vlasenko4b875702009-03-19 13:30:04 +00008934static smallint evalskip; /* set to SKIPxxx if we are skipping commands */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008935static int skipcount; /* number of levels to skip */
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +00008936static int loopnest; /* current loop nesting level */
Denys Vlasenko675d24a2018-01-27 22:02:05 +01008937static int funcline; /* starting line number of current function, or 0 if not in a function */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008938
Denis Vlasenko4b875702009-03-19 13:30:04 +00008939/* Forward decl way out to parsing code - dotrap needs it */
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02008940static int evalstring(char *s, int flags);
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008941
Denis Vlasenko4b875702009-03-19 13:30:04 +00008942/* Called to execute a trap.
8943 * Single callsite - at the end of evaltree().
Denys Vlasenkob563f622010-09-25 17:15:13 +02008944 * If we return non-zero, evaltree raises EXEXIT exception.
Denis Vlasenko4b875702009-03-19 13:30:04 +00008945 *
8946 * Perhaps we should avoid entering new trap handlers
8947 * while we are executing a trap handler. [is it a TODO?]
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008948 */
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008949static void
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008950dotrap(void)
8951{
Denis Vlasenko4b875702009-03-19 13:30:04 +00008952 uint8_t *g;
8953 int sig;
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008954 uint8_t last_status;
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008955
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008956 if (!pending_sig)
8957 return;
8958
8959 last_status = exitstatus;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02008960 pending_sig = 0;
Denys Vlasenkode892052016-10-02 01:49:13 +02008961 barrier();
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008962
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008963 TRACE(("dotrap entered\n"));
Denis Vlasenko4b875702009-03-19 13:30:04 +00008964 for (sig = 1, g = gotsig; sig < NSIG; sig++, g++) {
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008965 char *p;
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008966
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008967 if (!*g)
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008968 continue;
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008969
8970 if (evalskip) {
8971 pending_sig = sig;
8972 break;
8973 }
8974
8975 p = trap[sig];
Denis Vlasenko4b875702009-03-19 13:30:04 +00008976 /* non-trapped SIGINT is handled separately by raise_interrupt,
8977 * don't upset it by resetting gotsig[SIGINT-1] */
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008978 if (sig == SIGINT && !p)
Denis Vlasenko4b875702009-03-19 13:30:04 +00008979 continue;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008980
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008981 TRACE(("sig %d is active, will run handler '%s'\n", sig, p));
Denis Vlasenko4b875702009-03-19 13:30:04 +00008982 *g = 0;
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008983 if (!p)
Denis Vlasenko4b875702009-03-19 13:30:04 +00008984 continue;
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008985 evalstring(p, 0);
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008986 }
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008987 exitstatus = last_status;
8988 TRACE(("dotrap returns\n"));
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008989}
8990
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00008991/* forward declarations - evaluation is fairly recursive business... */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008992static int evalloop(union node *, int);
8993static int evalfor(union node *, int);
8994static int evalcase(union node *, int);
8995static int evalsubshell(union node *, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008996static void expredir(union node *);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008997static int evalpipe(union node *, int);
8998static int evalcommand(union node *, int);
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02008999static int evalbltin(const struct builtincmd *, int, char **, int);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009000static void prehash(union node *);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009001
Eric Andersen62483552001-07-10 06:09:16 +00009002/*
Eric Andersenc470f442003-07-28 09:56:35 +00009003 * Evaluate a parse tree. The value is left in the global variable
9004 * exitstatus.
Eric Andersen62483552001-07-10 06:09:16 +00009005 */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009006static int
Eric Andersenc470f442003-07-28 09:56:35 +00009007evaltree(union node *n, int flags)
Eric Andersen62483552001-07-10 06:09:16 +00009008{
Eric Andersenc470f442003-07-28 09:56:35 +00009009 int checkexit = 0;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009010 int (*evalfn)(union node *, int);
9011 int status = 0;
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00009012
Eric Andersenc470f442003-07-28 09:56:35 +00009013 if (n == NULL) {
9014 TRACE(("evaltree(NULL) called\n"));
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02009015 goto out;
Eric Andersen62483552001-07-10 06:09:16 +00009016 }
Denis Vlasenko653d8e72009-03-19 21:59:35 +00009017 TRACE(("evaltree(%p: %d, %d) called\n", n, n->type, flags));
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00009018
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02009019 dotrap();
9020
Eric Andersenc470f442003-07-28 09:56:35 +00009021 switch (n->type) {
9022 default:
Denis Vlasenkoa7189f02006-11-17 20:29:00 +00009023#if DEBUG
Eric Andersenc470f442003-07-28 09:56:35 +00009024 out1fmt("Node type = %d\n", n->type);
Denys Vlasenko8131eea2009-11-02 14:19:51 +01009025 fflush_all();
Eric Andersenc470f442003-07-28 09:56:35 +00009026 break;
9027#endif
9028 case NNOT:
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009029 status = !evaltree(n->nnot.com, EV_TESTED);
Eric Andersenc470f442003-07-28 09:56:35 +00009030 goto setstatus;
9031 case NREDIR:
Denys Vlasenko675d24a2018-01-27 22:02:05 +01009032 errlinno = lineno = n->nredir.linno;
9033 if (funcline)
9034 lineno -= funcline - 1;
Eric Andersenc470f442003-07-28 09:56:35 +00009035 expredir(n->nredir.redirect);
Denys Vlasenko1c79aeb2017-07-29 22:51:52 +02009036 pushredir(n->nredir.redirect);
Eric Andersenc470f442003-07-28 09:56:35 +00009037 status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
9038 if (!status) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009039 status = evaltree(n->nredir.n, flags & EV_TESTED);
Eric Andersenc470f442003-07-28 09:56:35 +00009040 }
Denys Vlasenkoeaf94362016-10-25 21:46:03 +02009041 if (n->nredir.redirect)
Denys Vlasenko035486c2017-07-31 04:09:19 +02009042 popredir(/*drop:*/ 0);
Eric Andersenc470f442003-07-28 09:56:35 +00009043 goto setstatus;
9044 case NCMD:
9045 evalfn = evalcommand;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009046 checkexit:
Eric Andersenc470f442003-07-28 09:56:35 +00009047 if (eflag && !(flags & EV_TESTED))
9048 checkexit = ~0;
9049 goto calleval;
9050 case NFOR:
9051 evalfn = evalfor;
9052 goto calleval;
9053 case NWHILE:
9054 case NUNTIL:
9055 evalfn = evalloop;
9056 goto calleval;
9057 case NSUBSHELL:
9058 case NBACKGND:
9059 evalfn = evalsubshell;
Denys Vlasenkocf98b0c2016-10-25 18:19:39 +02009060 goto checkexit;
Eric Andersenc470f442003-07-28 09:56:35 +00009061 case NPIPE:
9062 evalfn = evalpipe;
9063 goto checkexit;
9064 case NCASE:
9065 evalfn = evalcase;
9066 goto calleval;
9067 case NAND:
9068 case NOR:
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00009069 case NSEMI: {
9070
Eric Andersenc470f442003-07-28 09:56:35 +00009071#if NAND + 1 != NOR
9072#error NAND + 1 != NOR
9073#endif
9074#if NOR + 1 != NSEMI
9075#error NOR + 1 != NSEMI
9076#endif
Denis Vlasenko87d5fd92008-07-26 13:48:35 +00009077 unsigned is_or = n->type - NAND;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009078 status = evaltree(
Eric Andersenc470f442003-07-28 09:56:35 +00009079 n->nbinary.ch1,
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00009080 (flags | ((is_or >> 1) - 1)) & EV_TESTED
Eric Andersenc470f442003-07-28 09:56:35 +00009081 );
Denys Vlasenkobc1a0082016-10-02 15:31:33 +02009082 if ((!status) == is_or || evalskip)
Eric Andersenc470f442003-07-28 09:56:35 +00009083 break;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009084 n = n->nbinary.ch2;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009085 evaln:
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009086 evalfn = evaltree;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009087 calleval:
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009088 status = evalfn(n, flags);
9089 goto setstatus;
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00009090 }
Eric Andersenc470f442003-07-28 09:56:35 +00009091 case NIF:
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009092 status = evaltree(n->nif.test, EV_TESTED);
Eric Andersenc470f442003-07-28 09:56:35 +00009093 if (evalskip)
9094 break;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009095 if (!status) {
Eric Andersenc470f442003-07-28 09:56:35 +00009096 n = n->nif.ifpart;
9097 goto evaln;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00009098 }
9099 if (n->nif.elsepart) {
Eric Andersenc470f442003-07-28 09:56:35 +00009100 n = n->nif.elsepart;
9101 goto evaln;
9102 }
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009103 status = 0;
9104 goto setstatus;
Eric Andersenc470f442003-07-28 09:56:35 +00009105 case NDEFUN:
Denys Vlasenko7aec8682016-10-25 20:26:02 +02009106 defun(n);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009107 /* Not necessary. To test it:
9108 * "false; f() { qwerty; }; echo $?" should print 0.
9109 */
9110 /* status = 0; */
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009111 setstatus:
Eric Andersenc470f442003-07-28 09:56:35 +00009112 exitstatus = status;
9113 break;
9114 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009115 out:
Denys Vlasenkob563f622010-09-25 17:15:13 +02009116 /* Order of checks below is important:
9117 * signal handlers trigger before exit caused by "set -e".
9118 */
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02009119 dotrap();
9120
9121 if (checkexit & status)
Denis Vlasenkob012b102007-02-19 22:43:01 +00009122 raise_exception(EXEXIT);
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02009123 if (flags & EV_EXIT)
9124 raise_exception(EXEXIT);
Denis Vlasenko653d8e72009-03-19 21:59:35 +00009125
Denis Vlasenko653d8e72009-03-19 21:59:35 +00009126 TRACE(("leaving evaltree (no interrupts)\n"));
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009127 return exitstatus;
Eric Andersen62483552001-07-10 06:09:16 +00009128}
9129
Denys Vlasenko37dc08b2016-10-02 04:38:07 +02009130static int
9131skiploop(void)
Denys Vlasenko35ec8182016-10-01 19:56:52 +02009132{
9133 int skip = evalskip;
9134
9135 switch (skip) {
9136 case 0:
9137 break;
9138 case SKIPBREAK:
9139 case SKIPCONT:
9140 if (--skipcount <= 0) {
9141 evalskip = 0;
9142 break;
9143 }
9144 skip = SKIPBREAK;
9145 break;
9146 }
9147 return skip;
9148}
9149
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009150static int
Eric Andersenc470f442003-07-28 09:56:35 +00009151evalloop(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00009152{
Denys Vlasenko35ec8182016-10-01 19:56:52 +02009153 int skip;
Eric Andersencb57d552001-06-28 07:25:16 +00009154 int status;
9155
9156 loopnest++;
9157 status = 0;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009158 flags &= EV_TESTED;
Denys Vlasenko35ec8182016-10-01 19:56:52 +02009159 do {
Eric Andersenc470f442003-07-28 09:56:35 +00009160 int i;
9161
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009162 i = evaltree(n->nbinary.ch1, EV_TESTED);
Denys Vlasenko35ec8182016-10-01 19:56:52 +02009163 skip = skiploop();
9164 if (skip == SKIPFUNC)
9165 status = i;
9166 if (skip)
9167 continue;
Eric Andersenc470f442003-07-28 09:56:35 +00009168 if (n->type != NWHILE)
9169 i = !i;
9170 if (i != 0)
9171 break;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009172 status = evaltree(n->nbinary.ch2, flags);
Denys Vlasenko35ec8182016-10-01 19:56:52 +02009173 skip = skiploop();
9174 } while (!(skip & ~SKIPCONT));
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009175 loopnest--;
9176
9177 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00009178}
9179
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009180static int
Eric Andersenc470f442003-07-28 09:56:35 +00009181evalfor(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00009182{
9183 struct arglist arglist;
9184 union node *argp;
9185 struct strlist *sp;
9186 struct stackmark smark;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009187 int status = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00009188
Denys Vlasenko675d24a2018-01-27 22:02:05 +01009189 errlinno = lineno = n->ncase.linno;
9190 if (funcline)
9191 lineno -= funcline - 1;
9192
Eric Andersencb57d552001-06-28 07:25:16 +00009193 setstackmark(&smark);
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00009194 arglist.list = NULL;
Eric Andersencb57d552001-06-28 07:25:16 +00009195 arglist.lastp = &arglist.list;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009196 for (argp = n->nfor.args; argp; argp = argp->narg.next) {
Ron Yorston549deab2015-05-18 09:57:51 +02009197 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
Eric Andersencb57d552001-06-28 07:25:16 +00009198 }
9199 *arglist.lastp = NULL;
9200
Eric Andersencb57d552001-06-28 07:25:16 +00009201 loopnest++;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009202 flags &= EV_TESTED;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009203 for (sp = arglist.list; sp; sp = sp->next) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009204 setvar0(n->nfor.var, sp->text);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009205 status = evaltree(n->nfor.body, flags);
Denys Vlasenko35ec8182016-10-01 19:56:52 +02009206 if (skiploop() & ~SKIPCONT)
Eric Andersencb57d552001-06-28 07:25:16 +00009207 break;
Eric Andersencb57d552001-06-28 07:25:16 +00009208 }
9209 loopnest--;
Eric Andersencb57d552001-06-28 07:25:16 +00009210 popstackmark(&smark);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009211
9212 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00009213}
9214
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009215static int
Eric Andersenc470f442003-07-28 09:56:35 +00009216evalcase(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00009217{
9218 union node *cp;
9219 union node *patp;
9220 struct arglist arglist;
9221 struct stackmark smark;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009222 int status = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00009223
Denys Vlasenko675d24a2018-01-27 22:02:05 +01009224 errlinno = lineno = n->ncase.linno;
9225 if (funcline)
9226 lineno -= funcline - 1;
9227
Eric Andersencb57d552001-06-28 07:25:16 +00009228 setstackmark(&smark);
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00009229 arglist.list = NULL;
Eric Andersencb57d552001-06-28 07:25:16 +00009230 arglist.lastp = &arglist.list;
Eric Andersencb57d552001-06-28 07:25:16 +00009231 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009232 for (cp = n->ncase.cases; cp && evalskip == 0; cp = cp->nclist.next) {
9233 for (patp = cp->nclist.pattern; patp; patp = patp->narg.next) {
Eric Andersencb57d552001-06-28 07:25:16 +00009234 if (casematch(patp, arglist.list->text)) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009235 /* Ensure body is non-empty as otherwise
9236 * EV_EXIT may prevent us from setting the
9237 * exit status.
9238 */
9239 if (evalskip == 0 && cp->nclist.body) {
9240 status = evaltree(cp->nclist.body, flags);
Eric Andersencb57d552001-06-28 07:25:16 +00009241 }
9242 goto out;
9243 }
9244 }
9245 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009246 out:
Eric Andersencb57d552001-06-28 07:25:16 +00009247 popstackmark(&smark);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009248
9249 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00009250}
9251
Eric Andersenc470f442003-07-28 09:56:35 +00009252/*
9253 * Kick off a subshell to evaluate a tree.
9254 */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009255static int
Eric Andersenc470f442003-07-28 09:56:35 +00009256evalsubshell(union node *n, int flags)
9257{
9258 struct job *jp;
Denys Vlasenko098b7132017-01-11 19:59:03 +01009259 int backgnd = (n->type == NBACKGND); /* FORK_BG(1) if yes, else FORK_FG(0) */
Eric Andersenc470f442003-07-28 09:56:35 +00009260 int status;
9261
Denys Vlasenko675d24a2018-01-27 22:02:05 +01009262 errlinno = lineno = n->nredir.linno;
9263 if (funcline)
9264 lineno -= funcline - 1;
9265
Eric Andersenc470f442003-07-28 09:56:35 +00009266 expredir(n->nredir.redirect);
Denys Vlasenko238bf182010-05-18 15:49:07 +02009267 if (!backgnd && (flags & EV_EXIT) && !may_have_traps)
Eric Andersenc470f442003-07-28 09:56:35 +00009268 goto nofork;
Denis Vlasenkob012b102007-02-19 22:43:01 +00009269 INT_OFF;
Denys Vlasenko098b7132017-01-11 19:59:03 +01009270 if (backgnd == FORK_FG)
9271 get_tty_state();
Denis Vlasenko68404f12008-03-17 09:00:54 +00009272 jp = makejob(/*n,*/ 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009273 if (forkshell(jp, n, backgnd) == 0) {
Denys Vlasenko238bf182010-05-18 15:49:07 +02009274 /* child */
Denis Vlasenkob012b102007-02-19 22:43:01 +00009275 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +00009276 flags |= EV_EXIT;
9277 if (backgnd)
Denys Vlasenko238bf182010-05-18 15:49:07 +02009278 flags &= ~EV_TESTED;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00009279 nofork:
Eric Andersenc470f442003-07-28 09:56:35 +00009280 redirect(n->nredir.redirect, 0);
9281 evaltreenr(n->nredir.n, flags);
9282 /* never returns */
9283 }
Denys Vlasenko70392332016-10-27 02:31:55 +02009284 /* parent */
Eric Andersenc470f442003-07-28 09:56:35 +00009285 status = 0;
Denys Vlasenko098b7132017-01-11 19:59:03 +01009286 if (backgnd == FORK_FG)
Eric Andersenc470f442003-07-28 09:56:35 +00009287 status = waitforjob(jp);
Denis Vlasenkob012b102007-02-19 22:43:01 +00009288 INT_ON;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009289 return status;
Eric Andersenc470f442003-07-28 09:56:35 +00009290}
9291
Eric Andersenc470f442003-07-28 09:56:35 +00009292/*
9293 * Compute the names of the files in a redirection list.
9294 */
Denis Vlasenko99eb8502007-02-23 21:09:49 +00009295static void fixredir(union node *, const char *, int);
Eric Andersenc470f442003-07-28 09:56:35 +00009296static void
9297expredir(union node *n)
9298{
9299 union node *redir;
9300
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009301 for (redir = n; redir; redir = redir->nfile.next) {
Eric Andersenc470f442003-07-28 09:56:35 +00009302 struct arglist fn;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009303
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00009304 fn.list = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00009305 fn.lastp = &fn.list;
9306 switch (redir->type) {
9307 case NFROMTO:
9308 case NFROM:
9309 case NTO:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01009310#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00009311 case NTO2:
9312#endif
Eric Andersenc470f442003-07-28 09:56:35 +00009313 case NCLOBBER:
9314 case NAPPEND:
9315 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02009316 TRACE(("expredir expanded to '%s'\n", fn.list->text));
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01009317#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00009318 store_expfname:
9319#endif
Denys Vlasenko7c4b13e2013-01-17 13:02:27 +01009320#if 0
9321// By the design of stack allocator, the loop of this kind:
9322// while true; do while true; do break; done </dev/null; done
9323// will look like a memory leak: ash plans to free expfname's
9324// of "/dev/null" as soon as it finishes running the loop
9325// (in this case, never).
9326// This "fix" is wrong:
Jon Tollefson4ba6c5d2012-11-13 19:26:53 +01009327 if (redir->nfile.expfname)
9328 stunalloc(redir->nfile.expfname);
Denys Vlasenko7c4b13e2013-01-17 13:02:27 +01009329// It results in corrupted state of stacked allocations.
9330#endif
Eric Andersenc470f442003-07-28 09:56:35 +00009331 redir->nfile.expfname = fn.list->text;
9332 break;
9333 case NFROMFD:
Denis Vlasenko559691a2008-10-05 18:39:31 +00009334 case NTOFD: /* >& */
Eric Andersenc470f442003-07-28 09:56:35 +00009335 if (redir->ndup.vname) {
9336 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009337 if (fn.list == NULL)
Denis Vlasenkob012b102007-02-19 22:43:01 +00009338 ash_msg_and_raise_error("redir error");
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01009339#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00009340//FIXME: we used expandarg with different args!
9341 if (!isdigit_str9(fn.list->text)) {
9342 /* >&file, not >&fd */
9343 if (redir->nfile.fd != 1) /* 123>&file - BAD */
9344 ash_msg_and_raise_error("redir error");
9345 redir->type = NTO2;
9346 goto store_expfname;
9347 }
9348#endif
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009349 fixredir(redir, fn.list->text, 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009350 }
9351 break;
9352 }
9353 }
9354}
9355
Eric Andersencb57d552001-06-28 07:25:16 +00009356/*
Eric Andersencb57d552001-06-28 07:25:16 +00009357 * Evaluate a pipeline. All the processes in the pipeline are children
9358 * of the process creating the pipeline. (This differs from some versions
9359 * of the shell, which make the last process in a pipeline the parent
9360 * of all the rest.)
9361 */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009362static int
Eric Andersenc470f442003-07-28 09:56:35 +00009363evalpipe(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00009364{
9365 struct job *jp;
9366 struct nodelist *lp;
9367 int pipelen;
9368 int prevfd;
9369 int pip[2];
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009370 int status = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00009371
Eric Andersenc470f442003-07-28 09:56:35 +00009372 TRACE(("evalpipe(0x%lx) called\n", (long)n));
Eric Andersencb57d552001-06-28 07:25:16 +00009373 pipelen = 0;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009374 for (lp = n->npipe.cmdlist; lp; lp = lp->next)
Eric Andersencb57d552001-06-28 07:25:16 +00009375 pipelen++;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009376 flags |= EV_EXIT;
Denis Vlasenkob012b102007-02-19 22:43:01 +00009377 INT_OFF;
Denys Vlasenko098b7132017-01-11 19:59:03 +01009378 if (n->npipe.pipe_backgnd == 0)
9379 get_tty_state();
Denis Vlasenko68404f12008-03-17 09:00:54 +00009380 jp = makejob(/*n,*/ pipelen);
Eric Andersencb57d552001-06-28 07:25:16 +00009381 prevfd = -1;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009382 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009383 prehash(lp->n);
Eric Andersencb57d552001-06-28 07:25:16 +00009384 pip[1] = -1;
9385 if (lp->next) {
9386 if (pipe(pip) < 0) {
9387 close(prevfd);
Denys Vlasenko12ffefb2017-08-23 14:52:56 +02009388 ash_msg_and_raise_perror("can't create pipe");
Eric Andersencb57d552001-06-28 07:25:16 +00009389 }
9390 }
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00009391 if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) {
Denys Vlasenko70392332016-10-27 02:31:55 +02009392 /* child */
Denis Vlasenkob012b102007-02-19 22:43:01 +00009393 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +00009394 if (pip[1] >= 0) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009395 close(pip[0]);
Eric Andersencb57d552001-06-28 07:25:16 +00009396 }
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009397 if (prevfd > 0) {
9398 dup2(prevfd, 0);
9399 close(prevfd);
9400 }
9401 if (pip[1] > 1) {
9402 dup2(pip[1], 1);
9403 close(pip[1]);
9404 }
Eric Andersenc470f442003-07-28 09:56:35 +00009405 evaltreenr(lp->n, flags);
9406 /* never returns */
Eric Andersencb57d552001-06-28 07:25:16 +00009407 }
Denys Vlasenko70392332016-10-27 02:31:55 +02009408 /* parent */
Eric Andersencb57d552001-06-28 07:25:16 +00009409 if (prevfd >= 0)
9410 close(prevfd);
9411 prevfd = pip[0];
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +00009412 /* Don't want to trigger debugging */
9413 if (pip[1] != -1)
9414 close(pip[1]);
Eric Andersencb57d552001-06-28 07:25:16 +00009415 }
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00009416 if (n->npipe.pipe_backgnd == 0) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009417 status = waitforjob(jp);
9418 TRACE(("evalpipe: job done exit status %d\n", status));
Eric Andersencb57d552001-06-28 07:25:16 +00009419 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00009420 INT_ON;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009421
9422 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00009423}
9424
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009425/*
9426 * Controls whether the shell is interactive or not.
9427 */
9428static void
9429setinteractive(int on)
9430{
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009431 static smallint is_interactive;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009432
9433 if (++on == is_interactive)
9434 return;
9435 is_interactive = on;
9436 setsignal(SIGINT);
9437 setsignal(SIGQUIT);
9438 setsignal(SIGTERM);
9439#if !ENABLE_FEATURE_SH_EXTRA_QUIET
9440 if (is_interactive > 1) {
9441 /* Looks like they want an interactive shell */
Denis Vlasenkoca525b42007-06-13 12:27:17 +00009442 static smallint did_banner;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009443
Denis Vlasenkoca525b42007-06-13 12:27:17 +00009444 if (!did_banner) {
Denys Vlasenkoc34c0332009-09-29 12:25:30 +02009445 /* note: ash and hush share this string */
9446 out1fmt("\n\n%s %s\n"
Denys Vlasenko2ec34962014-09-08 16:52:39 +02009447 IF_ASH_HELP("Enter 'help' for a list of built-in commands.\n")
9448 "\n",
Denys Vlasenkoc34c0332009-09-29 12:25:30 +02009449 bb_banner,
9450 "built-in shell (ash)"
9451 );
Denis Vlasenkoca525b42007-06-13 12:27:17 +00009452 did_banner = 1;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009453 }
9454 }
9455#endif
9456}
9457
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009458static void
9459optschanged(void)
9460{
9461#if DEBUG
9462 opentrace();
9463#endif
9464 setinteractive(iflag);
9465 setjobctl(mflag);
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009466#if ENABLE_FEATURE_EDITING_VI
9467 if (viflag)
9468 line_input_state->flags |= VI_MODE;
9469 else
9470 line_input_state->flags &= ~VI_MODE;
9471#else
9472 viflag = 0; /* forcibly keep the option off */
9473#endif
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009474}
9475
Denys Vlasenkob8ab27b2017-07-26 19:22:34 +02009476struct localvar_list {
9477 struct localvar_list *next;
9478 struct localvar *lv;
9479};
9480
9481static struct localvar_list *localvar_stack;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009482
9483/*
9484 * Called after a function returns.
9485 * Interrupts must be off.
9486 */
9487static void
Denys Vlasenko981a0562017-07-26 19:53:11 +02009488poplocalvars(int keep)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009489{
Denys Vlasenkob8ab27b2017-07-26 19:22:34 +02009490 struct localvar_list *ll;
9491 struct localvar *lvp, *next;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009492 struct var *vp;
9493
Denys Vlasenkob8ab27b2017-07-26 19:22:34 +02009494 INT_OFF;
9495 ll = localvar_stack;
9496 localvar_stack = ll->next;
9497
9498 next = ll->lv;
9499 free(ll);
9500
9501 while ((lvp = next) != NULL) {
9502 next = lvp->next;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009503 vp = lvp->vp;
Denys Vlasenkob563f622010-09-25 17:15:13 +02009504 TRACE(("poplocalvar %s\n", vp ? vp->var_text : "-"));
Denys Vlasenko981a0562017-07-26 19:53:11 +02009505 if (keep) {
9506 int bits = VSTRFIXED;
9507
9508 if (lvp->flags != VUNSET) {
9509 if (vp->var_text == lvp->text)
9510 bits |= VTEXTFIXED;
9511 else if (!(lvp->flags & (VTEXTFIXED|VSTACK)))
9512 free((char*)lvp->text);
9513 }
9514
9515 vp->flags &= ~bits;
9516 vp->flags |= (lvp->flags & bits);
9517
9518 if ((vp->flags &
9519 (VEXPORT|VREADONLY|VSTRFIXED|VUNSET)) == VUNSET)
9520 unsetvar(vp->var_text);
9521 } else if (vp == NULL) { /* $- saved */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009522 memcpy(optlist, lvp->text, sizeof(optlist));
9523 free((char*)lvp->text);
9524 optschanged();
Denys Vlasenkod5b500c2017-07-26 19:25:40 +02009525 } else if (lvp->flags == VUNSET) {
9526 vp->flags &= ~(VSTRFIXED|VREADONLY);
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009527 unsetvar(vp->var_text);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009528 } else {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009529 if (vp->var_func)
9530 vp->var_func(var_end(lvp->text));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009531 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009532 free((char*)vp->var_text);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009533 vp->flags = lvp->flags;
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009534 vp->var_text = lvp->text;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009535 }
9536 free(lvp);
9537 }
Denys Vlasenkob8ab27b2017-07-26 19:22:34 +02009538 INT_ON;
9539}
9540
9541/*
9542 * Create a new localvar environment.
9543 */
Denys Vlasenko484fc202017-07-26 19:55:31 +02009544static struct localvar_list *
Denys Vlasenkob8ab27b2017-07-26 19:22:34 +02009545pushlocalvars(void)
9546{
9547 struct localvar_list *ll;
9548
9549 INT_OFF;
9550 ll = ckzalloc(sizeof(*ll));
9551 /*ll->lv = NULL; - zalloc did it */
9552 ll->next = localvar_stack;
9553 localvar_stack = ll;
9554 INT_ON;
Denys Vlasenko484fc202017-07-26 19:55:31 +02009555
9556 return ll->next;
9557}
9558
9559static void
9560unwindlocalvars(struct localvar_list *stop)
9561{
9562 while (localvar_stack != stop)
9563 poplocalvars(0);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009564}
9565
9566static int
9567evalfun(struct funcnode *func, int argc, char **argv, int flags)
9568{
9569 volatile struct shparam saveparam;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009570 struct jmploc *volatile savehandler;
9571 struct jmploc jmploc;
9572 int e;
Denys Vlasenko675d24a2018-01-27 22:02:05 +01009573 int savefuncline;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009574
9575 saveparam = shellparam;
Denys Vlasenko675d24a2018-01-27 22:02:05 +01009576 savefuncline = funcline;
Denys Vlasenkoa2d121c2016-09-30 11:30:11 +02009577 savehandler = exception_handler;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009578 e = setjmp(jmploc.loc);
9579 if (e) {
9580 goto funcdone;
9581 }
9582 INT_OFF;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009583 exception_handler = &jmploc;
Denis Vlasenko01631112007-12-16 17:20:38 +00009584 shellparam.malloced = 0;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009585 func->count++;
Denys Vlasenko675d24a2018-01-27 22:02:05 +01009586 funcline = func->n.ndefun.linno;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009587 INT_ON;
9588 shellparam.nparam = argc - 1;
9589 shellparam.p = argv + 1;
9590#if ENABLE_ASH_GETOPTS
9591 shellparam.optind = 1;
9592 shellparam.optoff = -1;
9593#endif
Denys Vlasenkob8ab27b2017-07-26 19:22:34 +02009594 pushlocalvars();
Denys Vlasenko675d24a2018-01-27 22:02:05 +01009595 evaltree(func->n.ndefun.body, flags & EV_TESTED);
Denys Vlasenko981a0562017-07-26 19:53:11 +02009596 poplocalvars(0);
Denis Vlasenko01631112007-12-16 17:20:38 +00009597 funcdone:
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009598 INT_OFF;
Denys Vlasenko675d24a2018-01-27 22:02:05 +01009599 funcline = savefuncline;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009600 freefunc(func);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009601 freeparam(&shellparam);
9602 shellparam = saveparam;
9603 exception_handler = savehandler;
9604 INT_ON;
9605 evalskip &= ~SKIPFUNC;
9606 return e;
9607}
9608
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009609/*
9610 * Make a variable a local variable. When a variable is made local, it's
9611 * value and flags are saved in a localvar structure. The saved values
9612 * will be restored when the shell function returns. We handle the name
Denys Vlasenkoe0a4e102015-05-13 02:20:14 +02009613 * "-" as a special case: it makes changes to "set +-options" local
9614 * (options will be restored on return from the function).
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009615 */
9616static void
9617mklocal(char *name)
9618{
9619 struct localvar *lvp;
9620 struct var **vpp;
9621 struct var *vp;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009622 char *eq = strchr(name, '=');
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009623
9624 INT_OFF;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009625 /* Cater for duplicate "local". Examples:
9626 * x=0; f() { local x=1; echo $x; local x; echo $x; }; f; echo $x
9627 * x=0; f() { local x=1; echo $x; local x=2; echo $x; }; f; echo $x
9628 */
Denys Vlasenkob8ab27b2017-07-26 19:22:34 +02009629 lvp = localvar_stack->lv;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009630 while (lvp) {
Eugene Rudoy1285aa62015-04-26 23:32:00 +02009631 if (lvp->vp && varcmp(lvp->vp->var_text, name) == 0) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009632 if (eq)
9633 setvareq(name, 0);
9634 /* else:
9635 * it's a duplicate "local VAR" declaration, do nothing
9636 */
Denys Vlasenko06b11492016-11-04 16:43:18 +01009637 goto ret;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009638 }
9639 lvp = lvp->next;
9640 }
9641
9642 lvp = ckzalloc(sizeof(*lvp));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009643 if (LONE_DASH(name)) {
9644 char *p;
9645 p = ckmalloc(sizeof(optlist));
9646 lvp->text = memcpy(p, optlist, sizeof(optlist));
9647 vp = NULL;
9648 } else {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009649 vpp = hashvar(name);
9650 vp = *findvar(vpp, name);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009651 if (vp == NULL) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009652 /* variable did not exist yet */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009653 if (eq)
Denys Vlasenkod04fc712017-07-26 20:06:48 +02009654 vp = setvareq(name, VSTRFIXED);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009655 else
Denys Vlasenkod04fc712017-07-26 20:06:48 +02009656 vp = setvar(name, NULL, VSTRFIXED);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009657 lvp->flags = VUNSET;
9658 } else {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009659 lvp->text = vp->var_text;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009660 lvp->flags = vp->flags;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009661 /* make sure neither "struct var" nor string gets freed
9662 * during (un)setting:
9663 */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009664 vp->flags |= VSTRFIXED|VTEXTFIXED;
9665 if (eq)
9666 setvareq(name, 0);
Denys Vlasenko109ee5d2014-03-16 18:41:11 +01009667 else
9668 /* "local VAR" unsets VAR: */
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009669 setvar0(name, NULL);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009670 }
9671 }
9672 lvp->vp = vp;
Denys Vlasenkob8ab27b2017-07-26 19:22:34 +02009673 lvp->next = localvar_stack->lv;
9674 localvar_stack->lv = lvp;
Denys Vlasenko06b11492016-11-04 16:43:18 +01009675 ret:
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009676 INT_ON;
9677}
9678
9679/*
9680 * The "local" command.
9681 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009682static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009683localcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009684{
9685 char *name;
9686
Denys Vlasenkob8ab27b2017-07-26 19:22:34 +02009687 if (!localvar_stack)
Ron Yorstonef2386b2015-10-29 16:19:14 +00009688 ash_msg_and_raise_error("not in a function");
9689
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009690 argv = argptr;
9691 while ((name = *argv++) != NULL) {
9692 mklocal(name);
9693 }
9694 return 0;
9695}
9696
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009697static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009698falsecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009699{
9700 return 1;
9701}
9702
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009703static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009704truecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009705{
9706 return 0;
9707}
9708
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009709static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009710execcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009711{
Denys Vlasenko6c149f42017-04-12 21:31:32 +02009712 optionarg = NULL;
9713 while (nextopt("a:") != '\0')
9714 /* nextopt() sets optionarg to "-a ARGV0" */;
9715
9716 argv = argptr;
9717 if (argv[0]) {
9718 char *prog;
9719
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009720 iflag = 0; /* exit on error */
9721 mflag = 0;
9722 optschanged();
Denys Vlasenkoe5814a52016-07-16 18:33:55 +02009723 /* We should set up signals for "exec CMD"
9724 * the same way as for "CMD" without "exec".
9725 * But optschanged->setinteractive->setsignal
9726 * still thought we are a root shell. Therefore, for example,
9727 * SIGQUIT is still set to IGN. Fix it:
9728 */
9729 shlvl++;
9730 setsignal(SIGQUIT);
9731 /*setsignal(SIGTERM); - unnecessary because of iflag=0 */
9732 /*setsignal(SIGTSTP); - unnecessary because of mflag=0 */
9733 /*setsignal(SIGTTOU); - unnecessary because of mflag=0 */
9734
Denys Vlasenko6c149f42017-04-12 21:31:32 +02009735 prog = argv[0];
9736 if (optionarg)
9737 argv[0] = optionarg;
9738 shellexec(prog, argv, pathval(), 0);
Denys Vlasenkoe5814a52016-07-16 18:33:55 +02009739 /* NOTREACHED */
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009740 }
9741 return 0;
9742}
9743
9744/*
9745 * The return command.
9746 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009747static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009748returncmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009749{
9750 /*
9751 * If called outside a function, do what ksh does;
9752 * skip the rest of the file.
9753 */
Denys Vlasenko6a0710e2016-09-30 14:18:34 +02009754 evalskip = SKIPFUNC;
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009755 return argv[1] ? number(argv[1]) : exitstatus;
9756}
9757
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009758/* Forward declarations for builtintab[] */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009759static int breakcmd(int, char **) FAST_FUNC;
9760static int dotcmd(int, char **) FAST_FUNC;
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009761static int evalcmd(int, char **, int) FAST_FUNC;
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009762static int exitcmd(int, char **) FAST_FUNC;
9763static int exportcmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009764#if ENABLE_ASH_GETOPTS
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009765static int getoptscmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009766#endif
Denys Vlasenko2ec34962014-09-08 16:52:39 +02009767#if ENABLE_ASH_HELP
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009768static int helpcmd(int, char **) FAST_FUNC;
Denis Vlasenko52764022007-02-24 13:42:56 +00009769#endif
Flemming Madsend96ffda2013-04-07 18:47:24 +02009770#if MAX_HISTORY
9771static int historycmd(int, char **) FAST_FUNC;
9772#endif
Denys Vlasenko0b883582016-12-23 16:49:07 +01009773#if ENABLE_FEATURE_SH_MATH
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009774static int letcmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009775#endif
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009776static int readcmd(int, char **) FAST_FUNC;
9777static int setcmd(int, char **) FAST_FUNC;
9778static int shiftcmd(int, char **) FAST_FUNC;
9779static int timescmd(int, char **) FAST_FUNC;
9780static int trapcmd(int, char **) FAST_FUNC;
9781static int umaskcmd(int, char **) FAST_FUNC;
9782static int unsetcmd(int, char **) FAST_FUNC;
9783static int ulimitcmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009784
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009785#define BUILTIN_NOSPEC "0"
9786#define BUILTIN_SPECIAL "1"
9787#define BUILTIN_REGULAR "2"
9788#define BUILTIN_SPEC_REG "3"
9789#define BUILTIN_ASSIGN "4"
9790#define BUILTIN_SPEC_ASSG "5"
9791#define BUILTIN_REG_ASSG "6"
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009792#define BUILTIN_SPEC_REG_ASSG "7"
9793
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009794/* Stubs for calling non-FAST_FUNC's */
Denys Vlasenko265062d2017-01-10 15:13:30 +01009795#if ENABLE_ASH_ECHO
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009796static int FAST_FUNC echocmd(int argc, char **argv) { return echo_main(argc, argv); }
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009797#endif
Denys Vlasenko265062d2017-01-10 15:13:30 +01009798#if ENABLE_ASH_PRINTF
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009799static int FAST_FUNC printfcmd(int argc, char **argv) { return printf_main(argc, argv); }
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009800#endif
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01009801#if ENABLE_ASH_TEST || BASH_TEST2
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009802static int FAST_FUNC testcmd(int argc, char **argv) { return test_main(argc, argv); }
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009803#endif
Denis Vlasenko468aea22008-04-01 14:47:57 +00009804
Denis Vlasenkof7d56652008-03-25 05:51:41 +00009805/* Keep these in proper order since it is searched via bsearch() */
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009806static const struct builtincmd builtintab[] = {
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009807 { BUILTIN_SPEC_REG "." , dotcmd },
9808 { BUILTIN_SPEC_REG ":" , truecmd },
Denys Vlasenko265062d2017-01-10 15:13:30 +01009809#if ENABLE_ASH_TEST
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009810 { BUILTIN_REGULAR "[" , testcmd },
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01009811#endif
9812#if BASH_TEST2
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009813 { BUILTIN_REGULAR "[[" , testcmd },
Denis Vlasenko80591b02008-03-25 07:49:43 +00009814#endif
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009815#if ENABLE_ASH_ALIAS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009816 { BUILTIN_REG_ASSG "alias" , aliascmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009817#endif
9818#if JOBS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009819 { BUILTIN_REGULAR "bg" , fg_bgcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009820#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009821 { BUILTIN_SPEC_REG "break" , breakcmd },
9822 { BUILTIN_REGULAR "cd" , cdcmd },
9823 { BUILTIN_NOSPEC "chdir" , cdcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009824#if ENABLE_ASH_CMDCMD
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009825 { BUILTIN_REGULAR "command" , commandcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009826#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009827 { BUILTIN_SPEC_REG "continue", breakcmd },
Denys Vlasenko265062d2017-01-10 15:13:30 +01009828#if ENABLE_ASH_ECHO
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009829 { BUILTIN_REGULAR "echo" , echocmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009830#endif
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009831 { BUILTIN_SPEC_REG "eval" , NULL }, /*evalcmd() has a differing prototype*/
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009832 { BUILTIN_SPEC_REG "exec" , execcmd },
9833 { BUILTIN_SPEC_REG "exit" , exitcmd },
9834 { BUILTIN_SPEC_REG_ASSG "export" , exportcmd },
9835 { BUILTIN_REGULAR "false" , falsecmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009836#if JOBS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009837 { BUILTIN_REGULAR "fg" , fg_bgcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009838#endif
9839#if ENABLE_ASH_GETOPTS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009840 { BUILTIN_REGULAR "getopts" , getoptscmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009841#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009842 { BUILTIN_NOSPEC "hash" , hashcmd },
Denys Vlasenko2ec34962014-09-08 16:52:39 +02009843#if ENABLE_ASH_HELP
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009844 { BUILTIN_NOSPEC "help" , helpcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009845#endif
Flemming Madsend96ffda2013-04-07 18:47:24 +02009846#if MAX_HISTORY
9847 { BUILTIN_NOSPEC "history" , historycmd },
9848#endif
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009849#if JOBS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009850 { BUILTIN_REGULAR "jobs" , jobscmd },
9851 { BUILTIN_REGULAR "kill" , killcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009852#endif
Denys Vlasenko0b883582016-12-23 16:49:07 +01009853#if ENABLE_FEATURE_SH_MATH
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009854 { BUILTIN_NOSPEC "let" , letcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009855#endif
Denys Vlasenko85241c72017-07-26 20:00:08 +02009856 { BUILTIN_SPEC_REG_ASSG "local" , localcmd },
Denys Vlasenko265062d2017-01-10 15:13:30 +01009857#if ENABLE_ASH_PRINTF
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009858 { BUILTIN_REGULAR "printf" , printfcmd },
Denis Vlasenkocd2663f2008-06-01 22:36:39 +00009859#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009860 { BUILTIN_NOSPEC "pwd" , pwdcmd },
9861 { BUILTIN_REGULAR "read" , readcmd },
9862 { BUILTIN_SPEC_REG_ASSG "readonly", exportcmd },
9863 { BUILTIN_SPEC_REG "return" , returncmd },
9864 { BUILTIN_SPEC_REG "set" , setcmd },
9865 { BUILTIN_SPEC_REG "shift" , shiftcmd },
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01009866#if BASH_SOURCE
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009867 { BUILTIN_SPEC_REG "source" , dotcmd },
Denys Vlasenko82731b42010-05-17 17:49:52 +02009868#endif
Denys Vlasenko265062d2017-01-10 15:13:30 +01009869#if ENABLE_ASH_TEST
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009870 { BUILTIN_REGULAR "test" , testcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009871#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009872 { BUILTIN_SPEC_REG "times" , timescmd },
9873 { BUILTIN_SPEC_REG "trap" , trapcmd },
9874 { BUILTIN_REGULAR "true" , truecmd },
9875 { BUILTIN_NOSPEC "type" , typecmd },
9876 { BUILTIN_NOSPEC "ulimit" , ulimitcmd },
9877 { BUILTIN_REGULAR "umask" , umaskcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009878#if ENABLE_ASH_ALIAS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009879 { BUILTIN_REGULAR "unalias" , unaliascmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009880#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009881 { BUILTIN_SPEC_REG "unset" , unsetcmd },
9882 { BUILTIN_REGULAR "wait" , waitcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009883};
9884
Denis Vlasenko80591b02008-03-25 07:49:43 +00009885/* Should match the above table! */
9886#define COMMANDCMD (builtintab + \
Denys Vlasenko928e2a72016-09-29 00:30:31 +02009887 /* . : */ 2 + \
Denys Vlasenko265062d2017-01-10 15:13:30 +01009888 /* [ */ 1 * ENABLE_ASH_TEST + \
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01009889 /* [[ */ 1 * BASH_TEST2 + \
Denys Vlasenko928e2a72016-09-29 00:30:31 +02009890 /* alias */ 1 * ENABLE_ASH_ALIAS + \
9891 /* bg */ 1 * ENABLE_ASH_JOB_CONTROL + \
9892 /* break cd cddir */ 3)
9893#define EVALCMD (COMMANDCMD + \
9894 /* command */ 1 * ENABLE_ASH_CMDCMD + \
9895 /* continue */ 1 + \
Denys Vlasenko265062d2017-01-10 15:13:30 +01009896 /* echo */ 1 * ENABLE_ASH_ECHO + \
Denys Vlasenko928e2a72016-09-29 00:30:31 +02009897 0)
9898#define EXECCMD (EVALCMD + \
9899 /* eval */ 1)
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009900
9901/*
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009902 * Search the table of builtin commands.
9903 */
Denys Vlasenko888527c2016-10-02 16:54:17 +02009904static int
9905pstrcmp1(const void *a, const void *b)
9906{
9907 return strcmp((char*)a, *(char**)b + 1);
9908}
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009909static struct builtincmd *
9910find_builtin(const char *name)
9911{
9912 struct builtincmd *bp;
9913
9914 bp = bsearch(
Denis Vlasenko80b8b392007-06-25 10:55:35 +00009915 name, builtintab, ARRAY_SIZE(builtintab), sizeof(builtintab[0]),
Denys Vlasenko888527c2016-10-02 16:54:17 +02009916 pstrcmp1
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009917 );
9918 return bp;
9919}
9920
9921/*
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009922 * Execute a simple command.
9923 */
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009924static int
9925isassignment(const char *p)
Paul Foxc3850c82005-07-20 18:23:39 +00009926{
9927 const char *q = endofname(p);
9928 if (p == q)
9929 return 0;
9930 return *q == '=';
9931}
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009932static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009933bltincmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009934{
9935 /* Preserve exitstatus of a previous possible redirection
9936 * as POSIX mandates */
9937 return back_exitstatus;
9938}
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009939static int
Eric Andersenc470f442003-07-28 09:56:35 +00009940evalcommand(union node *cmd, int flags)
9941{
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00009942 static const struct builtincmd null_bltin = {
9943 "\0\0", bltincmd /* why three NULs? */
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009944 };
Denys Vlasenko484fc202017-07-26 19:55:31 +02009945 struct localvar_list *localvar_stop;
Denys Vlasenko1c79aeb2017-07-29 22:51:52 +02009946 struct redirtab *redir_stop;
Eric Andersenc470f442003-07-28 09:56:35 +00009947 struct stackmark smark;
9948 union node *argp;
9949 struct arglist arglist;
9950 struct arglist varlist;
9951 char **argv;
9952 int argc;
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009953 const struct strlist *sp;
Eric Andersenc470f442003-07-28 09:56:35 +00009954 struct cmdentry cmdentry;
9955 struct job *jp;
9956 char *lastarg;
9957 const char *path;
9958 int spclbltin;
Eric Andersenc470f442003-07-28 09:56:35 +00009959 int status;
9960 char **nargv;
Denis Vlasenko34c73c42008-08-16 11:48:02 +00009961 smallint cmd_is_exec;
Eric Andersenc470f442003-07-28 09:56:35 +00009962
Denys Vlasenko675d24a2018-01-27 22:02:05 +01009963 errlinno = lineno = cmd->ncmd.linno;
9964 if (funcline)
9965 lineno -= funcline - 1;
9966
Eric Andersenc470f442003-07-28 09:56:35 +00009967 /* First expand the arguments. */
9968 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
9969 setstackmark(&smark);
Denys Vlasenko484fc202017-07-26 19:55:31 +02009970 localvar_stop = pushlocalvars();
Eric Andersenc470f442003-07-28 09:56:35 +00009971 back_exitstatus = 0;
9972
9973 cmdentry.cmdtype = CMDBUILTIN;
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00009974 cmdentry.u.cmd = &null_bltin;
Eric Andersenc470f442003-07-28 09:56:35 +00009975 varlist.lastp = &varlist.list;
9976 *varlist.lastp = NULL;
9977 arglist.lastp = &arglist.list;
9978 *arglist.lastp = NULL;
9979
9980 argc = 0;
Denis Vlasenkob012b102007-02-19 22:43:01 +00009981 if (cmd->ncmd.args) {
Denys Vlasenkod07a15b2017-07-30 16:51:05 +02009982 struct builtincmd *bcmd;
9983 smallint pseudovarflag;
9984
Paul Foxc3850c82005-07-20 18:23:39 +00009985 bcmd = find_builtin(cmd->ncmd.args->narg.text);
9986 pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd);
Paul Foxc3850c82005-07-20 18:23:39 +00009987
Denys Vlasenkod07a15b2017-07-30 16:51:05 +02009988 for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) {
9989 struct strlist **spp;
Eric Andersenc470f442003-07-28 09:56:35 +00009990
Denys Vlasenkod07a15b2017-07-30 16:51:05 +02009991 spp = arglist.lastp;
9992 if (pseudovarflag && isassignment(argp->narg.text))
9993 expandarg(argp, &arglist, EXP_VARTILDE);
9994 else
9995 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
Paul Foxc3850c82005-07-20 18:23:39 +00009996
Denys Vlasenkod07a15b2017-07-30 16:51:05 +02009997 for (sp = *spp; sp; sp = sp->next)
9998 argc++;
9999 }
Eric Andersenc470f442003-07-28 09:56:35 +000010000 }
10001
Denys Vlasenko65a8b852016-10-26 22:29:11 +020010002 /* Reserve one extra spot at the front for shellexec. */
10003 nargv = stalloc(sizeof(char *) * (argc + 2));
10004 argv = ++nargv;
Denis Vlasenko2da584f2007-02-19 22:44:05 +000010005 for (sp = arglist.list; sp; sp = sp->next) {
Eric Andersenc470f442003-07-28 09:56:35 +000010006 TRACE(("evalcommand arg: %s\n", sp->text));
10007 *nargv++ = sp->text;
10008 }
10009 *nargv = NULL;
10010
10011 lastarg = NULL;
Denys Vlasenko675d24a2018-01-27 22:02:05 +010010012 if (iflag && funcline == 0 && argc > 0)
Eric Andersenc470f442003-07-28 09:56:35 +000010013 lastarg = nargv[-1];
10014
10015 expredir(cmd->ncmd.redirect);
Denys Vlasenko1c79aeb2017-07-29 22:51:52 +020010016 redir_stop = pushredir(cmd->ncmd.redirect);
Denys Vlasenkod07a15b2017-07-30 16:51:05 +020010017 preverrout_fd = 2;
Denys Vlasenkof8cdc7a2017-08-04 15:24:49 +020010018 if (BASH_XTRACEFD && xflag) {
10019 /* NB: bash closes fd == $BASH_XTRACEFD when it is changed.
10020 * we do not emulate this. We only use its value.
10021 */
10022 const char *xtracefd = lookupvar("BASH_XTRACEFD");
10023 if (xtracefd && is_number(xtracefd))
10024 preverrout_fd = atoi(xtracefd);
10025
10026 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010027 status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH | REDIR_SAVEFD2);
Eric Andersenc470f442003-07-28 09:56:35 +000010028
Denys Vlasenko8837c5d2010-06-02 12:56:18 +020010029 path = vpath.var_text;
Eric Andersenc470f442003-07-28 09:56:35 +000010030 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
10031 struct strlist **spp;
10032 char *p;
10033
10034 spp = varlist.lastp;
10035 expandarg(argp, &varlist, EXP_VARTILDE);
10036
Denys Vlasenko981a0562017-07-26 19:53:11 +020010037 mklocal((*spp)->text);
10038
Eric Andersenc470f442003-07-28 09:56:35 +000010039 /*
10040 * Modify the command lookup path, if a PATH= assignment
10041 * is present
10042 */
10043 p = (*spp)->text;
Denys Vlasenko8837c5d2010-06-02 12:56:18 +020010044 if (varcmp(p, path) == 0)
Eric Andersenc470f442003-07-28 09:56:35 +000010045 path = p;
10046 }
10047
10048 /* Print the command if xflag is set. */
10049 if (xflag) {
Denys Vlasenko42ba7572017-07-21 13:20:14 +020010050 const char *pfx = "";
Eric Andersenc470f442003-07-28 09:56:35 +000010051
Denys Vlasenko46999802017-07-29 21:12:29 +020010052 fdprintf(preverrout_fd, "%s", expandstr(ps4val(), DQSYNTAX));
Denys Vlasenko42ba7572017-07-21 13:20:14 +020010053
Glenn L McGrath7b8765c2003-08-29 07:29:30 +000010054 sp = varlist.list;
Denys Vlasenko42ba7572017-07-21 13:20:14 +020010055 while (sp) {
10056 char *varval = sp->text;
10057 char *eq = strchrnul(varval, '=');
10058 if (*eq)
10059 eq++;
10060 fdprintf(preverrout_fd, "%s%.*s%s",
10061 pfx,
10062 (int)(eq - varval), varval,
10063 maybe_single_quote(eq)
10064 );
10065 sp = sp->next;
10066 pfx = " ";
10067 }
10068
10069 sp = arglist.list;
10070 while (sp) {
10071 fdprintf(preverrout_fd, "%s%s",
10072 pfx,
10073 /* always quote if matches reserved word: */
10074 findkwd(sp->text)
10075 ? single_quote(sp->text)
10076 : maybe_single_quote(sp->text)
10077 );
10078 sp = sp->next;
10079 pfx = " ";
Glenn L McGrath7b8765c2003-08-29 07:29:30 +000010080 }
Denis Vlasenko0e6f6612008-02-15 15:02:15 +000010081 safe_write(preverrout_fd, "\n", 1);
Eric Andersenc470f442003-07-28 09:56:35 +000010082 }
10083
10084 cmd_is_exec = 0;
10085 spclbltin = -1;
10086
10087 /* Now locate the command. */
10088 if (argc) {
Eric Andersenc470f442003-07-28 09:56:35 +000010089 int cmd_flag = DO_ERR;
Denys Vlasenko0b4980c2012-09-25 12:49:29 +020010090#if ENABLE_ASH_CMDCMD
10091 const char *oldpath = path + 5;
10092#endif
Eric Andersenc470f442003-07-28 09:56:35 +000010093 path += 5;
Eric Andersenc470f442003-07-28 09:56:35 +000010094 for (;;) {
10095 find_command(argv[0], &cmdentry, cmd_flag, path);
10096 if (cmdentry.cmdtype == CMDUNKNOWN) {
Denys Vlasenko8131eea2009-11-02 14:19:51 +010010097 flush_stdout_stderr();
Denis Vlasenko6514c5e2008-07-24 13:41:37 +000010098 status = 127;
Eric Andersenc470f442003-07-28 09:56:35 +000010099 goto bail;
10100 }
10101
10102 /* implement bltin and command here */
10103 if (cmdentry.cmdtype != CMDBUILTIN)
10104 break;
10105 if (spclbltin < 0)
10106 spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd);
10107 if (cmdentry.u.cmd == EXECCMD)
Denis Vlasenko34c73c42008-08-16 11:48:02 +000010108 cmd_is_exec = 1;
Denis Vlasenko131ae172007-02-18 13:00:19 +000010109#if ENABLE_ASH_CMDCMD
Eric Andersenc470f442003-07-28 09:56:35 +000010110 if (cmdentry.u.cmd == COMMANDCMD) {
Eric Andersenc470f442003-07-28 09:56:35 +000010111 path = oldpath;
10112 nargv = parse_command_args(argv, &path);
10113 if (!nargv)
10114 break;
Denys Vlasenkocac4d002016-10-01 03:02:25 +020010115 /* It's "command [-p] PROG ARGS" (that is, no -Vv).
10116 * nargv => "PROG". path is updated if -p.
10117 */
Eric Andersenc470f442003-07-28 09:56:35 +000010118 argc -= nargv - argv;
10119 argv = nargv;
10120 cmd_flag |= DO_NOFUNC;
10121 } else
10122#endif
10123 break;
10124 }
10125 }
10126
10127 if (status) {
Ron Yorstonea7d2f62017-01-03 11:18:23 +010010128 bail:
10129 exitstatus = status;
10130
Eric Andersenc470f442003-07-28 09:56:35 +000010131 /* We have a redirection error. */
10132 if (spclbltin > 0)
Denis Vlasenkob012b102007-02-19 22:43:01 +000010133 raise_exception(EXERROR);
Ron Yorstonea7d2f62017-01-03 11:18:23 +010010134
Eric Andersenc470f442003-07-28 09:56:35 +000010135 goto out;
10136 }
10137
10138 /* Execute the command. */
10139 switch (cmdentry.cmdtype) {
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +020010140 default: {
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +000010141
Denys Vlasenko1750d3a2018-01-15 00:41:04 +010010142#if ENABLE_FEATURE_SH_STANDALONE \
10143 && ENABLE_FEATURE_SH_NOFORK \
10144 && NUM_APPLETS > 1
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +020010145/* (1) BUG: if variables are set, we need to fork, or save/restore them
10146 * around run_nofork_applet() call.
10147 * (2) Should this check also be done in forkshell()?
10148 * (perhaps it should, so that "VAR=VAL nofork" at least avoids exec...)
10149 */
Denis Vlasenko7465dbc2008-04-13 02:25:53 +000010150 /* find_command() encodes applet_no as (-2 - applet_no) */
10151 int applet_no = (- cmdentry.u.index - 2);
Denis Vlasenko9bc80d72008-04-12 20:07:53 +000010152 if (applet_no >= 0 && APPLET_IS_NOFORK(applet_no)) {
Denys Vlasenkoa5060b82017-11-03 14:16:25 +010010153 char **sv_environ;
10154
10155 INT_OFF;
10156 sv_environ = environ;
10157 environ = listvars(VEXPORT, VUNSET, varlist.list, /*end:*/ NULL);
Denys Vlasenkod329e342017-08-04 14:50:03 +020010158 /*
10159 * Run <applet>_main().
10160 * Signals (^C) can't interrupt here.
10161 * Otherwise we can mangle stdio or malloc internal state.
10162 * This makes applets which can run for a long time
10163 * and/or wait for user input ineligible for NOFORK:
10164 * for example, "yes" or "rm" (rm -i waits for input).
10165 */
Ron Yorston5ccb0e92016-10-20 12:24:02 +010010166 status = run_nofork_applet(applet_no, argv);
Denys Vlasenkoa5060b82017-11-03 14:16:25 +010010167 environ = sv_environ;
Denys Vlasenkod329e342017-08-04 14:50:03 +020010168 /*
10169 * Try enabling NOFORK for "yes" applet.
10170 * ^C _will_ stop it (write returns EINTR),
10171 * but this causes stdout FILE to be stuck
10172 * and needing clearerr(). What if other applets
10173 * also can get EINTRs? Do we need to switch
10174 * our signals to SA_RESTART?
10175 */
10176 /*clearerr(stdout);*/
10177 INT_ON;
Denis Vlasenko9bc80d72008-04-12 20:07:53 +000010178 break;
10179 }
Denis Vlasenko9bc80d72008-04-12 20:07:53 +000010180#endif
Denys Vlasenkocfd392b2017-08-03 19:56:29 +020010181 /* Can we avoid forking? For example, very last command
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +020010182 * in a script or a subshell does not need forking,
10183 * we can just exec it.
10184 */
Denys Vlasenko238bf182010-05-18 15:49:07 +020010185 if (!(flags & EV_EXIT) || may_have_traps) {
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +020010186 /* No, forking off a child is necessary */
Denis Vlasenkob012b102007-02-19 22:43:01 +000010187 INT_OFF;
Denys Vlasenko098b7132017-01-11 19:59:03 +010010188 get_tty_state();
Denis Vlasenko68404f12008-03-17 09:00:54 +000010189 jp = makejob(/*cmd,*/ 1);
Eric Andersenc470f442003-07-28 09:56:35 +000010190 if (forkshell(jp, cmd, FORK_FG) != 0) {
Denys Vlasenko238bf182010-05-18 15:49:07 +020010191 /* parent */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020010192 status = waitforjob(jp);
Denis Vlasenkob012b102007-02-19 22:43:01 +000010193 INT_ON;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020010194 TRACE(("forked child exited with %d\n", status));
Eric Andersenc470f442003-07-28 09:56:35 +000010195 break;
10196 }
Denys Vlasenko238bf182010-05-18 15:49:07 +020010197 /* child */
Denis Vlasenkob012b102007-02-19 22:43:01 +000010198 FORCE_INT_ON;
Denys Vlasenkoc7f95d22010-05-18 15:52:23 +020010199 /* fall through to exec'ing external program */
Eric Andersenc470f442003-07-28 09:56:35 +000010200 }
10201 listsetvar(varlist.list, VEXPORT|VSTACK);
Denys Vlasenkoe139ae32017-04-12 21:02:33 +020010202 shellexec(argv[0], argv, path, cmdentry.u.index);
Eric Andersenc470f442003-07-28 09:56:35 +000010203 /* NOTREACHED */
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +020010204 } /* default */
Eric Andersenc470f442003-07-28 09:56:35 +000010205 case CMDBUILTIN:
Denys Vlasenko85241c72017-07-26 20:00:08 +020010206 if (spclbltin > 0 || argc == 0) {
10207 poplocalvars(1);
10208 if (cmd_is_exec && argc > 1)
10209 listsetvar(varlist.list, VEXPORT);
10210 }
Denys Vlasenko981a0562017-07-26 19:53:11 +020010211
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +000010212 /* Tight loop with builtins only:
10213 * "while kill -0 $child; do true; done"
10214 * will never exit even if $child died, unless we do this
10215 * to reap the zombie and make kill detect that it's gone: */
10216 dowait(DOWAIT_NONBLOCK, NULL);
10217
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020010218 if (evalbltin(cmdentry.u.cmd, argc, argv, flags)) {
Denys Vlasenkoc0663c72016-10-27 21:09:01 +020010219 if (exception_type == EXERROR && spclbltin <= 0) {
10220 FORCE_INT_ON;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020010221 goto readstatus;
Eric Andersenc470f442003-07-28 09:56:35 +000010222 }
Denys Vlasenkoc0663c72016-10-27 21:09:01 +020010223 raise:
10224 longjmp(exception_handler->loc, 1);
Eric Andersenc470f442003-07-28 09:56:35 +000010225 }
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020010226 goto readstatus;
Eric Andersenc470f442003-07-28 09:56:35 +000010227
10228 case CMDFUNCTION:
Denys Vlasenko981a0562017-07-26 19:53:11 +020010229 poplocalvars(1);
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +000010230 /* See above for the rationale */
10231 dowait(DOWAIT_NONBLOCK, NULL);
Eric Andersenc470f442003-07-28 09:56:35 +000010232 if (evalfun(cmdentry.u.func, argc, argv, flags))
10233 goto raise;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020010234 readstatus:
10235 status = exitstatus;
Eric Andersenc470f442003-07-28 09:56:35 +000010236 break;
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +020010237 } /* switch */
Eric Andersenc470f442003-07-28 09:56:35 +000010238
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010239 out:
Denys Vlasenkoeaf94362016-10-25 21:46:03 +020010240 if (cmd->ncmd.redirect)
Denys Vlasenko035486c2017-07-31 04:09:19 +020010241 popredir(/*drop:*/ cmd_is_exec);
Denys Vlasenko1c79aeb2017-07-29 22:51:52 +020010242 unwindredir(redir_stop);
Denys Vlasenko484fc202017-07-26 19:55:31 +020010243 unwindlocalvars(localvar_stop);
Denis Vlasenko6514c5e2008-07-24 13:41:37 +000010244 if (lastarg) {
Eric Andersenc470f442003-07-28 09:56:35 +000010245 /* dsl: I think this is intended to be used to support
10246 * '_' in 'vi' command mode during line editing...
10247 * However I implemented that within libedit itself.
10248 */
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020010249 setvar0("_", lastarg);
Denis Vlasenko6514c5e2008-07-24 13:41:37 +000010250 }
Eric Andersenc470f442003-07-28 09:56:35 +000010251 popstackmark(&smark);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020010252
10253 return status;
Eric Andersenc470f442003-07-28 09:56:35 +000010254}
10255
10256static int
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020010257evalbltin(const struct builtincmd *cmd, int argc, char **argv, int flags)
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010258{
Eric Andersenc470f442003-07-28 09:56:35 +000010259 char *volatile savecmdname;
10260 struct jmploc *volatile savehandler;
10261 struct jmploc jmploc;
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020010262 int status;
Eric Andersenc470f442003-07-28 09:56:35 +000010263 int i;
10264
10265 savecmdname = commandname;
Denys Vlasenkoa2d121c2016-09-30 11:30:11 +020010266 savehandler = exception_handler;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010267 i = setjmp(jmploc.loc);
10268 if (i)
Eric Andersenc470f442003-07-28 09:56:35 +000010269 goto cmddone;
Denis Vlasenko2da584f2007-02-19 22:44:05 +000010270 exception_handler = &jmploc;
Eric Andersenc470f442003-07-28 09:56:35 +000010271 commandname = argv[0];
10272 argptr = argv + 1;
10273 optptr = NULL; /* initialize nextopt */
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020010274 if (cmd == EVALCMD)
10275 status = evalcmd(argc, argv, flags);
10276 else
10277 status = (*cmd->builtin)(argc, argv);
Denis Vlasenkob012b102007-02-19 22:43:01 +000010278 flush_stdout_stderr();
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020010279 status |= ferror(stdout);
10280 exitstatus = status;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010281 cmddone:
Rob Landleyf296f0b2006-07-06 01:09:21 +000010282 clearerr(stdout);
Eric Andersenc470f442003-07-28 09:56:35 +000010283 commandname = savecmdname;
Denis Vlasenko2da584f2007-02-19 22:44:05 +000010284 exception_handler = savehandler;
Eric Andersenc470f442003-07-28 09:56:35 +000010285
10286 return i;
10287}
10288
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010289static int
10290goodname(const char *p)
Glenn L McGrath16e45d72004-02-04 08:24:39 +000010291{
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +020010292 return endofname(p)[0] == '\0';
Glenn L McGrath16e45d72004-02-04 08:24:39 +000010293}
10294
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010295
Glenn L McGrath50812ff2002-08-23 13:14:48 +000010296/*
10297 * Search for a command. This is called before we fork so that the
10298 * location of the command will be available in the parent as well as
Glenn L McGrath16e45d72004-02-04 08:24:39 +000010299 * the child. The check for "goodname" is an overly conservative
10300 * check that the name will not be subject to expansion.
Glenn L McGrath50812ff2002-08-23 13:14:48 +000010301 */
Eric Andersenc470f442003-07-28 09:56:35 +000010302static void
10303prehash(union node *n)
Glenn L McGrath50812ff2002-08-23 13:14:48 +000010304{
10305 struct cmdentry entry;
10306
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000010307 if (n->type == NCMD && n->ncmd.args && goodname(n->ncmd.args->narg.text))
10308 find_command(n->ncmd.args->narg.text, &entry, 0, pathval());
Glenn L McGrath50812ff2002-08-23 13:14:48 +000010309}
10310
Eric Andersencb57d552001-06-28 07:25:16 +000010311
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000010312/* ============ Builtin commands
10313 *
10314 * Builtin commands whose functions are closely tied to evaluation
10315 * are implemented here.
Eric Andersencb57d552001-06-28 07:25:16 +000010316 */
10317
10318/*
Eric Andersencb57d552001-06-28 07:25:16 +000010319 * Handle break and continue commands. Break, continue, and return are
10320 * all handled by setting the evalskip flag. The evaluation routines
10321 * above all check this flag, and if it is set they start skipping
10322 * commands rather than executing them. The variable skipcount is
10323 * the number of loops to break/continue, or the number of function
10324 * levels to return. (The latter is always 1.) It should probably
10325 * be an error to break out of more loops than exist, but it isn't
10326 * in the standard shell so we don't make it one here.
10327 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010328static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010329breakcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000010330{
Denis Vlasenko68404f12008-03-17 09:00:54 +000010331 int n = argv[1] ? number(argv[1]) : 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010332
Aaron Lehmann2aef3a62001-12-31 06:03:12 +000010333 if (n <= 0)
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +020010334 ash_msg_and_raise_error(msg_illnum, argv[1]);
Eric Andersencb57d552001-06-28 07:25:16 +000010335 if (n > loopnest)
10336 n = loopnest;
10337 if (n > 0) {
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000010338 evalskip = (**argv == 'c') ? SKIPCONT : SKIPBREAK;
Eric Andersencb57d552001-06-28 07:25:16 +000010339 skipcount = n;
10340 }
10341 return 0;
10342}
10343
Eric Andersenc470f442003-07-28 09:56:35 +000010344
Denys Vlasenko70392332016-10-27 02:31:55 +020010345/*
Eric Andersen90898442003-08-06 11:20:52 +000010346 * This implements the input routines used by the parser.
Eric Andersencb57d552001-06-28 07:25:16 +000010347 */
Denis Vlasenko99eb8502007-02-23 21:09:49 +000010348
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010349enum {
10350 INPUT_PUSH_FILE = 1,
10351 INPUT_NOFILE_OK = 2,
10352};
Eric Andersencb57d552001-06-28 07:25:16 +000010353
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010354static smallint checkkwd;
Denis Vlasenko99eb8502007-02-23 21:09:49 +000010355/* values of checkkwd variable */
10356#define CHKALIAS 0x1
10357#define CHKKWD 0x2
10358#define CHKNL 0x4
Denys Vlasenkoa7328982017-07-29 19:57:28 +020010359#define CHKEOFMARK 0x8
Denis Vlasenko99eb8502007-02-23 21:09:49 +000010360
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010361/*
10362 * Push a string back onto the input at this current parsefile level.
10363 * We handle aliases this way.
10364 */
10365#if !ENABLE_ASH_ALIAS
10366#define pushstring(s, ap) pushstring(s)
10367#endif
10368static void
10369pushstring(char *s, struct alias *ap)
10370{
10371 struct strpush *sp;
10372 int len;
10373
10374 len = strlen(s);
10375 INT_OFF;
10376 if (g_parsefile->strpush) {
10377 sp = ckzalloc(sizeof(*sp));
10378 sp->prev = g_parsefile->strpush;
10379 } else {
10380 sp = &(g_parsefile->basestrpush);
10381 }
10382 g_parsefile->strpush = sp;
10383 sp->prev_string = g_parsefile->next_to_pgetc;
10384 sp->prev_left_in_line = g_parsefile->left_in_line;
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010385 sp->unget = g_parsefile->unget;
10386 memcpy(sp->lastc, g_parsefile->lastc, sizeof(sp->lastc));
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010387#if ENABLE_ASH_ALIAS
10388 sp->ap = ap;
10389 if (ap) {
10390 ap->flag |= ALIASINUSE;
10391 sp->string = s;
10392 }
10393#endif
10394 g_parsefile->next_to_pgetc = s;
10395 g_parsefile->left_in_line = len;
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010396 g_parsefile->unget = 0;
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010397 INT_ON;
10398}
10399
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010400static void
10401popstring(void)
Eric Andersenc470f442003-07-28 09:56:35 +000010402{
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010403 struct strpush *sp = g_parsefile->strpush;
Eric Andersenc470f442003-07-28 09:56:35 +000010404
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010405 INT_OFF;
Denis Vlasenko131ae172007-02-18 13:00:19 +000010406#if ENABLE_ASH_ALIAS
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010407 if (sp->ap) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010408 if (g_parsefile->next_to_pgetc[-1] == ' '
10409 || g_parsefile->next_to_pgetc[-1] == '\t'
10410 ) {
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010411 checkkwd |= CHKALIAS;
Glenn L McGrath28939ad2004-07-21 10:20:19 +000010412 }
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010413 if (sp->string != sp->ap->val) {
10414 free(sp->string);
10415 }
10416 sp->ap->flag &= ~ALIASINUSE;
10417 if (sp->ap->flag & ALIASDEAD) {
10418 unalias(sp->ap->name);
10419 }
Glenn L McGrath28939ad2004-07-21 10:20:19 +000010420 }
Denis Vlasenko8e1c7152007-01-22 07:21:38 +000010421#endif
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010422 g_parsefile->next_to_pgetc = sp->prev_string;
10423 g_parsefile->left_in_line = sp->prev_left_in_line;
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010424 g_parsefile->unget = sp->unget;
10425 memcpy(g_parsefile->lastc, sp->lastc, sizeof(sp->lastc));
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010426 g_parsefile->strpush = sp->prev;
10427 if (sp != &(g_parsefile->basestrpush))
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010428 free(sp);
10429 INT_ON;
10430}
Denis Vlasenko8e1c7152007-01-22 07:21:38 +000010431
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010432static int
10433preadfd(void)
Eric Andersencb57d552001-06-28 07:25:16 +000010434{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010435 int nr;
Denis Vlasenko6a0ad252008-07-25 13:34:05 +000010436 char *buf = g_parsefile->buf;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010437
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010438 g_parsefile->next_to_pgetc = buf;
Denis Vlasenko38f63192007-01-22 09:03:07 +000010439#if ENABLE_FEATURE_EDITING
Denis Vlasenko85c24712008-03-17 09:04:04 +000010440 retry:
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010441 if (!iflag || g_parsefile->pf_fd != STDIN_FILENO)
Ron Yorston61d6ae22015-04-19 10:50:25 +010010442 nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1);
Eric Andersenc470f442003-07-28 09:56:35 +000010443 else {
Denys Vlasenko66c5b122011-02-08 05:07:02 +010010444# if ENABLE_ASH_IDLE_TIMEOUT
Denys Vlasenko84ea60e2017-08-02 17:27:28 +020010445 int timeout = -1;
Denys Vlasenko66c5b122011-02-08 05:07:02 +010010446 if (iflag) {
10447 const char *tmout_var = lookupvar("TMOUT");
10448 if (tmout_var) {
10449 timeout = atoi(tmout_var) * 1000;
10450 if (timeout <= 0)
10451 timeout = -1;
10452 }
10453 }
Denys Vlasenko84ea60e2017-08-02 17:27:28 +020010454 line_input_state->timeout = timeout;
Denys Vlasenko66c5b122011-02-08 05:07:02 +010010455# endif
Denys Vlasenko8c52f802011-02-04 17:36:21 +010010456# if ENABLE_FEATURE_TAB_COMPLETION
Denis Vlasenko8e1c7152007-01-22 07:21:38 +000010457 line_input_state->path_lookup = pathval();
Denys Vlasenko8c52f802011-02-04 17:36:21 +010010458# endif
Denys Vlasenkoe9ab07c2014-08-13 18:00:08 +020010459 reinit_unicode_for_ash();
Denys Vlasenko84ea60e2017-08-02 17:27:28 +020010460 nr = read_line_input(line_input_state, cmdedit_prompt, buf, IBUFSIZ);
Denis Vlasenko8e1c7152007-01-22 07:21:38 +000010461 if (nr == 0) {
Denys Vlasenko4b89d512016-11-25 03:41:03 +010010462 /* ^C pressed, "convert" to SIGINT */
10463 write(STDOUT_FILENO, "^C", 2);
Denis Vlasenko8e1c7152007-01-22 07:21:38 +000010464 if (trap[SIGINT]) {
Glenn L McGrath16e45d72004-02-04 08:24:39 +000010465 buf[0] = '\n';
Denis Vlasenko8e1c7152007-01-22 07:21:38 +000010466 buf[1] = '\0';
Glenn L McGrath16e45d72004-02-04 08:24:39 +000010467 raise(SIGINT);
10468 return 1;
10469 }
Denys Vlasenko8660aeb2016-11-24 17:44:02 +010010470 exitstatus = 128 + SIGINT;
Denys Vlasenko4b89d512016-11-25 03:41:03 +010010471 bb_putchar('\n');
Eric Andersenc470f442003-07-28 09:56:35 +000010472 goto retry;
10473 }
Denys Vlasenko66c5b122011-02-08 05:07:02 +010010474 if (nr < 0) {
10475 if (errno == 0) {
10476 /* Ctrl+D pressed */
10477 nr = 0;
10478 }
10479# if ENABLE_ASH_IDLE_TIMEOUT
10480 else if (errno == EAGAIN && timeout > 0) {
Denys Vlasenkod60752f2015-10-07 22:42:45 +020010481 puts("\007timed out waiting for input: auto-logout");
Denys Vlasenko66c5b122011-02-08 05:07:02 +010010482 exitshell();
10483 }
10484# endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010485 }
Eric Andersencb57d552001-06-28 07:25:16 +000010486 }
10487#else
Ron Yorston61d6ae22015-04-19 10:50:25 +010010488 nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1);
Eric Andersencb57d552001-06-28 07:25:16 +000010489#endif
10490
Denys Vlasenko80c5b682011-05-08 21:21:10 +020010491#if 0 /* disabled: nonblock_immune_read() handles this problem */
Eric Andersencb57d552001-06-28 07:25:16 +000010492 if (nr < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +000010493 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
Denis Vlasenkod37f2222007-08-19 13:42:08 +000010494 int flags = fcntl(0, F_GETFL);
Denis Vlasenko9cb220b2007-12-09 10:03:28 +000010495 if (flags >= 0 && (flags & O_NONBLOCK)) {
10496 flags &= ~O_NONBLOCK;
Eric Andersencb57d552001-06-28 07:25:16 +000010497 if (fcntl(0, F_SETFL, flags) >= 0) {
10498 out2str("sh: turning off NDELAY mode\n");
10499 goto retry;
10500 }
10501 }
10502 }
10503 }
Denis Vlasenkoe376d452008-02-20 22:23:24 +000010504#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010505 return nr;
10506}
10507
10508/*
10509 * Refill the input buffer and return the next input character:
10510 *
10511 * 1) If a string was pushed back on the input, pop it;
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010512 * 2) If an EOF was pushed back (g_parsefile->left_in_line < -BIGNUM)
10513 * or we are reading from a string so we can't refill the buffer,
10514 * return EOF.
Denys Vlasenko883cea42009-07-11 15:31:59 +020010515 * 3) If there is more stuff in this buffer, use it else call read to fill it.
Eric Andersencb57d552001-06-28 07:25:16 +000010516 * 4) Process input up to the next newline, deleting nul characters.
10517 */
Denis Vlasenko727752d2008-11-28 03:41:47 +000010518//#define pgetc_debug(...) bb_error_msg(__VA_ARGS__)
10519#define pgetc_debug(...) ((void)0)
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010520static int pgetc(void);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010521static int
Eric Andersenc470f442003-07-28 09:56:35 +000010522preadbuffer(void)
Eric Andersencb57d552001-06-28 07:25:16 +000010523{
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010524 char *q;
Eric Andersencb57d552001-06-28 07:25:16 +000010525 int more;
Eric Andersencb57d552001-06-28 07:25:16 +000010526
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010527 if (g_parsefile->strpush) {
Denis Vlasenko131ae172007-02-18 13:00:19 +000010528#if ENABLE_ASH_ALIAS
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010529 if (g_parsefile->left_in_line == -1
10530 && g_parsefile->strpush->ap
10531 && g_parsefile->next_to_pgetc[-1] != ' '
10532 && g_parsefile->next_to_pgetc[-1] != '\t'
Denis Vlasenko16898402008-11-25 01:34:52 +000010533 ) {
Denis Vlasenko727752d2008-11-28 03:41:47 +000010534 pgetc_debug("preadbuffer PEOA");
Eric Andersencb57d552001-06-28 07:25:16 +000010535 return PEOA;
10536 }
Eric Andersen2870d962001-07-02 17:27:21 +000010537#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010538 popstring();
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010539 return pgetc();
Eric Andersencb57d552001-06-28 07:25:16 +000010540 }
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010541 /* on both branches above g_parsefile->left_in_line < 0.
Denis Vlasenko727752d2008-11-28 03:41:47 +000010542 * "pgetc" needs refilling.
10543 */
10544
Denis Vlasenkoe27dafd2008-11-28 04:01:03 +000010545 /* -90 is our -BIGNUM. Below we use -99 to mark "EOF on read",
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010546 * pungetc() may increment it a few times.
Denis Vlasenkoe27dafd2008-11-28 04:01:03 +000010547 * Assuming it won't increment it to less than -90.
Denis Vlasenko727752d2008-11-28 03:41:47 +000010548 */
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010549 if (g_parsefile->left_in_line < -90 || g_parsefile->buf == NULL) {
Denis Vlasenko727752d2008-11-28 03:41:47 +000010550 pgetc_debug("preadbuffer PEOF1");
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010551 /* even in failure keep left_in_line and next_to_pgetc
10552 * in lock step, for correct multi-layer pungetc.
10553 * left_in_line was decremented before preadbuffer(),
10554 * must inc next_to_pgetc: */
10555 g_parsefile->next_to_pgetc++;
Eric Andersencb57d552001-06-28 07:25:16 +000010556 return PEOF;
Denis Vlasenko727752d2008-11-28 03:41:47 +000010557 }
Eric Andersencb57d552001-06-28 07:25:16 +000010558
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010559 more = g_parsefile->left_in_buffer;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010560 if (more <= 0) {
Denis Vlasenko727752d2008-11-28 03:41:47 +000010561 flush_stdout_stderr();
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010562 again:
10563 more = preadfd();
10564 if (more <= 0) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010565 /* don't try reading again */
10566 g_parsefile->left_in_line = -99;
Denis Vlasenko727752d2008-11-28 03:41:47 +000010567 pgetc_debug("preadbuffer PEOF2");
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010568 g_parsefile->next_to_pgetc++;
Eric Andersencb57d552001-06-28 07:25:16 +000010569 return PEOF;
10570 }
10571 }
10572
Denis Vlasenko727752d2008-11-28 03:41:47 +000010573 /* Find out where's the end of line.
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010574 * Set g_parsefile->left_in_line
10575 * and g_parsefile->left_in_buffer acordingly.
Denis Vlasenko727752d2008-11-28 03:41:47 +000010576 * NUL chars are deleted.
10577 */
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010578 q = g_parsefile->next_to_pgetc;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010579 for (;;) {
Denis Vlasenko727752d2008-11-28 03:41:47 +000010580 char c;
Eric Andersencb57d552001-06-28 07:25:16 +000010581
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010582 more--;
Eric Andersenc470f442003-07-28 09:56:35 +000010583
Denis Vlasenko727752d2008-11-28 03:41:47 +000010584 c = *q;
10585 if (c == '\0') {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010586 memmove(q, q + 1, more);
Denis Vlasenko727752d2008-11-28 03:41:47 +000010587 } else {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010588 q++;
10589 if (c == '\n') {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010590 g_parsefile->left_in_line = q - g_parsefile->next_to_pgetc - 1;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010591 break;
10592 }
Eric Andersencb57d552001-06-28 07:25:16 +000010593 }
10594
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010595 if (more <= 0) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010596 g_parsefile->left_in_line = q - g_parsefile->next_to_pgetc - 1;
10597 if (g_parsefile->left_in_line < 0)
Eric Andersencb57d552001-06-28 07:25:16 +000010598 goto again;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010599 break;
Eric Andersencb57d552001-06-28 07:25:16 +000010600 }
10601 }
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010602 g_parsefile->left_in_buffer = more;
Eric Andersencb57d552001-06-28 07:25:16 +000010603
Eric Andersencb57d552001-06-28 07:25:16 +000010604 if (vflag) {
Denis Vlasenko727752d2008-11-28 03:41:47 +000010605 char save = *q;
10606 *q = '\0';
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010607 out2str(g_parsefile->next_to_pgetc);
Denis Vlasenko727752d2008-11-28 03:41:47 +000010608 *q = save;
Eric Andersencb57d552001-06-28 07:25:16 +000010609 }
10610
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010611 pgetc_debug("preadbuffer at %d:%p'%s'",
10612 g_parsefile->left_in_line,
10613 g_parsefile->next_to_pgetc,
10614 g_parsefile->next_to_pgetc);
Denys Vlasenkocd716832009-11-28 22:14:02 +010010615 return (unsigned char)*g_parsefile->next_to_pgetc++;
Eric Andersencb57d552001-06-28 07:25:16 +000010616}
10617
Denys Vlasenkoce332a22016-10-02 23:47:34 +020010618static void
10619nlprompt(void)
10620{
10621 g_parsefile->linno++;
10622 setprompt_if(doprompt, 2);
10623}
10624static void
10625nlnoprompt(void)
10626{
10627 g_parsefile->linno++;
10628 needprompt = doprompt;
10629}
10630
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010631static int
10632pgetc(void)
10633{
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010634 int c;
10635
10636 pgetc_debug("pgetc at %d:%p'%s'",
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010637 g_parsefile->left_in_line,
10638 g_parsefile->next_to_pgetc,
10639 g_parsefile->next_to_pgetc);
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010640 if (g_parsefile->unget)
10641 return g_parsefile->lastc[--g_parsefile->unget];
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010642
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010643 if (--g_parsefile->left_in_line >= 0)
Denys Vlasenko2fe66b12016-12-12 17:39:12 +010010644 c = (unsigned char)*g_parsefile->next_to_pgetc++;
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010645 else
10646 c = preadbuffer();
10647
10648 g_parsefile->lastc[1] = g_parsefile->lastc[0];
10649 g_parsefile->lastc[0] = c;
10650
10651 return c;
10652}
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010653
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010654#if ENABLE_ASH_ALIAS
10655static int
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010010656pgetc_without_PEOA(void)
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010657{
10658 int c;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010659 do {
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010660 pgetc_debug("pgetc at %d:%p'%s'",
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010661 g_parsefile->left_in_line,
10662 g_parsefile->next_to_pgetc,
10663 g_parsefile->next_to_pgetc);
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010664 c = pgetc();
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010665 } while (c == PEOA);
10666 return c;
10667}
10668#else
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010010669# define pgetc_without_PEOA() pgetc()
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010670#endif
10671
10672/*
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010673 * Undo a call to pgetc. Only two characters may be pushed back.
Eric Andersenc470f442003-07-28 09:56:35 +000010674 * PEOF may be pushed back.
10675 */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010676static void
Eric Andersenc470f442003-07-28 09:56:35 +000010677pungetc(void)
10678{
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010679 g_parsefile->unget++;
Eric Andersencb57d552001-06-28 07:25:16 +000010680}
10681
Denys Vlasenko73c3e072016-09-29 17:17:04 +020010682/* This one eats backslash+newline */
10683static int
10684pgetc_eatbnl(void)
10685{
10686 int c;
10687
10688 while ((c = pgetc()) == '\\') {
10689 if (pgetc() != '\n') {
10690 pungetc();
10691 break;
10692 }
10693
Denys Vlasenkoce332a22016-10-02 23:47:34 +020010694 nlprompt();
Denys Vlasenko73c3e072016-09-29 17:17:04 +020010695 }
10696
10697 return c;
10698}
10699
Denys Vlasenko216913c2018-04-02 12:35:04 +020010700struct synstack {
10701 smalluint syntax;
10702 uint8_t innerdq :1;
10703 uint8_t varpushed :1;
10704 uint8_t dblquote :1;
10705 int varnest; /* levels of variables expansion */
10706 int dqvarnest; /* levels of variables expansion within double quotes */
10707 int parenlevel; /* levels of parens in arithmetic */
10708 struct synstack *prev;
10709 struct synstack *next;
10710};
10711
10712static void
10713synstack_push(struct synstack **stack, struct synstack *next, int syntax)
10714{
10715 memset(next, 0, sizeof(*next));
10716 next->syntax = syntax;
10717 next->next = *stack;
10718 (*stack)->prev = next;
10719 *stack = next;
10720}
10721
10722static ALWAYS_INLINE void
10723synstack_pop(struct synstack **stack)
10724{
10725 *stack = (*stack)->next;
10726}
10727
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010728/*
10729 * To handle the "." command, a stack of input files is used. Pushfile
10730 * adds a new entry to the stack and popfile restores the previous level.
10731 */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010732static void
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010733pushfile(void)
Eric Andersenc470f442003-07-28 09:56:35 +000010734{
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010735 struct parsefile *pf;
10736
Denis Vlasenko597906c2008-02-20 16:38:54 +000010737 pf = ckzalloc(sizeof(*pf));
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010738 pf->prev = g_parsefile;
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010739 pf->pf_fd = -1;
Denis Vlasenko597906c2008-02-20 16:38:54 +000010740 /*pf->strpush = NULL; - ckzalloc did it */
10741 /*pf->basestrpush.prev = NULL;*/
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010742 /*pf->unget = 0;*/
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010743 g_parsefile = pf;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010744}
10745
10746static void
10747popfile(void)
10748{
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010749 struct parsefile *pf = g_parsefile;
Eric Andersenc470f442003-07-28 09:56:35 +000010750
Denys Vlasenko493b9ca2016-10-30 18:27:14 +010010751 if (pf == &basepf)
10752 return;
10753
Denis Vlasenkob012b102007-02-19 22:43:01 +000010754 INT_OFF;
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010755 if (pf->pf_fd >= 0)
10756 close(pf->pf_fd);
Denis Vlasenko60818682007-09-28 22:07:23 +000010757 free(pf->buf);
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010758 while (pf->strpush)
10759 popstring();
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010760 g_parsefile = pf->prev;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010761 free(pf);
Denis Vlasenkob012b102007-02-19 22:43:01 +000010762 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +000010763}
10764
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010765/*
10766 * Return to top level.
10767 */
10768static void
10769popallfiles(void)
10770{
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010771 while (g_parsefile != &basepf)
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010772 popfile();
10773}
10774
10775/*
10776 * Close the file(s) that the shell is reading commands from. Called
10777 * after a fork is done.
10778 */
10779static void
10780closescript(void)
10781{
10782 popallfiles();
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010783 if (g_parsefile->pf_fd > 0) {
10784 close(g_parsefile->pf_fd);
10785 g_parsefile->pf_fd = 0;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010786 }
10787}
10788
10789/*
10790 * Like setinputfile, but takes an open file descriptor. Call this with
10791 * interrupts off.
10792 */
10793static void
10794setinputfd(int fd, int push)
10795{
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010796 if (push) {
10797 pushfile();
Denis Vlasenko727752d2008-11-28 03:41:47 +000010798 g_parsefile->buf = NULL;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010799 }
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010800 g_parsefile->pf_fd = fd;
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010801 if (g_parsefile->buf == NULL)
10802 g_parsefile->buf = ckmalloc(IBUFSIZ);
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010803 g_parsefile->left_in_buffer = 0;
10804 g_parsefile->left_in_line = 0;
10805 g_parsefile->linno = 1;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010806}
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010807
Eric Andersenc470f442003-07-28 09:56:35 +000010808/*
10809 * Set the input to take input from a file. If push is set, push the
10810 * old input onto the stack first.
10811 */
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010812static int
10813setinputfile(const char *fname, int flags)
Eric Andersenc470f442003-07-28 09:56:35 +000010814{
10815 int fd;
Eric Andersenc470f442003-07-28 09:56:35 +000010816
Denis Vlasenkob012b102007-02-19 22:43:01 +000010817 INT_OFF;
Denys Vlasenko60fb98e2018-03-30 22:15:14 +020010818 fd = open(fname, O_RDONLY | O_CLOEXEC);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010819 if (fd < 0) {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010820 if (flags & INPUT_NOFILE_OK)
10821 goto out;
Denys Vlasenkob7adf7a2016-10-25 17:00:13 +020010822 exitstatus = 127;
Johannes Schindelin20a63b22017-08-22 22:03:17 +020010823 ash_msg_and_raise_perror("can't open '%s'", fname);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010824 }
Denys Vlasenko64774602016-10-26 15:24:30 +020010825 if (fd < 10)
10826 fd = savefd(fd);
Denys Vlasenko60fb98e2018-03-30 22:15:14 +020010827 else if (O_CLOEXEC == 0) /* old libc */
Denys Vlasenkoe19923f2016-10-26 15:38:44 +020010828 close_on_exec_on(fd);
Denys Vlasenko60fb98e2018-03-30 22:15:14 +020010829
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010830 setinputfd(fd, flags & INPUT_PUSH_FILE);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010831 out:
Denis Vlasenkob012b102007-02-19 22:43:01 +000010832 INT_ON;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010833 return fd;
Eric Andersenc470f442003-07-28 09:56:35 +000010834}
10835
Eric Andersencb57d552001-06-28 07:25:16 +000010836/*
10837 * Like setinputfile, but takes input from a string.
10838 */
Eric Andersenc470f442003-07-28 09:56:35 +000010839static void
10840setinputstring(char *string)
Eric Andersen62483552001-07-10 06:09:16 +000010841{
Denis Vlasenkob012b102007-02-19 22:43:01 +000010842 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +000010843 pushfile();
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010844 g_parsefile->next_to_pgetc = string;
10845 g_parsefile->left_in_line = strlen(string);
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010846 g_parsefile->buf = NULL;
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010847 g_parsefile->linno = 1;
Denis Vlasenkob012b102007-02-19 22:43:01 +000010848 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +000010849}
10850
10851
Denys Vlasenko70392332016-10-27 02:31:55 +020010852/*
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010853 * Routines to check for mail.
Eric Andersencb57d552001-06-28 07:25:16 +000010854 */
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010855
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010856#if ENABLE_ASH_MAIL
Eric Andersencb57d552001-06-28 07:25:16 +000010857
Denys Vlasenko23841622015-10-09 15:52:03 +020010858/* Hash of mtimes of mailboxes */
10859static unsigned mailtime_hash;
Eric Andersenc470f442003-07-28 09:56:35 +000010860/* Set if MAIL or MAILPATH is changed. */
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010861static smallint mail_var_path_changed;
Eric Andersencb57d552001-06-28 07:25:16 +000010862
Eric Andersencb57d552001-06-28 07:25:16 +000010863/*
Eric Andersenc470f442003-07-28 09:56:35 +000010864 * Print appropriate message(s) if mail has arrived.
10865 * If mail_var_path_changed is set,
10866 * then the value of MAIL has mail_var_path_changed,
10867 * so we just update the values.
Eric Andersencb57d552001-06-28 07:25:16 +000010868 */
Eric Andersenc470f442003-07-28 09:56:35 +000010869static void
10870chkmail(void)
Eric Andersencb57d552001-06-28 07:25:16 +000010871{
Eric Andersencb57d552001-06-28 07:25:16 +000010872 const char *mpath;
10873 char *p;
10874 char *q;
Denys Vlasenko23841622015-10-09 15:52:03 +020010875 unsigned new_hash;
Eric Andersencb57d552001-06-28 07:25:16 +000010876 struct stackmark smark;
10877 struct stat statb;
10878
Eric Andersencb57d552001-06-28 07:25:16 +000010879 setstackmark(&smark);
Eric Andersenc470f442003-07-28 09:56:35 +000010880 mpath = mpathset() ? mpathval() : mailval();
Denys Vlasenko23841622015-10-09 15:52:03 +020010881 new_hash = 0;
10882 for (;;) {
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020010883 p = path_advance(&mpath, nullstr);
Eric Andersencb57d552001-06-28 07:25:16 +000010884 if (p == NULL)
10885 break;
10886 if (*p == '\0')
10887 continue;
Denis Vlasenkof7d56652008-03-25 05:51:41 +000010888 for (q = p; *q; q++)
10889 continue;
Denis Vlasenkoa7189f02006-11-17 20:29:00 +000010890#if DEBUG
Eric Andersencb57d552001-06-28 07:25:16 +000010891 if (q[-1] != '/')
10892 abort();
10893#endif
Eric Andersenc470f442003-07-28 09:56:35 +000010894 q[-1] = '\0'; /* delete trailing '/' */
10895 if (stat(p, &statb) < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +000010896 continue;
Eric Andersencb57d552001-06-28 07:25:16 +000010897 }
Denys Vlasenko23841622015-10-09 15:52:03 +020010898 /* Very simplistic "hash": just a sum of all mtimes */
10899 new_hash += (unsigned)statb.st_mtime;
10900 }
10901 if (!mail_var_path_changed && mailtime_hash != new_hash) {
Denys Vlasenko4cd99e72015-10-09 16:02:53 +020010902 if (mailtime_hash != 0)
10903 out2str("you have mail\n");
Denys Vlasenko23841622015-10-09 15:52:03 +020010904 mailtime_hash = new_hash;
Eric Andersencb57d552001-06-28 07:25:16 +000010905 }
Eric Andersenc470f442003-07-28 09:56:35 +000010906 mail_var_path_changed = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010907 popstackmark(&smark);
10908}
Eric Andersencb57d552001-06-28 07:25:16 +000010909
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010910static void FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010911changemail(const char *val UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000010912{
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010913 mail_var_path_changed = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000010914}
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010915
Denis Vlasenko131ae172007-02-18 13:00:19 +000010916#endif /* ASH_MAIL */
Eric Andersenc470f442003-07-28 09:56:35 +000010917
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010918
10919/* ============ ??? */
10920
Eric Andersencb57d552001-06-28 07:25:16 +000010921/*
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010922 * Set the shell parameters.
Eric Andersencb57d552001-06-28 07:25:16 +000010923 */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010924static void
10925setparam(char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000010926{
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010927 char **newparam;
10928 char **ap;
10929 int nparam;
Eric Andersencb57d552001-06-28 07:25:16 +000010930
Denis Vlasenkof7d56652008-03-25 05:51:41 +000010931 for (nparam = 0; argv[nparam]; nparam++)
10932 continue;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010933 ap = newparam = ckmalloc((nparam + 1) * sizeof(*ap));
10934 while (*argv) {
10935 *ap++ = ckstrdup(*argv++);
Eric Andersencb57d552001-06-28 07:25:16 +000010936 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010937 *ap = NULL;
10938 freeparam(&shellparam);
Denis Vlasenko01631112007-12-16 17:20:38 +000010939 shellparam.malloced = 1;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010940 shellparam.nparam = nparam;
10941 shellparam.p = newparam;
10942#if ENABLE_ASH_GETOPTS
10943 shellparam.optind = 1;
10944 shellparam.optoff = -1;
10945#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010946}
10947
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010948/*
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010949 * Process shell options. The global variable argptr contains a pointer
10950 * to the argument list; we advance it past the options.
Denis Vlasenko94e87bc2008-02-14 16:51:58 +000010951 *
10952 * SUSv3 section 2.8.1 "Consequences of Shell Errors" says:
10953 * For a non-interactive shell, an error condition encountered
10954 * by a special built-in ... shall cause the shell to write a diagnostic message
10955 * to standard error and exit as shown in the following table:
Denis Vlasenko56244732008-02-17 15:14:04 +000010956 * Error Special Built-In
Denis Vlasenko94e87bc2008-02-14 16:51:58 +000010957 * ...
10958 * Utility syntax error (option or operand error) Shall exit
10959 * ...
10960 * However, in bug 1142 (http://busybox.net/bugs/view.php?id=1142)
10961 * we see that bash does not do that (set "finishes" with error code 1 instead,
10962 * and shell continues), and people rely on this behavior!
10963 * Testcase:
10964 * set -o barfoo 2>/dev/null
10965 * echo $?
10966 *
10967 * Oh well. Let's mimic that.
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010968 */
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010969static int
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010970plus_minus_o(char *name, int val)
Eric Andersen62483552001-07-10 06:09:16 +000010971{
10972 int i;
10973
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010974 if (name) {
10975 for (i = 0; i < NOPTS; i++) {
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000010976 if (strcmp(name, optnames(i)) == 0) {
Eric Andersenc470f442003-07-28 09:56:35 +000010977 optlist[i] = val;
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010978 return 0;
Eric Andersen62483552001-07-10 06:09:16 +000010979 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010980 }
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010981 ash_msg("illegal option %co %s", val ? '-' : '+', name);
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010982 return 1;
Eric Andersen62483552001-07-10 06:09:16 +000010983 }
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000010984 for (i = 0; i < NOPTS; i++) {
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010985 if (val) {
10986 out1fmt("%-16s%s\n", optnames(i), optlist[i] ? "on" : "off");
10987 } else {
10988 out1fmt("set %co %s\n", optlist[i] ? '-' : '+', optnames(i));
10989 }
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000010990 }
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010991 return 0;
Eric Andersen62483552001-07-10 06:09:16 +000010992}
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010993static void
10994setoption(int flag, int val)
10995{
10996 int i;
10997
10998 for (i = 0; i < NOPTS; i++) {
10999 if (optletters(i) == flag) {
11000 optlist[i] = val;
11001 return;
11002 }
11003 }
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000011004 ash_msg_and_raise_error("illegal option %c%c", val ? '-' : '+', flag);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011005 /* NOTREACHED */
11006}
Denis Vlasenko28bf6712008-02-14 15:01:47 +000011007static int
Denys Vlasenkoec05df12017-07-31 19:43:47 +020011008options(int cmdline, int *login_sh)
Eric Andersencb57d552001-06-28 07:25:16 +000011009{
11010 char *p;
11011 int val;
11012 int c;
11013
11014 if (cmdline)
11015 minusc = NULL;
11016 while ((p = *argptr) != NULL) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011017 c = *p++;
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000011018 if (c != '-' && c != '+')
11019 break;
11020 argptr++;
11021 val = 0; /* val = 0 if c == '+' */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011022 if (c == '-') {
Eric Andersencb57d552001-06-28 07:25:16 +000011023 val = 1;
Denis Vlasenko9f739442006-12-16 23:49:13 +000011024 if (p[0] == '\0' || LONE_DASH(p)) {
Eric Andersen2870d962001-07-02 17:27:21 +000011025 if (!cmdline) {
11026 /* "-" means turn off -x and -v */
11027 if (p[0] == '\0')
11028 xflag = vflag = 0;
11029 /* "--" means reset params */
11030 else if (*argptr == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +000011031 setparam(argptr);
Eric Andersen2870d962001-07-02 17:27:21 +000011032 }
Denys Vlasenkob0b83432011-03-07 12:34:59 +010011033 break; /* "-" or "--" terminates options */
Eric Andersencb57d552001-06-28 07:25:16 +000011034 }
Eric Andersencb57d552001-06-28 07:25:16 +000011035 }
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000011036 /* first char was + or - */
Eric Andersencb57d552001-06-28 07:25:16 +000011037 while ((c = *p++) != '\0') {
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000011038 /* bash 3.2 indeed handles -c CMD and +c CMD the same */
Eric Andersencb57d552001-06-28 07:25:16 +000011039 if (c == 'c' && cmdline) {
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000011040 minusc = p; /* command is after shell args */
Eric Andersencb57d552001-06-28 07:25:16 +000011041 } else if (c == 'o') {
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000011042 if (plus_minus_o(*argptr, val)) {
Denis Vlasenko28bf6712008-02-14 15:01:47 +000011043 /* it already printed err message */
11044 return 1; /* error */
11045 }
Eric Andersencb57d552001-06-28 07:25:16 +000011046 if (*argptr)
11047 argptr++;
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000011048 } else if (cmdline && (c == 'l')) { /* -l or +l == --login */
Denys Vlasenkoec05df12017-07-31 19:43:47 +020011049 if (login_sh)
11050 *login_sh = 1;
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000011051 /* bash does not accept +-login, we also won't */
11052 } else if (cmdline && val && (c == '-')) { /* long options */
Denys Vlasenkoec05df12017-07-31 19:43:47 +020011053 if (strcmp(p, "login") == 0) {
11054 if (login_sh)
11055 *login_sh = 1;
11056 }
Robert Griebl64f70cc2002-05-14 23:22:06 +000011057 break;
Eric Andersencb57d552001-06-28 07:25:16 +000011058 } else {
11059 setoption(c, val);
11060 }
11061 }
11062 }
Denis Vlasenko28bf6712008-02-14 15:01:47 +000011063 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +000011064}
11065
Eric Andersencb57d552001-06-28 07:25:16 +000011066/*
Eric Andersencb57d552001-06-28 07:25:16 +000011067 * The shift builtin command.
11068 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020011069static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000011070shiftcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000011071{
11072 int n;
11073 char **ap1, **ap2;
11074
11075 n = 1;
Denis Vlasenko68404f12008-03-17 09:00:54 +000011076 if (argv[1])
Eric Andersencb57d552001-06-28 07:25:16 +000011077 n = number(argv[1]);
11078 if (n > shellparam.nparam)
Ingo van Lil9c8e94b2018-01-05 15:04:23 +010011079 return 1;
Denis Vlasenkob012b102007-02-19 22:43:01 +000011080 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +000011081 shellparam.nparam -= n;
Denis Vlasenko2da584f2007-02-19 22:44:05 +000011082 for (ap1 = shellparam.p; --n >= 0; ap1++) {
Denis Vlasenko01631112007-12-16 17:20:38 +000011083 if (shellparam.malloced)
Denis Vlasenkob012b102007-02-19 22:43:01 +000011084 free(*ap1);
Eric Andersencb57d552001-06-28 07:25:16 +000011085 }
11086 ap2 = shellparam.p;
Denis Vlasenkof7d56652008-03-25 05:51:41 +000011087 while ((*ap2++ = *ap1++) != NULL)
11088 continue;
Denis Vlasenko131ae172007-02-18 13:00:19 +000011089#if ENABLE_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +000011090 shellparam.optind = 1;
11091 shellparam.optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +000011092#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +000011093 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +000011094 return 0;
11095}
11096
Eric Andersencb57d552001-06-28 07:25:16 +000011097/*
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011098 * POSIX requires that 'set' (but not export or readonly) output the
11099 * variables in lexicographic order - by the locale's collating order (sigh).
11100 * Maybe we could keep them in an ordered balanced binary tree
11101 * instead of hashed lists.
11102 * For now just roll 'em through qsort for printing...
11103 */
11104static int
11105showvars(const char *sep_prefix, int on, int off)
11106{
11107 const char *sep;
11108 char **ep, **epend;
11109
Denys Vlasenkoa5060b82017-11-03 14:16:25 +010011110 ep = listvars(on, off, /*strlist:*/ NULL, &epend);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011111 qsort(ep, epend - ep, sizeof(char *), vpcmp);
11112
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000011113 sep = *sep_prefix ? " " : sep_prefix;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011114
11115 for (; ep < epend; ep++) {
11116 const char *p;
11117 const char *q;
11118
Denys Vlasenko9c143ce2017-11-02 12:56:24 +010011119 p = endofname(*ep);
11120/* Used to have simple "p = strchrnul(*ep, '=')" here instead, but this
11121 * makes "export -p" to have output not suitable for "eval":
11122 * import os
11123 * os.environ["test-test"]="test"
11124 * if os.fork() == 0:
11125 * os.execv("ash", [ 'ash', '-c', 'eval $(export -p); echo OK' ]) # fixes this
11126 * os.execv("ash", [ 'ash', '-c', 'env | grep test-test' ])
11127 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011128 q = nullstr;
Denys Vlasenko9c143ce2017-11-02 12:56:24 +010011129 if (*p == '=')
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011130 q = single_quote(++p);
11131 out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
11132 }
11133 return 0;
11134}
11135
11136/*
Eric Andersencb57d552001-06-28 07:25:16 +000011137 * The set command builtin.
11138 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020011139static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000011140setcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +000011141{
Denis Vlasenko28bf6712008-02-14 15:01:47 +000011142 int retval;
11143
Denis Vlasenko68404f12008-03-17 09:00:54 +000011144 if (!argv[1])
Eric Andersenc470f442003-07-28 09:56:35 +000011145 return showvars(nullstr, 0, VUNSET);
Denys Vlasenkob0b83432011-03-07 12:34:59 +010011146
Denis Vlasenkob012b102007-02-19 22:43:01 +000011147 INT_OFF;
Denys Vlasenkoec05df12017-07-31 19:43:47 +020011148 retval = options(/*cmdline:*/ 0, NULL);
Denys Vlasenkob0b83432011-03-07 12:34:59 +010011149 if (retval == 0) { /* if no parse error... */
Denis Vlasenko28bf6712008-02-14 15:01:47 +000011150 optschanged();
11151 if (*argptr != NULL) {
11152 setparam(argptr);
11153 }
Eric Andersencb57d552001-06-28 07:25:16 +000011154 }
Denis Vlasenkob012b102007-02-19 22:43:01 +000011155 INT_ON;
Denis Vlasenko28bf6712008-02-14 15:01:47 +000011156 return retval;
Eric Andersencb57d552001-06-28 07:25:16 +000011157}
11158
Denis Vlasenko131ae172007-02-18 13:00:19 +000011159#if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020011160static void FAST_FUNC
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000011161change_random(const char *value)
Eric Andersenef02f822004-03-11 13:34:24 +000011162{
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020011163 uint32_t t;
11164
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011165 if (value == NULL) {
Eric Andersen16767e22004-03-16 05:14:10 +000011166 /* "get", generate */
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020011167 t = next_random(&random_gen);
Eric Andersen16767e22004-03-16 05:14:10 +000011168 /* set without recursion */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +020011169 setvar(vrandom.var_text, utoa(t), VNOFUNC);
Eric Andersen16767e22004-03-16 05:14:10 +000011170 vrandom.flags &= ~VNOFUNC;
11171 } else {
11172 /* set/reset */
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020011173 t = strtoul(value, NULL, 10);
11174 INIT_RANDOM_T(&random_gen, (t ? t : 1), t);
Eric Andersen16767e22004-03-16 05:14:10 +000011175 }
Eric Andersenef02f822004-03-11 13:34:24 +000011176}
Eric Andersen16767e22004-03-16 05:14:10 +000011177#endif
11178
Denis Vlasenko131ae172007-02-18 13:00:19 +000011179#if ENABLE_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +000011180static int
Denys Vlasenko35c2a132016-10-26 17:34:26 +020011181getopts(char *optstr, char *optvar, char **optfirst)
Eric Andersencb57d552001-06-28 07:25:16 +000011182{
11183 char *p, *q;
11184 char c = '?';
11185 int done = 0;
Denys Vlasenko9c541002015-10-07 15:44:36 +020011186 char sbuf[2];
Eric Andersena48b0a32003-10-22 10:56:47 +000011187 char **optnext;
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020011188 int ind = shellparam.optind;
11189 int off = shellparam.optoff;
Eric Andersencb57d552001-06-28 07:25:16 +000011190
Denys Vlasenko9c541002015-10-07 15:44:36 +020011191 sbuf[1] = '\0';
11192
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020011193 shellparam.optind = -1;
11194 optnext = optfirst + ind - 1;
Eric Andersena48b0a32003-10-22 10:56:47 +000011195
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020011196 if (ind <= 1 || off < 0 || (int)strlen(optnext[-1]) < off)
Eric Andersencb57d552001-06-28 07:25:16 +000011197 p = NULL;
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020011198 else
11199 p = optnext[-1] + off;
Eric Andersencb57d552001-06-28 07:25:16 +000011200 if (p == NULL || *p == '\0') {
11201 /* Current word is done, advance */
Eric Andersencb57d552001-06-28 07:25:16 +000011202 p = *optnext;
11203 if (p == NULL || *p != '-' || *++p == '\0') {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011204 atend:
Denys Vlasenko9832bba2017-08-15 15:44:41 +020011205 unsetvar("OPTARG");
Eric Andersencb57d552001-06-28 07:25:16 +000011206 p = NULL;
11207 done = 1;
11208 goto out;
11209 }
11210 optnext++;
Denis Vlasenko9f739442006-12-16 23:49:13 +000011211 if (LONE_DASH(p)) /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +000011212 goto atend;
11213 }
11214
11215 c = *p++;
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +000011216 for (q = optstr; *q != c;) {
Eric Andersencb57d552001-06-28 07:25:16 +000011217 if (*q == '\0') {
Denys Vlasenko9832bba2017-08-15 15:44:41 +020011218 /* OPTERR is a bashism */
11219 const char *cp = lookupvar("OPTERR");
11220 if ((cp && LONE_CHAR(cp, '0'))
11221 || (optstr[0] == ':')
11222 ) {
Denys Vlasenko9c541002015-10-07 15:44:36 +020011223 sbuf[0] = c;
11224 /*sbuf[1] = '\0'; - already is */
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020011225 setvar0("OPTARG", sbuf);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011226 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000011227 fprintf(stderr, "Illegal option -%c\n", c);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011228 unsetvar("OPTARG");
Eric Andersencb57d552001-06-28 07:25:16 +000011229 }
11230 c = '?';
Eric Andersenc470f442003-07-28 09:56:35 +000011231 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +000011232 }
11233 if (*++q == ':')
11234 q++;
11235 }
11236
11237 if (*++q == ':') {
11238 if (*p == '\0' && (p = *optnext) == NULL) {
Denys Vlasenko9832bba2017-08-15 15:44:41 +020011239 /* OPTERR is a bashism */
11240 const char *cp = lookupvar("OPTERR");
11241 if ((cp && LONE_CHAR(cp, '0'))
11242 || (optstr[0] == ':')
11243 ) {
Denys Vlasenko9c541002015-10-07 15:44:36 +020011244 sbuf[0] = c;
11245 /*sbuf[1] = '\0'; - already is */
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020011246 setvar0("OPTARG", sbuf);
Eric Andersencb57d552001-06-28 07:25:16 +000011247 c = ':';
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011248 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000011249 fprintf(stderr, "No arg for -%c option\n", c);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011250 unsetvar("OPTARG");
Eric Andersencb57d552001-06-28 07:25:16 +000011251 c = '?';
11252 }
Eric Andersenc470f442003-07-28 09:56:35 +000011253 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +000011254 }
11255
11256 if (p == *optnext)
11257 optnext++;
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020011258 setvar0("OPTARG", p);
Eric Andersencb57d552001-06-28 07:25:16 +000011259 p = NULL;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011260 } else
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020011261 setvar0("OPTARG", nullstr);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011262 out:
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020011263 ind = optnext - optfirst + 1;
11264 setvar("OPTIND", itoa(ind), VNOFUNC);
Denys Vlasenko9c541002015-10-07 15:44:36 +020011265 sbuf[0] = c;
11266 /*sbuf[1] = '\0'; - already is */
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020011267 setvar0(optvar, sbuf);
11268
11269 shellparam.optoff = p ? p - *(optnext - 1) : -1;
11270 shellparam.optind = ind;
11271
Eric Andersencb57d552001-06-28 07:25:16 +000011272 return done;
11273}
Eric Andersenc470f442003-07-28 09:56:35 +000011274
11275/*
11276 * The getopts builtin. Shellparam.optnext points to the next argument
11277 * to be processed. Shellparam.optptr points to the next character to
11278 * be processed in the current argument. If shellparam.optnext is NULL,
11279 * then it's the first time getopts has been called.
11280 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020011281static int FAST_FUNC
Eric Andersenc470f442003-07-28 09:56:35 +000011282getoptscmd(int argc, char **argv)
11283{
11284 char **optbase;
11285
11286 if (argc < 3)
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +000011287 ash_msg_and_raise_error("usage: getopts optstring var [arg]");
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011288 if (argc == 3) {
Eric Andersenc470f442003-07-28 09:56:35 +000011289 optbase = shellparam.p;
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020011290 if ((unsigned)shellparam.optind > shellparam.nparam + 1) {
Eric Andersenc470f442003-07-28 09:56:35 +000011291 shellparam.optind = 1;
11292 shellparam.optoff = -1;
11293 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011294 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000011295 optbase = &argv[3];
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020011296 if ((unsigned)shellparam.optind > argc - 2) {
Eric Andersenc470f442003-07-28 09:56:35 +000011297 shellparam.optind = 1;
11298 shellparam.optoff = -1;
11299 }
11300 }
11301
Denys Vlasenko35c2a132016-10-26 17:34:26 +020011302 return getopts(argv[1], argv[2], optbase);
Eric Andersenc470f442003-07-28 09:56:35 +000011303}
Denis Vlasenko131ae172007-02-18 13:00:19 +000011304#endif /* ASH_GETOPTS */
Eric Andersencb57d552001-06-28 07:25:16 +000011305
Eric Andersencb57d552001-06-28 07:25:16 +000011306
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011307/* ============ Shell parser */
Eric Andersencb57d552001-06-28 07:25:16 +000011308
Denis Vlasenkob07a4962008-06-22 13:16:23 +000011309struct heredoc {
11310 struct heredoc *next; /* next here document in list */
11311 union node *here; /* redirection node */
11312 char *eofmark; /* string indicating end of input */
11313 smallint striptabs; /* if set, strip leading tabs */
11314};
11315
11316static smallint tokpushback; /* last token pushed back */
Denis Vlasenkob07a4962008-06-22 13:16:23 +000011317static smallint quoteflag; /* set if (part of) last token was quoted */
11318static token_id_t lasttoken; /* last token read (integer id Txxx) */
11319static struct heredoc *heredoclist; /* list of here documents to read */
11320static char *wordtext; /* text of last word returned by readtoken */
11321static struct nodelist *backquotelist;
11322static union node *redirnode;
11323static struct heredoc *heredoc;
Denis Vlasenko99eb8502007-02-23 21:09:49 +000011324
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020011325static const char *
11326tokname(char *buf, int tok)
11327{
11328 if (tok < TSEMI)
Denys Vlasenko888527c2016-10-02 16:54:17 +020011329 return tokname_array[tok];
11330 sprintf(buf, "\"%s\"", tokname_array[tok]);
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020011331 return buf;
11332}
11333
11334/* raise_error_unexpected_syntax:
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011335 * Called when an unexpected token is read during the parse. The argument
11336 * is the token that is expected, or -1 if more than one type of token can
11337 * occur at this point.
11338 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000011339static void raise_error_unexpected_syntax(int) NORETURN;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011340static void
11341raise_error_unexpected_syntax(int token)
11342{
11343 char msg[64];
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020011344 char buf[16];
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011345 int l;
11346
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020011347 l = sprintf(msg, "unexpected %s", tokname(buf, lasttoken));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011348 if (token >= 0)
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020011349 sprintf(msg + l, " (expecting %s)", tokname(buf, token));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011350 raise_error_syntax(msg);
11351 /* NOTREACHED */
11352}
Eric Andersencb57d552001-06-28 07:25:16 +000011353
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011354/* parsing is heavily cross-recursive, need these forward decls */
11355static union node *andor(void);
11356static union node *pipeline(void);
11357static union node *parse_command(void);
11358static void parseheredoc(void);
Ron Yorstonc0e00762015-10-29 11:30:55 +000011359static int peektoken(void);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011360static int readtoken(void);
Eric Andersencb57d552001-06-28 07:25:16 +000011361
Eric Andersenc470f442003-07-28 09:56:35 +000011362static union node *
11363list(int nlflag)
Eric Andersencb57d552001-06-28 07:25:16 +000011364{
11365 union node *n1, *n2, *n3;
11366 int tok;
11367
Eric Andersencb57d552001-06-28 07:25:16 +000011368 n1 = NULL;
11369 for (;;) {
Ron Yorstonc0e00762015-10-29 11:30:55 +000011370 switch (peektoken()) {
11371 case TNL:
11372 if (!(nlflag & 1))
11373 break;
11374 parseheredoc();
11375 return n1;
11376
11377 case TEOF:
11378 if (!n1 && (nlflag & 1))
11379 n1 = NODE_EOF;
11380 parseheredoc();
11381 return n1;
11382 }
11383
11384 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Denys Vlasenko888527c2016-10-02 16:54:17 +020011385 if (nlflag == 2 && ((1 << peektoken()) & tokendlist))
Ron Yorstonc0e00762015-10-29 11:30:55 +000011386 return n1;
11387 nlflag |= 2;
11388
Eric Andersencb57d552001-06-28 07:25:16 +000011389 n2 = andor();
11390 tok = readtoken();
11391 if (tok == TBACKGND) {
Eric Andersenc470f442003-07-28 09:56:35 +000011392 if (n2->type == NPIPE) {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +000011393 n2->npipe.pipe_backgnd = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011394 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000011395 if (n2->type != NREDIR) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011396 n3 = stzalloc(sizeof(struct nredir));
Eric Andersenc470f442003-07-28 09:56:35 +000011397 n3->nredir.n = n2;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011398 /*n3->nredir.redirect = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011399 n2 = n3;
11400 }
11401 n2->type = NBACKGND;
Eric Andersencb57d552001-06-28 07:25:16 +000011402 }
11403 }
11404 if (n1 == NULL) {
11405 n1 = n2;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011406 } else {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011407 n3 = stzalloc(sizeof(struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +000011408 n3->type = NSEMI;
11409 n3->nbinary.ch1 = n1;
11410 n3->nbinary.ch2 = n2;
11411 n1 = n3;
11412 }
11413 switch (tok) {
Ron Yorstonc0e00762015-10-29 11:30:55 +000011414 case TNL:
11415 case TEOF:
11416 tokpushback = 1;
11417 /* fall through */
Eric Andersencb57d552001-06-28 07:25:16 +000011418 case TBACKGND:
11419 case TSEMI:
Eric Andersencb57d552001-06-28 07:25:16 +000011420 break;
Eric Andersencb57d552001-06-28 07:25:16 +000011421 default:
Ron Yorstonc0e00762015-10-29 11:30:55 +000011422 if ((nlflag & 1))
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011423 raise_error_unexpected_syntax(-1);
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011424 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011425 return n1;
11426 }
11427 }
11428}
11429
Eric Andersenc470f442003-07-28 09:56:35 +000011430static union node *
11431andor(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011432{
Eric Andersencb57d552001-06-28 07:25:16 +000011433 union node *n1, *n2, *n3;
11434 int t;
11435
Eric Andersencb57d552001-06-28 07:25:16 +000011436 n1 = pipeline();
11437 for (;;) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011438 t = readtoken();
11439 if (t == TAND) {
Eric Andersencb57d552001-06-28 07:25:16 +000011440 t = NAND;
11441 } else if (t == TOR) {
11442 t = NOR;
11443 } else {
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011444 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011445 return n1;
11446 }
Eric Andersenc470f442003-07-28 09:56:35 +000011447 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000011448 n2 = pipeline();
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011449 n3 = stzalloc(sizeof(struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +000011450 n3->type = t;
11451 n3->nbinary.ch1 = n1;
11452 n3->nbinary.ch2 = n2;
11453 n1 = n3;
11454 }
11455}
11456
Eric Andersenc470f442003-07-28 09:56:35 +000011457static union node *
11458pipeline(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011459{
Eric Andersencb57d552001-06-28 07:25:16 +000011460 union node *n1, *n2, *pipenode;
11461 struct nodelist *lp, *prev;
11462 int negate;
11463
11464 negate = 0;
11465 TRACE(("pipeline: entered\n"));
11466 if (readtoken() == TNOT) {
11467 negate = !negate;
Eric Andersenc470f442003-07-28 09:56:35 +000011468 checkkwd = CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000011469 } else
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011470 tokpushback = 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011471 n1 = parse_command();
Eric Andersencb57d552001-06-28 07:25:16 +000011472 if (readtoken() == TPIPE) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011473 pipenode = stzalloc(sizeof(struct npipe));
Eric Andersencb57d552001-06-28 07:25:16 +000011474 pipenode->type = NPIPE;
Denis Vlasenko2dc240c2008-07-24 06:07:50 +000011475 /*pipenode->npipe.pipe_backgnd = 0; - stzalloc did it */
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011476 lp = stzalloc(sizeof(struct nodelist));
Eric Andersencb57d552001-06-28 07:25:16 +000011477 pipenode->npipe.cmdlist = lp;
11478 lp->n = n1;
11479 do {
11480 prev = lp;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011481 lp = stzalloc(sizeof(struct nodelist));
Eric Andersenc470f442003-07-28 09:56:35 +000011482 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011483 lp->n = parse_command();
Eric Andersencb57d552001-06-28 07:25:16 +000011484 prev->next = lp;
11485 } while (readtoken() == TPIPE);
11486 lp->next = NULL;
11487 n1 = pipenode;
11488 }
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011489 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011490 if (negate) {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011491 n2 = stzalloc(sizeof(struct nnot));
Eric Andersencb57d552001-06-28 07:25:16 +000011492 n2->type = NNOT;
11493 n2->nnot.com = n1;
11494 return n2;
Denis Vlasenko2da584f2007-02-19 22:44:05 +000011495 }
11496 return n1;
Eric Andersencb57d552001-06-28 07:25:16 +000011497}
11498
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011499static union node *
11500makename(void)
11501{
11502 union node *n;
11503
Denis Vlasenko597906c2008-02-20 16:38:54 +000011504 n = stzalloc(sizeof(struct narg));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011505 n->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011506 /*n->narg.next = NULL; - stzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011507 n->narg.text = wordtext;
11508 n->narg.backquote = backquotelist;
11509 return n;
11510}
11511
11512static void
11513fixredir(union node *n, const char *text, int err)
11514{
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000011515 int fd;
11516
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011517 TRACE(("Fix redir %s %d\n", text, err));
11518 if (!err)
11519 n->ndup.vname = NULL;
11520
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000011521 fd = bb_strtou(text, NULL, 10);
11522 if (!errno && fd >= 0)
11523 n->ndup.dupfd = fd;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011524 else if (LONE_DASH(text))
11525 n->ndup.dupfd = -1;
11526 else {
11527 if (err)
Denis Vlasenko559691a2008-10-05 18:39:31 +000011528 raise_error_syntax("bad fd number");
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011529 n->ndup.vname = makename();
11530 }
11531}
11532
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011533static void
11534parsefname(void)
11535{
11536 union node *n = redirnode;
11537
Denys Vlasenkoa7328982017-07-29 19:57:28 +020011538 if (n->type == NHERE)
11539 checkkwd = CHKEOFMARK;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011540 if (readtoken() != TWORD)
11541 raise_error_unexpected_syntax(-1);
11542 if (n->type == NHERE) {
11543 struct heredoc *here = heredoc;
11544 struct heredoc *p;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011545
11546 if (quoteflag == 0)
11547 n->type = NXHERE;
11548 TRACE(("Here document %d\n", n->type));
Denys Vlasenko740058b2018-01-09 17:01:00 +010011549 rmescapes(wordtext, 0, NULL);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011550 here->eofmark = wordtext;
11551 here->next = NULL;
11552 if (heredoclist == NULL)
11553 heredoclist = here;
11554 else {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011555 for (p = heredoclist; p->next; p = p->next)
11556 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011557 p->next = here;
11558 }
11559 } else if (n->type == NTOFD || n->type == NFROMFD) {
11560 fixredir(n, wordtext, 0);
11561 } else {
11562 n->nfile.fname = makename();
11563 }
11564}
Eric Andersencb57d552001-06-28 07:25:16 +000011565
Eric Andersenc470f442003-07-28 09:56:35 +000011566static union node *
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011567simplecmd(void)
11568{
11569 union node *args, **app;
11570 union node *n = NULL;
11571 union node *vars, **vpp;
11572 union node **rpp, *redir;
11573 int savecheckkwd;
Denys Vlasenko675d24a2018-01-27 22:02:05 +010011574 int savelinno;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011575#if BASH_TEST2
Denis Vlasenko80591b02008-03-25 07:49:43 +000011576 smallint double_brackets_flag = 0;
11577#endif
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011578 IF_BASH_FUNCTION(smallint function_flag = 0;)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011579
11580 args = NULL;
11581 app = &args;
11582 vars = NULL;
11583 vpp = &vars;
11584 redir = NULL;
11585 rpp = &redir;
11586
11587 savecheckkwd = CHKALIAS;
Denys Vlasenko675d24a2018-01-27 22:02:05 +010011588 savelinno = g_parsefile->linno;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011589 for (;;) {
Denis Vlasenko80591b02008-03-25 07:49:43 +000011590 int t;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011591 checkkwd = savecheckkwd;
Denis Vlasenko80591b02008-03-25 07:49:43 +000011592 t = readtoken();
11593 switch (t) {
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011594#if BASH_FUNCTION
Ron Yorston95ebcf72015-11-03 09:42:23 +000011595 case TFUNCTION:
11596 if (peektoken() != TWORD)
11597 raise_error_unexpected_syntax(TWORD);
11598 function_flag = 1;
11599 break;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011600#endif
11601#if BASH_TEST2
Denis Vlasenko80591b02008-03-25 07:49:43 +000011602 case TAND: /* "&&" */
11603 case TOR: /* "||" */
11604 if (!double_brackets_flag) {
11605 tokpushback = 1;
11606 goto out;
11607 }
11608 wordtext = (char *) (t == TAND ? "-a" : "-o");
11609#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011610 case TWORD:
Denis Vlasenko597906c2008-02-20 16:38:54 +000011611 n = stzalloc(sizeof(struct narg));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011612 n->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011613 /*n->narg.next = NULL; - stzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011614 n->narg.text = wordtext;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011615#if BASH_TEST2
Denis Vlasenko80591b02008-03-25 07:49:43 +000011616 if (strcmp("[[", wordtext) == 0)
11617 double_brackets_flag = 1;
11618 else if (strcmp("]]", wordtext) == 0)
11619 double_brackets_flag = 0;
11620#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011621 n->narg.backquote = backquotelist;
11622 if (savecheckkwd && isassignment(wordtext)) {
11623 *vpp = n;
11624 vpp = &n->narg.next;
11625 } else {
11626 *app = n;
11627 app = &n->narg.next;
11628 savecheckkwd = 0;
11629 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011630#if BASH_FUNCTION
Ron Yorston95ebcf72015-11-03 09:42:23 +000011631 if (function_flag) {
11632 checkkwd = CHKNL | CHKKWD;
11633 switch (peektoken()) {
11634 case TBEGIN:
11635 case TIF:
11636 case TCASE:
11637 case TUNTIL:
11638 case TWHILE:
11639 case TFOR:
11640 goto do_func;
11641 case TLP:
11642 function_flag = 0;
11643 break;
Denys Vlasenkoe93031e2018-04-10 01:23:19 +020011644# if BASH_TEST2
Ron Yorston95ebcf72015-11-03 09:42:23 +000011645 case TWORD:
11646 if (strcmp("[[", wordtext) == 0)
11647 goto do_func;
11648 /* fall through */
Denys Vlasenkoe93031e2018-04-10 01:23:19 +020011649# endif
Ron Yorston95ebcf72015-11-03 09:42:23 +000011650 default:
11651 raise_error_unexpected_syntax(-1);
11652 }
11653 }
11654#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011655 break;
11656 case TREDIR:
11657 *rpp = n = redirnode;
11658 rpp = &n->nfile.next;
11659 parsefname(); /* read name of redirection file */
11660 break;
11661 case TLP:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011662 IF_BASH_FUNCTION(do_func:)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011663 if (args && app == &args->narg.next
11664 && !vars && !redir
11665 ) {
11666 struct builtincmd *bcmd;
11667 const char *name;
11668
11669 /* We have a function */
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011670 if (IF_BASH_FUNCTION(!function_flag &&) readtoken() != TRP)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011671 raise_error_unexpected_syntax(TRP);
11672 name = n->narg.text;
11673 if (!goodname(name)
11674 || ((bcmd = find_builtin(name)) && IS_BUILTIN_SPECIAL(bcmd))
11675 ) {
Denis Vlasenko559691a2008-10-05 18:39:31 +000011676 raise_error_syntax("bad function name");
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011677 }
11678 n->type = NDEFUN;
11679 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Denys Vlasenko675d24a2018-01-27 22:02:05 +010011680 n->ndefun.text = n->narg.text;
11681 n->ndefun.linno = g_parsefile->linno;
11682 n->ndefun.body = parse_command();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011683 return n;
11684 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011685 IF_BASH_FUNCTION(function_flag = 0;)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011686 /* fall through */
11687 default:
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011688 tokpushback = 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011689 goto out;
11690 }
11691 }
11692 out:
11693 *app = NULL;
11694 *vpp = NULL;
11695 *rpp = NULL;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011696 n = stzalloc(sizeof(struct ncmd));
Denys Vlasenko57b7efb2018-04-10 01:20:26 +020011697 if (NCMD != 0)
11698 n->type = NCMD;
Denys Vlasenko675d24a2018-01-27 22:02:05 +010011699 n->ncmd.linno = savelinno;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011700 n->ncmd.args = args;
11701 n->ncmd.assign = vars;
11702 n->ncmd.redirect = redir;
11703 return n;
11704}
11705
11706static union node *
11707parse_command(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011708{
Eric Andersencb57d552001-06-28 07:25:16 +000011709 union node *n1, *n2;
11710 union node *ap, **app;
11711 union node *cp, **cpp;
11712 union node *redir, **rpp;
Eric Andersenc470f442003-07-28 09:56:35 +000011713 union node **rpp2;
Eric Andersencb57d552001-06-28 07:25:16 +000011714 int t;
Denys Vlasenko675d24a2018-01-27 22:02:05 +010011715 int savelinno;
Eric Andersencb57d552001-06-28 07:25:16 +000011716
11717 redir = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +000011718 rpp2 = &redir;
Eric Andersen88cec252001-09-06 17:35:20 +000011719
Denys Vlasenko675d24a2018-01-27 22:02:05 +010011720 savelinno = g_parsefile->linno;
11721
Eric Andersencb57d552001-06-28 07:25:16 +000011722 switch (readtoken()) {
Eric Andersenc470f442003-07-28 09:56:35 +000011723 default:
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011724 raise_error_unexpected_syntax(-1);
Eric Andersenc470f442003-07-28 09:56:35 +000011725 /* NOTREACHED */
Eric Andersencb57d552001-06-28 07:25:16 +000011726 case TIF:
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011727 n1 = stzalloc(sizeof(struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +000011728 n1->type = NIF;
11729 n1->nif.test = list(0);
11730 if (readtoken() != TTHEN)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011731 raise_error_unexpected_syntax(TTHEN);
Eric Andersencb57d552001-06-28 07:25:16 +000011732 n1->nif.ifpart = list(0);
11733 n2 = n1;
11734 while (readtoken() == TELIF) {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011735 n2->nif.elsepart = stzalloc(sizeof(struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +000011736 n2 = n2->nif.elsepart;
11737 n2->type = NIF;
11738 n2->nif.test = list(0);
11739 if (readtoken() != TTHEN)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011740 raise_error_unexpected_syntax(TTHEN);
Eric Andersencb57d552001-06-28 07:25:16 +000011741 n2->nif.ifpart = list(0);
11742 }
11743 if (lasttoken == TELSE)
11744 n2->nif.elsepart = list(0);
11745 else {
11746 n2->nif.elsepart = NULL;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011747 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011748 }
Eric Andersenc470f442003-07-28 09:56:35 +000011749 t = TFI;
Eric Andersencb57d552001-06-28 07:25:16 +000011750 break;
11751 case TWHILE:
Eric Andersenc470f442003-07-28 09:56:35 +000011752 case TUNTIL: {
Eric Andersencb57d552001-06-28 07:25:16 +000011753 int got;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011754 n1 = stzalloc(sizeof(struct nbinary));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011755 n1->type = (lasttoken == TWHILE) ? NWHILE : NUNTIL;
Eric Andersencb57d552001-06-28 07:25:16 +000011756 n1->nbinary.ch1 = list(0);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011757 got = readtoken();
11758 if (got != TDO) {
Denys Vlasenko888527c2016-10-02 16:54:17 +020011759 TRACE(("expecting DO got '%s' %s\n", tokname_array[got],
Denis Vlasenko131ae172007-02-18 13:00:19 +000011760 got == TWORD ? wordtext : ""));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011761 raise_error_unexpected_syntax(TDO);
Eric Andersencb57d552001-06-28 07:25:16 +000011762 }
11763 n1->nbinary.ch2 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +000011764 t = TDONE;
Eric Andersencb57d552001-06-28 07:25:16 +000011765 break;
11766 }
11767 case TFOR:
Denis Vlasenko2dc240c2008-07-24 06:07:50 +000011768 if (readtoken() != TWORD || quoteflag || !goodname(wordtext))
Denis Vlasenko559691a2008-10-05 18:39:31 +000011769 raise_error_syntax("bad for loop variable");
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011770 n1 = stzalloc(sizeof(struct nfor));
Eric Andersencb57d552001-06-28 07:25:16 +000011771 n1->type = NFOR;
Denys Vlasenko675d24a2018-01-27 22:02:05 +010011772 n1->nfor.linno = savelinno;
Eric Andersencb57d552001-06-28 07:25:16 +000011773 n1->nfor.var = wordtext;
Ron Yorstonab80e012015-08-03 13:46:00 +010011774 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000011775 if (readtoken() == TIN) {
11776 app = &ap;
11777 while (readtoken() == TWORD) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011778 n2 = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000011779 n2->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011780 /*n2->narg.next = NULL; - stzalloc did it */
Eric Andersencb57d552001-06-28 07:25:16 +000011781 n2->narg.text = wordtext;
11782 n2->narg.backquote = backquotelist;
11783 *app = n2;
11784 app = &n2->narg.next;
11785 }
11786 *app = NULL;
11787 n1->nfor.args = ap;
11788 if (lasttoken != TNL && lasttoken != TSEMI)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011789 raise_error_unexpected_syntax(-1);
Eric Andersencb57d552001-06-28 07:25:16 +000011790 } else {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011791 n2 = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000011792 n2->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011793 /*n2->narg.next = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011794 n2->narg.text = (char *)dolatstr;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011795 /*n2->narg.backquote = NULL;*/
Eric Andersencb57d552001-06-28 07:25:16 +000011796 n1->nfor.args = n2;
11797 /*
11798 * Newline or semicolon here is optional (but note
11799 * that the original Bourne shell only allowed NL).
11800 */
Ron Yorstonab80e012015-08-03 13:46:00 +010011801 if (lasttoken != TSEMI)
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011802 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011803 }
Eric Andersenc470f442003-07-28 09:56:35 +000011804 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000011805 if (readtoken() != TDO)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011806 raise_error_unexpected_syntax(TDO);
Eric Andersencb57d552001-06-28 07:25:16 +000011807 n1->nfor.body = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +000011808 t = TDONE;
Eric Andersencb57d552001-06-28 07:25:16 +000011809 break;
11810 case TCASE:
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011811 n1 = stzalloc(sizeof(struct ncase));
Eric Andersencb57d552001-06-28 07:25:16 +000011812 n1->type = NCASE;
Denys Vlasenko675d24a2018-01-27 22:02:05 +010011813 n1->ncase.linno = savelinno;
Eric Andersencb57d552001-06-28 07:25:16 +000011814 if (readtoken() != TWORD)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011815 raise_error_unexpected_syntax(TWORD);
Denis Vlasenko597906c2008-02-20 16:38:54 +000011816 n1->ncase.expr = n2 = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000011817 n2->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011818 /*n2->narg.next = NULL; - stzalloc did it */
Eric Andersencb57d552001-06-28 07:25:16 +000011819 n2->narg.text = wordtext;
11820 n2->narg.backquote = backquotelist;
Ron Yorston383b8852015-08-03 13:46:25 +010011821 checkkwd = CHKNL | CHKKWD | CHKALIAS;
11822 if (readtoken() != TIN)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011823 raise_error_unexpected_syntax(TIN);
Eric Andersencb57d552001-06-28 07:25:16 +000011824 cpp = &n1->ncase.cases;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011825 next_case:
Eric Andersenc470f442003-07-28 09:56:35 +000011826 checkkwd = CHKNL | CHKKWD;
11827 t = readtoken();
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011828 while (t != TESAC) {
Eric Andersencb57d552001-06-28 07:25:16 +000011829 if (lasttoken == TLP)
11830 readtoken();
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011831 *cpp = cp = stzalloc(sizeof(struct nclist));
Eric Andersencb57d552001-06-28 07:25:16 +000011832 cp->type = NCLIST;
11833 app = &cp->nclist.pattern;
11834 for (;;) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011835 *app = ap = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000011836 ap->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011837 /*ap->narg.next = NULL; - stzalloc did it */
Eric Andersencb57d552001-06-28 07:25:16 +000011838 ap->narg.text = wordtext;
11839 ap->narg.backquote = backquotelist;
Eric Andersenc470f442003-07-28 09:56:35 +000011840 if (readtoken() != TPIPE)
Eric Andersencb57d552001-06-28 07:25:16 +000011841 break;
11842 app = &ap->narg.next;
11843 readtoken();
11844 }
Denis Vlasenko597906c2008-02-20 16:38:54 +000011845 //ap->narg.next = NULL;
Eric Andersencb57d552001-06-28 07:25:16 +000011846 if (lasttoken != TRP)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011847 raise_error_unexpected_syntax(TRP);
Eric Andersenc470f442003-07-28 09:56:35 +000011848 cp->nclist.body = list(2);
Eric Andersencb57d552001-06-28 07:25:16 +000011849
Eric Andersenc470f442003-07-28 09:56:35 +000011850 cpp = &cp->nclist.next;
11851
11852 checkkwd = CHKNL | CHKKWD;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011853 t = readtoken();
11854 if (t != TESAC) {
Eric Andersencb57d552001-06-28 07:25:16 +000011855 if (t != TENDCASE)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011856 raise_error_unexpected_syntax(TENDCASE);
11857 goto next_case;
Eric Andersencb57d552001-06-28 07:25:16 +000011858 }
Eric Andersenc470f442003-07-28 09:56:35 +000011859 }
Eric Andersencb57d552001-06-28 07:25:16 +000011860 *cpp = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +000011861 goto redir;
Eric Andersencb57d552001-06-28 07:25:16 +000011862 case TLP:
Denis Vlasenko597906c2008-02-20 16:38:54 +000011863 n1 = stzalloc(sizeof(struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +000011864 n1->type = NSUBSHELL;
Denys Vlasenko675d24a2018-01-27 22:02:05 +010011865 n1->nredir.linno = savelinno;
Eric Andersencb57d552001-06-28 07:25:16 +000011866 n1->nredir.n = list(0);
Denis Vlasenko597906c2008-02-20 16:38:54 +000011867 /*n1->nredir.redirect = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011868 t = TRP;
Eric Andersencb57d552001-06-28 07:25:16 +000011869 break;
11870 case TBEGIN:
11871 n1 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +000011872 t = TEND;
Eric Andersencb57d552001-06-28 07:25:16 +000011873 break;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011874 IF_BASH_FUNCTION(case TFUNCTION:)
Eric Andersencb57d552001-06-28 07:25:16 +000011875 case TWORD:
Eric Andersenc470f442003-07-28 09:56:35 +000011876 case TREDIR:
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011877 tokpushback = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000011878 return simplecmd();
Eric Andersencb57d552001-06-28 07:25:16 +000011879 }
11880
Eric Andersenc470f442003-07-28 09:56:35 +000011881 if (readtoken() != t)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011882 raise_error_unexpected_syntax(t);
Eric Andersenc470f442003-07-28 09:56:35 +000011883
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011884 redir:
Eric Andersencb57d552001-06-28 07:25:16 +000011885 /* Now check for redirection which may follow command */
Eric Andersenc470f442003-07-28 09:56:35 +000011886 checkkwd = CHKKWD | CHKALIAS;
11887 rpp = rpp2;
Eric Andersencb57d552001-06-28 07:25:16 +000011888 while (readtoken() == TREDIR) {
11889 *rpp = n2 = redirnode;
11890 rpp = &n2->nfile.next;
11891 parsefname();
11892 }
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011893 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011894 *rpp = NULL;
11895 if (redir) {
11896 if (n1->type != NSUBSHELL) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011897 n2 = stzalloc(sizeof(struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +000011898 n2->type = NREDIR;
Denys Vlasenko675d24a2018-01-27 22:02:05 +010011899 n2->nredir.linno = savelinno;
Eric Andersencb57d552001-06-28 07:25:16 +000011900 n2->nredir.n = n1;
11901 n1 = n2;
11902 }
11903 n1->nredir.redirect = redir;
11904 }
Eric Andersencb57d552001-06-28 07:25:16 +000011905 return n1;
11906}
11907
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011908#if BASH_DOLLAR_SQUOTE
Denys Vlasenko37dc08b2016-10-02 04:38:07 +020011909static int
11910decode_dollar_squote(void)
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011911{
11912 static const char C_escapes[] ALIGN1 = "nrbtfav""x\\01234567";
11913 int c, cnt;
11914 char *p;
11915 char buf[4];
11916
11917 c = pgetc();
11918 p = strchr(C_escapes, c);
11919 if (p) {
11920 buf[0] = c;
11921 p = buf;
11922 cnt = 3;
11923 if ((unsigned char)(c - '0') <= 7) { /* \ooo */
11924 do {
11925 c = pgetc();
11926 *++p = c;
11927 } while ((unsigned char)(c - '0') <= 7 && --cnt);
11928 pungetc();
11929 } else if (c == 'x') { /* \xHH */
11930 do {
11931 c = pgetc();
11932 *++p = c;
11933 } while (isxdigit(c) && --cnt);
11934 pungetc();
11935 if (cnt == 3) { /* \x but next char is "bad" */
11936 c = 'x';
11937 goto unrecognized;
11938 }
11939 } else { /* simple seq like \\ or \t */
11940 p++;
11941 }
11942 *p = '\0';
11943 p = buf;
11944 c = bb_process_escape_sequence((void*)&p);
11945 } else { /* unrecognized "\z": print both chars unless ' or " */
11946 if (c != '\'' && c != '"') {
11947 unrecognized:
11948 c |= 0x100; /* "please encode \, then me" */
11949 }
11950 }
11951 return c;
11952}
11953#endif
11954
Denys Vlasenko46999802017-07-29 21:12:29 +020011955/* Used by expandstr to get here-doc like behaviour. */
11956#define FAKEEOFMARK ((char*)(uintptr_t)1)
11957
11958static ALWAYS_INLINE int
11959realeofmark(const char *eofmark)
11960{
11961 return eofmark && eofmark != FAKEEOFMARK;
11962}
11963
Eric Andersencb57d552001-06-28 07:25:16 +000011964/*
11965 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
11966 * is not NULL, read a here document. In the latter case, eofmark is the
11967 * word which marks the end of the document and striptabs is true if
Denys Vlasenkocd716832009-11-28 22:14:02 +010011968 * leading tabs should be stripped from the document. The argument c
Eric Andersencb57d552001-06-28 07:25:16 +000011969 * is the first character of the input token or document.
11970 *
11971 * Because C does not have internal subroutines, I have simulated them
11972 * using goto's to implement the subroutine linkage. The following macros
11973 * will run code that appears at the end of readtoken1.
11974 */
Eric Andersen2870d962001-07-02 17:27:21 +000011975#define CHECKEND() {goto checkend; checkend_return:;}
11976#define PARSEREDIR() {goto parseredir; parseredir_return:;}
11977#define PARSESUB() {goto parsesub; parsesub_return:;}
11978#define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
11979#define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
11980#define PARSEARITH() {goto parsearith; parsearith_return:;}
Eric Andersencb57d552001-06-28 07:25:16 +000011981static int
Denys Vlasenkocd716832009-11-28 22:14:02 +010011982readtoken1(int c, int syntax, char *eofmark, int striptabs)
Manuel Novoa III 16815d42001-08-10 19:36:07 +000011983{
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011984 /* NB: syntax parameter fits into smallint */
Denys Vlasenkocd716832009-11-28 22:14:02 +010011985 /* c parameter is an unsigned char or PEOF or PEOA */
Eric Andersencb57d552001-06-28 07:25:16 +000011986 char *out;
Denys Vlasenko50e6d422016-09-30 11:35:54 +020011987 size_t len;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011988 struct nodelist *bqlist;
11989 smallint quotef;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011990 smallint oldstyle;
Denis Vlasenko46a53062007-09-24 18:30:02 +000011991 smallint pssyntax; /* we are expanding a prompt string */
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011992 IF_BASH_DOLLAR_SQUOTE(smallint bash_dollar_squote = 0;)
Denys Vlasenko216913c2018-04-02 12:35:04 +020011993 /* syntax stack */
Denys Vlasenkoee1fd122018-04-04 13:59:53 +020011994 struct synstack synbase = { };
Denys Vlasenko216913c2018-04-02 12:35:04 +020011995 struct synstack *synstack = &synbase;
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011996
Denys Vlasenko5f0a75f2017-07-29 22:58:44 +020011997#if ENABLE_ASH_EXPAND_PRMT
Denis Vlasenko46a53062007-09-24 18:30:02 +000011998 pssyntax = (syntax == PSSYNTAX);
11999 if (pssyntax)
12000 syntax = DQSYNTAX;
Denys Vlasenko5f0a75f2017-07-29 22:58:44 +020012001#else
12002 pssyntax = 0; /* constant */
12003#endif
Denys Vlasenkoee1fd122018-04-04 13:59:53 +020012004 synstack->syntax = syntax;
12005
Denys Vlasenko216913c2018-04-02 12:35:04 +020012006 if (syntax == DQSYNTAX)
12007 synstack->dblquote = 1;
12008 quotef = 0;
12009 bqlist = NULL;
Eric Andersencb57d552001-06-28 07:25:16 +000012010
12011 STARTSTACKSTR(out);
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012012 loop:
12013 /* For each line, until end of word */
Denys Vlasenko958581a2010-09-12 15:04:27 +020012014 CHECKEND(); /* set c to PEOF if at end of here document */
12015 for (;;) { /* until end of line or end of word */
12016 CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */
Denys Vlasenko216913c2018-04-02 12:35:04 +020012017 switch (SIT(c, synstack->syntax)) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020012018 case CNL: /* '\n' */
Denys Vlasenko680c3012018-04-11 12:39:18 +020012019 if (synstack->syntax == BASESYNTAX
12020 && !synstack->varnest
12021 ) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020012022 goto endword; /* exit outer loop */
Denys Vlasenko680c3012018-04-11 12:39:18 +020012023 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020012024 USTPUTC(c, out);
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012025 nlprompt();
Denys Vlasenko958581a2010-09-12 15:04:27 +020012026 c = pgetc();
12027 goto loop; /* continue outer loop */
12028 case CWORD:
12029 USTPUTC(c, out);
12030 break;
12031 case CCTL:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010012032#if BASH_DOLLAR_SQUOTE
Denys Vlasenko958581a2010-09-12 15:04:27 +020012033 if (c == '\\' && bash_dollar_squote) {
12034 c = decode_dollar_squote();
Denys Vlasenko13f20912016-09-25 20:54:25 +020012035 if (c == '\0') {
12036 /* skip $'\000', $'\x00' (like bash) */
12037 break;
12038 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020012039 if (c & 0x100) {
Denys Vlasenko13f20912016-09-25 20:54:25 +020012040 /* Unknown escape. Encode as '\z' */
Denys Vlasenko958581a2010-09-12 15:04:27 +020012041 c = (unsigned char)c;
Denys Vlasenko216913c2018-04-02 12:35:04 +020012042 if (eofmark == NULL || synstack->dblquote)
Denys Vlasenko13f20912016-09-25 20:54:25 +020012043 USTPUTC(CTLESC, out);
12044 USTPUTC('\\', out);
Denis Vlasenkoef527f52008-06-23 01:52:30 +000012045 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020012046 }
Denis Vlasenkoef527f52008-06-23 01:52:30 +000012047#endif
Denys Vlasenkoc4c20122018-04-02 13:29:20 +020012048 if (!eofmark || synstack->dblquote || synstack->varnest)
Denys Vlasenko13f20912016-09-25 20:54:25 +020012049 USTPUTC(CTLESC, out);
Denys Vlasenko958581a2010-09-12 15:04:27 +020012050 USTPUTC(c, out);
12051 break;
12052 case CBACK: /* backslash */
12053 c = pgetc_without_PEOA();
12054 if (c == PEOF) {
12055 USTPUTC(CTLESC, out);
12056 USTPUTC('\\', out);
12057 pungetc();
12058 } else if (c == '\n') {
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012059 nlprompt();
Denys Vlasenko958581a2010-09-12 15:04:27 +020012060 } else {
Denys Vlasenko5f0a75f2017-07-29 22:58:44 +020012061 if (pssyntax && c == '$') {
Eric Andersenc470f442003-07-28 09:56:35 +000012062 USTPUTC(CTLESC, out);
Eric Andersencb57d552001-06-28 07:25:16 +000012063 USTPUTC('\\', out);
Denys Vlasenko958581a2010-09-12 15:04:27 +020012064 }
Denys Vlasenko8de5b9f2018-02-13 14:43:29 +010012065 /* Backslash is retained if we are in "str"
12066 * and next char isn't dquote-special.
12067 */
Denys Vlasenko216913c2018-04-02 12:35:04 +020012068 if (synstack->dblquote
Denys Vlasenko958581a2010-09-12 15:04:27 +020012069 && c != '\\'
12070 && c != '`'
12071 && c != '$'
Denys Vlasenko216913c2018-04-02 12:35:04 +020012072 && (c != '"' || (eofmark != NULL && !synstack->varnest))
12073 && (c != '}' || !synstack->varnest)
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000012074 ) {
Denys Vlasenko8de5b9f2018-02-13 14:43:29 +010012075 USTPUTC(CTLESC, out); /* protect '\' from glob */
Denys Vlasenko958581a2010-09-12 15:04:27 +020012076 USTPUTC('\\', out);
Eric Andersencb57d552001-06-28 07:25:16 +000012077 }
Ron Yorston549deab2015-05-18 09:57:51 +020012078 USTPUTC(CTLESC, out);
Denys Vlasenko0ff78a02010-08-30 15:20:07 +020012079 USTPUTC(c, out);
Denys Vlasenko958581a2010-09-12 15:04:27 +020012080 quotef = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000012081 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020012082 break;
12083 case CSQUOTE:
Denys Vlasenko216913c2018-04-02 12:35:04 +020012084 synstack->syntax = SQSYNTAX;
Denys Vlasenko958581a2010-09-12 15:04:27 +020012085 quotemark:
12086 if (eofmark == NULL) {
12087 USTPUTC(CTLQUOTEMARK, out);
12088 }
12089 break;
12090 case CDQUOTE:
Denys Vlasenko216913c2018-04-02 12:35:04 +020012091 synstack->syntax = DQSYNTAX;
12092 synstack->dblquote = 1;
12093 toggledq:
12094 if (synstack->varnest)
12095 synstack->innerdq ^= 1;
Denys Vlasenko958581a2010-09-12 15:04:27 +020012096 goto quotemark;
12097 case CENDQUOTE:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010012098 IF_BASH_DOLLAR_SQUOTE(bash_dollar_squote = 0;)
Denys Vlasenko216913c2018-04-02 12:35:04 +020012099 if (eofmark != NULL && synstack->varnest == 0) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020012100 USTPUTC(c, out);
Denys Vlasenko216913c2018-04-02 12:35:04 +020012101 break;
Denys Vlasenko958581a2010-09-12 15:04:27 +020012102 }
Denys Vlasenko216913c2018-04-02 12:35:04 +020012103
12104 if (synstack->dqvarnest == 0) {
12105 synstack->syntax = BASESYNTAX;
12106 synstack->dblquote = 0;
12107 }
12108
12109 quotef = 1;
12110
12111 if (c == '"')
12112 goto toggledq;
12113
12114 goto quotemark;
Denys Vlasenko958581a2010-09-12 15:04:27 +020012115 case CVAR: /* '$' */
12116 PARSESUB(); /* parse substitution */
12117 break;
12118 case CENDVAR: /* '}' */
Denys Vlasenko216913c2018-04-02 12:35:04 +020012119 if (!synstack->innerdq && synstack->varnest > 0) {
12120 if (!--synstack->varnest && synstack->varpushed)
12121 synstack_pop(&synstack);
12122 else if (synstack->dqvarnest > 0)
12123 synstack->dqvarnest--;
Denys Vlasenko958581a2010-09-12 15:04:27 +020012124 c = CTLENDVAR;
12125 }
12126 USTPUTC(c, out);
12127 break;
Denys Vlasenko0b883582016-12-23 16:49:07 +010012128#if ENABLE_FEATURE_SH_MATH
Denys Vlasenko958581a2010-09-12 15:04:27 +020012129 case CLP: /* '(' in arithmetic */
Denys Vlasenko216913c2018-04-02 12:35:04 +020012130 synstack->parenlevel++;
Denys Vlasenko958581a2010-09-12 15:04:27 +020012131 USTPUTC(c, out);
12132 break;
12133 case CRP: /* ')' in arithmetic */
Denys Vlasenko216913c2018-04-02 12:35:04 +020012134 if (synstack->parenlevel > 0) {
12135 synstack->parenlevel--;
Denys Vlasenko958581a2010-09-12 15:04:27 +020012136 } else {
Denys Vlasenko459293b2016-09-29 17:58:58 +020012137 if (pgetc_eatbnl() == ')') {
Ron Yorstonad88bde2015-05-18 09:56:16 +020012138 c = CTLENDARI;
Denys Vlasenko216913c2018-04-02 12:35:04 +020012139 synstack_pop(&synstack);
Denys Vlasenko958581a2010-09-12 15:04:27 +020012140 } else {
12141 /*
12142 * unbalanced parens
12143 * (don't 2nd guess - no error)
12144 */
12145 pungetc();
12146 }
12147 }
12148 USTPUTC(c, out);
12149 break;
12150#endif
12151 case CBQUOTE: /* '`' */
Denys Vlasenko41fddb42018-04-01 16:38:32 +020012152 if (checkkwd & CHKEOFMARK) {
12153 quotef = 1;
12154 USTPUTC('`', out);
12155 break;
12156 }
12157
Denys Vlasenko958581a2010-09-12 15:04:27 +020012158 PARSEBACKQOLD();
12159 break;
12160 case CENDFILE:
12161 goto endword; /* exit outer loop */
12162 case CIGN:
12163 break;
12164 default:
Denys Vlasenko216913c2018-04-02 12:35:04 +020012165 if (synstack->varnest == 0) {
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010012166#if BASH_REDIR_OUTPUT
Denys Vlasenko958581a2010-09-12 15:04:27 +020012167 if (c == '&') {
Denys Vlasenko459293b2016-09-29 17:58:58 +020012168//Can't call pgetc_eatbnl() here, this requires three-deep pungetc()
Denys Vlasenko958581a2010-09-12 15:04:27 +020012169 if (pgetc() == '>')
12170 c = 0x100 + '>'; /* flag &> */
12171 pungetc();
12172 }
12173#endif
12174 goto endword; /* exit outer loop */
12175 }
12176 IF_ASH_ALIAS(if (c != PEOA))
12177 USTPUTC(c, out);
12178 }
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020012179 c = pgetc();
Denys Vlasenko958581a2010-09-12 15:04:27 +020012180 } /* for (;;) */
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000012181 endword:
Denys Vlasenko958581a2010-09-12 15:04:27 +020012182
Denys Vlasenko0b883582016-12-23 16:49:07 +010012183#if ENABLE_FEATURE_SH_MATH
Denys Vlasenko216913c2018-04-02 12:35:04 +020012184 if (synstack->syntax == ARISYNTAX)
Denis Vlasenko559691a2008-10-05 18:39:31 +000012185 raise_error_syntax("missing '))'");
Eric Andersenc470f442003-07-28 09:56:35 +000012186#endif
Denys Vlasenko216913c2018-04-02 12:35:04 +020012187 if (synstack->syntax != BASESYNTAX && eofmark == NULL)
Denis Vlasenko559691a2008-10-05 18:39:31 +000012188 raise_error_syntax("unterminated quoted string");
Denys Vlasenko216913c2018-04-02 12:35:04 +020012189 if (synstack->varnest != 0) {
Eric Andersenc470f442003-07-28 09:56:35 +000012190 /* { */
Denis Vlasenko559691a2008-10-05 18:39:31 +000012191 raise_error_syntax("missing '}'");
Eric Andersencb57d552001-06-28 07:25:16 +000012192 }
12193 USTPUTC('\0', out);
Eric Andersenc470f442003-07-28 09:56:35 +000012194 len = out - (char *)stackblock();
Eric Andersencb57d552001-06-28 07:25:16 +000012195 out = stackblock();
12196 if (eofmark == NULL) {
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010012197 if ((c == '>' || c == '<' IF_BASH_REDIR_OUTPUT( || c == 0x100 + '>'))
Denis Vlasenko834dee72008-10-07 09:18:30 +000012198 && quotef == 0
12199 ) {
Denis Vlasenko559691a2008-10-05 18:39:31 +000012200 if (isdigit_str9(out)) {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000012201 PARSEREDIR(); /* passed as params: out, c */
12202 lasttoken = TREDIR;
12203 return lasttoken;
12204 }
12205 /* else: non-number X seen, interpret it
12206 * as "NNNX>file" = "NNNX >file" */
Eric Andersencb57d552001-06-28 07:25:16 +000012207 }
Denis Vlasenkoef527f52008-06-23 01:52:30 +000012208 pungetc();
Eric Andersencb57d552001-06-28 07:25:16 +000012209 }
12210 quoteflag = quotef;
12211 backquotelist = bqlist;
12212 grabstackblock(len);
12213 wordtext = out;
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000012214 lasttoken = TWORD;
12215 return lasttoken;
Eric Andersencb57d552001-06-28 07:25:16 +000012216/* end of readtoken routine */
12217
Eric Andersencb57d552001-06-28 07:25:16 +000012218/*
12219 * Check to see whether we are at the end of the here document. When this
12220 * is called, c is set to the first character of the next input line. If
12221 * we are at the end of the here document, this routine sets the c to PEOF.
12222 */
Eric Andersenc470f442003-07-28 09:56:35 +000012223checkend: {
Denys Vlasenko46999802017-07-29 21:12:29 +020012224 if (realeofmark(eofmark)) {
Denys Vlasenkoa7328982017-07-29 19:57:28 +020012225 int markloc;
12226 char *p;
12227
Denis Vlasenko131ae172007-02-18 13:00:19 +000012228#if ENABLE_ASH_ALIAS
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010012229 if (c == PEOA)
12230 c = pgetc_without_PEOA();
Eric Andersenc470f442003-07-28 09:56:35 +000012231#endif
12232 if (striptabs) {
12233 while (c == '\t') {
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010012234 c = pgetc_without_PEOA();
Eric Andersencb57d552001-06-28 07:25:16 +000012235 }
Eric Andersenc470f442003-07-28 09:56:35 +000012236 }
Eric Andersencb57d552001-06-28 07:25:16 +000012237
Denys Vlasenkoa7328982017-07-29 19:57:28 +020012238 markloc = out - (char *)stackblock();
12239 for (p = eofmark; STPUTC(c, out), *p; p++) {
12240 if (c != *p)
12241 goto more_heredoc;
12242
12243 c = pgetc_without_PEOA();
12244 }
12245
12246 if (c == '\n' || c == PEOF) {
12247 c = PEOF;
12248 g_parsefile->linno++;
12249 needprompt = doprompt;
12250 } else {
12251 int len_here;
12252
12253 more_heredoc:
12254 p = (char *)stackblock() + markloc + 1;
12255 len_here = out - p;
12256
12257 if (len_here) {
12258 len_here -= (c >= PEOF);
12259 c = p[-1];
12260
12261 if (len_here) {
12262 char *str;
12263
12264 str = alloca(len_here + 1);
12265 *(char *)mempcpy(str, p, len_here) = '\0';
12266
12267 pushstring(str, NULL);
Eric Andersencb57d552001-06-28 07:25:16 +000012268 }
12269 }
12270 }
Denys Vlasenkoa7328982017-07-29 19:57:28 +020012271
12272 STADJUST((char *)stackblock() + markloc - out, out);
Eric Andersencb57d552001-06-28 07:25:16 +000012273 }
Eric Andersenc470f442003-07-28 09:56:35 +000012274 goto checkend_return;
12275}
Eric Andersencb57d552001-06-28 07:25:16 +000012276
Eric Andersencb57d552001-06-28 07:25:16 +000012277/*
12278 * Parse a redirection operator. The variable "out" points to a string
12279 * specifying the fd to be redirected. The variable "c" contains the
12280 * first character of the redirection operator.
12281 */
Eric Andersenc470f442003-07-28 09:56:35 +000012282parseredir: {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000012283 /* out is already checked to be a valid number or "" */
12284 int fd = (*out == '\0' ? -1 : atoi(out));
Eric Andersenc470f442003-07-28 09:56:35 +000012285 union node *np;
Eric Andersencb57d552001-06-28 07:25:16 +000012286
Denis Vlasenko597906c2008-02-20 16:38:54 +000012287 np = stzalloc(sizeof(struct nfile));
Eric Andersenc470f442003-07-28 09:56:35 +000012288 if (c == '>') {
12289 np->nfile.fd = 1;
Denys Vlasenko220be532018-03-31 19:21:31 +020012290 c = pgetc_eatbnl();
Eric Andersenc470f442003-07-28 09:56:35 +000012291 if (c == '>')
12292 np->type = NAPPEND;
12293 else if (c == '|')
12294 np->type = NCLOBBER;
12295 else if (c == '&')
12296 np->type = NTOFD;
Denis Vlasenko559691a2008-10-05 18:39:31 +000012297 /* it also can be NTO2 (>&file), but we can't figure it out yet */
Eric Andersenc470f442003-07-28 09:56:35 +000012298 else {
12299 np->type = NTO;
12300 pungetc();
Eric Andersencb57d552001-06-28 07:25:16 +000012301 }
Denis Vlasenko834dee72008-10-07 09:18:30 +000012302 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010012303#if BASH_REDIR_OUTPUT
Denis Vlasenko834dee72008-10-07 09:18:30 +000012304 else if (c == 0x100 + '>') { /* this flags &> redirection */
12305 np->nfile.fd = 1;
12306 pgetc(); /* this is '>', no need to check */
12307 np->type = NTO2;
12308 }
12309#endif
12310 else { /* c == '<' */
Denis Vlasenko597906c2008-02-20 16:38:54 +000012311 /*np->nfile.fd = 0; - stzalloc did it */
Denys Vlasenko220be532018-03-31 19:21:31 +020012312 c = pgetc_eatbnl();
Denis Vlasenko5cedb752007-02-18 19:56:41 +000012313 switch (c) {
Eric Andersenc470f442003-07-28 09:56:35 +000012314 case '<':
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000012315 if (sizeof(struct nfile) != sizeof(struct nhere)) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000012316 np = stzalloc(sizeof(struct nhere));
12317 /*np->nfile.fd = 0; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000012318 }
12319 np->type = NHERE;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000012320 heredoc = stzalloc(sizeof(struct heredoc));
Eric Andersenc470f442003-07-28 09:56:35 +000012321 heredoc->here = np;
Denys Vlasenko220be532018-03-31 19:21:31 +020012322 c = pgetc_eatbnl();
Denis Vlasenko5cedb752007-02-18 19:56:41 +000012323 if (c == '-') {
Eric Andersenc470f442003-07-28 09:56:35 +000012324 heredoc->striptabs = 1;
12325 } else {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000012326 /*heredoc->striptabs = 0; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000012327 pungetc();
12328 }
12329 break;
12330
12331 case '&':
12332 np->type = NFROMFD;
12333 break;
12334
12335 case '>':
12336 np->type = NFROMTO;
12337 break;
12338
12339 default:
12340 np->type = NFROM;
12341 pungetc();
12342 break;
12343 }
Eric Andersencb57d552001-06-28 07:25:16 +000012344 }
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000012345 if (fd >= 0)
12346 np->nfile.fd = fd;
Eric Andersenc470f442003-07-28 09:56:35 +000012347 redirnode = np;
12348 goto parseredir_return;
12349}
Eric Andersencb57d552001-06-28 07:25:16 +000012350
Eric Andersencb57d552001-06-28 07:25:16 +000012351/*
12352 * Parse a substitution. At this point, we have read the dollar sign
12353 * and nothing else.
12354 */
Denis Vlasenkocc571512007-02-23 21:10:35 +000012355
12356/* is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise
12357 * (assuming ascii char codes, as the original implementation did) */
12358#define is_special(c) \
Denis Vlasenkoef527f52008-06-23 01:52:30 +000012359 (((unsigned)(c) - 33 < 32) \
12360 && ((0xc1ff920dU >> ((unsigned)(c) - 33)) & 1))
Eric Andersenc470f442003-07-28 09:56:35 +000012361parsesub: {
Denys Vlasenkocd716832009-11-28 22:14:02 +010012362 unsigned char subtype;
Eric Andersenc470f442003-07-28 09:56:35 +000012363 int typeloc;
Eric Andersencb57d552001-06-28 07:25:16 +000012364
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012365 c = pgetc_eatbnl();
Denys Vlasenkoa7328982017-07-29 19:57:28 +020012366 if ((checkkwd & CHKEOFMARK)
12367 || c > 255 /* PEOA or PEOF */
Denis Vlasenkoef527f52008-06-23 01:52:30 +000012368 || (c != '(' && c != '{' && !is_name(c) && !is_special(c))
Eric Andersenc470f442003-07-28 09:56:35 +000012369 ) {
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010012370#if BASH_DOLLAR_SQUOTE
Denys Vlasenko216913c2018-04-02 12:35:04 +020012371 if (synstack->syntax != DQSYNTAX && c == '\'')
Denis Vlasenkoef527f52008-06-23 01:52:30 +000012372 bash_dollar_squote = 1;
12373 else
12374#endif
12375 USTPUTC('$', out);
Eric Andersenc470f442003-07-28 09:56:35 +000012376 pungetc();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012377 } else if (c == '(') {
12378 /* $(command) or $((arith)) */
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012379 if (pgetc_eatbnl() == '(') {
Denys Vlasenko0b883582016-12-23 16:49:07 +010012380#if ENABLE_FEATURE_SH_MATH
Eric Andersenc470f442003-07-28 09:56:35 +000012381 PARSEARITH();
12382#else
Denys Vlasenko4f8079d2017-07-17 17:11:48 +020012383 raise_error_syntax("support for $((arith)) is disabled");
Eric Andersenc470f442003-07-28 09:56:35 +000012384#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012385 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000012386 pungetc();
12387 PARSEBACKQNEW();
12388 }
12389 } else {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012390 /* $VAR, $<specialchar>, ${...}, or PEOA/PEOF */
Denys Vlasenko216913c2018-04-02 12:35:04 +020012391 smalluint newsyn = synstack->syntax;
12392
Eric Andersenc470f442003-07-28 09:56:35 +000012393 USTPUTC(CTLVAR, out);
12394 typeloc = out - (char *)stackblock();
Denys Vlasenko3df14102016-10-26 16:41:13 +020012395 STADJUST(1, out);
Eric Andersenc470f442003-07-28 09:56:35 +000012396 subtype = VSNORMAL;
12397 if (c == '{') {
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012398 c = pgetc_eatbnl();
Denys Vlasenkof15aa572016-10-26 15:56:53 +020012399 subtype = 0;
Eric Andersenc470f442003-07-28 09:56:35 +000012400 }
Denys Vlasenkof15aa572016-10-26 15:56:53 +020012401 varname:
Denys Vlasenko3df14102016-10-26 16:41:13 +020012402 if (is_name(c)) {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012403 /* $[{[#]]NAME[}] */
Eric Andersenc470f442003-07-28 09:56:35 +000012404 do {
12405 STPUTC(c, out);
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012406 c = pgetc_eatbnl();
Denys Vlasenko3df14102016-10-26 16:41:13 +020012407 } while (is_in_name(c));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012408 } else if (isdigit(c)) {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012409 /* $[{[#]]NUM[}] */
Eric Andersenc470f442003-07-28 09:56:35 +000012410 do {
12411 STPUTC(c, out);
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012412 c = pgetc_eatbnl();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012413 } while (isdigit(c));
Denys Vlasenko452cc1d2017-08-14 14:23:45 +020012414 } else {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012415 /* $[{[#]]<specialchar>[}] */
Denys Vlasenkof15aa572016-10-26 15:56:53 +020012416 int cc = c;
12417
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012418 c = pgetc_eatbnl();
Denys Vlasenkof15aa572016-10-26 15:56:53 +020012419 if (!subtype && cc == '#') {
12420 subtype = VSLENGTH;
12421 if (c == '_' || isalnum(c))
12422 goto varname;
12423 cc = c;
12424 c = pgetc_eatbnl();
12425 if (cc == '}' || c != '}') {
12426 pungetc();
12427 subtype = 0;
12428 c = cc;
12429 cc = '#';
12430 }
12431 }
Denys Vlasenko452cc1d2017-08-14 14:23:45 +020012432
12433 if (!is_special(cc)) {
12434 if (subtype == VSLENGTH)
12435 subtype = 0;
12436 goto badsub;
12437 }
12438
Denys Vlasenkof15aa572016-10-26 15:56:53 +020012439 USTPUTC(cc, out);
Denis Vlasenko559691a2008-10-05 18:39:31 +000012440 }
Denys Vlasenko452cc1d2017-08-14 14:23:45 +020012441
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012442 if (c != '}' && subtype == VSLENGTH) {
12443 /* ${#VAR didn't end with } */
Cristian Ionescu-Idbohrn301f5ec2009-10-05 02:07:23 +020012444 goto badsub;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012445 }
Eric Andersencb57d552001-06-28 07:25:16 +000012446
Eric Andersenc470f442003-07-28 09:56:35 +000012447 if (subtype == 0) {
Denys Vlasenkof8ddbe12016-07-25 03:56:00 +020012448 static const char types[] ALIGN1 = "}-+?=";
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012449 /* ${VAR...} but not $VAR or ${#VAR} */
12450 /* c == first char after VAR */
Denys Vlasenko216913c2018-04-02 12:35:04 +020012451 int cc = c;
12452
Eric Andersenc470f442003-07-28 09:56:35 +000012453 switch (c) {
12454 case ':':
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012455 c = pgetc_eatbnl();
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010012456#if BASH_SUBSTR
Denys Vlasenkof8ddbe12016-07-25 03:56:00 +020012457 /* This check is only needed to not misinterpret
12458 * ${VAR:-WORD}, ${VAR:+WORD}, ${VAR:=WORD}, ${VAR:?WORD}
12459 * constructs.
12460 */
12461 if (!strchr(types, c)) {
Denis Vlasenko92e13c22008-03-25 01:17:40 +000012462 subtype = VSSUBSTR;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012463 pungetc();
Denys Vlasenko88e15702016-10-26 01:55:56 +020012464 break; /* "goto badsub" is bigger (!) */
Denis Vlasenko92e13c22008-03-25 01:17:40 +000012465 }
12466#endif
Denys Vlasenko3df14102016-10-26 16:41:13 +020012467 subtype = VSNUL;
Eric Andersenc470f442003-07-28 09:56:35 +000012468 /*FALLTHROUGH*/
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012469 default: {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012470 const char *p = strchr(types, c);
Eric Andersenc470f442003-07-28 09:56:35 +000012471 if (p == NULL)
Denys Vlasenko88e15702016-10-26 01:55:56 +020012472 break;
Denys Vlasenko3df14102016-10-26 16:41:13 +020012473 subtype |= p - types + VSNORMAL;
Eric Andersenc470f442003-07-28 09:56:35 +000012474 break;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012475 }
Eric Andersenc470f442003-07-28 09:56:35 +000012476 case '%':
Denys Vlasenko216913c2018-04-02 12:35:04 +020012477 case '#':
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012478 subtype = (c == '#' ? VSTRIMLEFT : VSTRIMRIGHT);
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012479 c = pgetc_eatbnl();
Denys Vlasenko216913c2018-04-02 12:35:04 +020012480 if (c == cc)
12481 subtype++;
12482 else
12483 pungetc();
12484
12485 newsyn = BASESYNTAX;
Denis Vlasenko92e13c22008-03-25 01:17:40 +000012486 break;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010012487#if BASH_PATTERN_SUBST
Denis Vlasenko92e13c22008-03-25 01:17:40 +000012488 case '/':
Denys Vlasenko6040fe82010-09-12 15:03:16 +020012489 /* ${v/[/]pattern/repl} */
12490//TODO: encode pattern and repl separately.
Denys Vlasenko216913c2018-04-02 12:35:04 +020012491// Currently cases like: v=1;echo ${v/$((1/1))/ONE}
12492// are broken (should print "ONE")
Denis Vlasenko92e13c22008-03-25 01:17:40 +000012493 subtype = VSREPLACE;
Denys Vlasenko216913c2018-04-02 12:35:04 +020012494 newsyn = BASESYNTAX;
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012495 c = pgetc_eatbnl();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012496 if (c != '/')
Denys Vlasenko88e15702016-10-26 01:55:56 +020012497 goto badsub;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012498 subtype++; /* VSREPLACEALL */
Denis Vlasenko92e13c22008-03-25 01:17:40 +000012499 break;
12500#endif
Eric Andersencb57d552001-06-28 07:25:16 +000012501 }
Eric Andersenc470f442003-07-28 09:56:35 +000012502 } else {
Denys Vlasenko88e15702016-10-26 01:55:56 +020012503 badsub:
Eric Andersenc470f442003-07-28 09:56:35 +000012504 pungetc();
12505 }
Denys Vlasenko216913c2018-04-02 12:35:04 +020012506
Denys Vlasenkof50e1462018-04-02 21:00:59 +020012507 if (newsyn == ARISYNTAX)
Denys Vlasenko216913c2018-04-02 12:35:04 +020012508 newsyn = DQSYNTAX;
12509
Denys Vlasenkof50e1462018-04-02 21:00:59 +020012510 if ((newsyn != synstack->syntax || synstack->innerdq)
12511 && subtype != VSNORMAL
12512 ) {
Denys Vlasenko216913c2018-04-02 12:35:04 +020012513 synstack_push(&synstack,
12514 synstack->prev ?: alloca(sizeof(*synstack)),
12515 newsyn);
12516
12517 synstack->varpushed = 1;
12518 synstack->dblquote = newsyn != BASESYNTAX;
12519 }
12520
Denys Vlasenko3df14102016-10-26 16:41:13 +020012521 ((unsigned char *)stackblock())[typeloc] = subtype;
Eric Andersenc470f442003-07-28 09:56:35 +000012522 if (subtype != VSNORMAL) {
Denys Vlasenko216913c2018-04-02 12:35:04 +020012523 synstack->varnest++;
12524 if (synstack->dblquote)
12525 synstack->dqvarnest++;
Eric Andersencb57d552001-06-28 07:25:16 +000012526 }
Denys Vlasenko88e15702016-10-26 01:55:56 +020012527 STPUTC('=', out);
Eric Andersencb57d552001-06-28 07:25:16 +000012528 }
Eric Andersenc470f442003-07-28 09:56:35 +000012529 goto parsesub_return;
12530}
Eric Andersencb57d552001-06-28 07:25:16 +000012531
Eric Andersencb57d552001-06-28 07:25:16 +000012532/*
12533 * Called to parse command substitutions. Newstyle is set if the command
12534 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
12535 * list of commands (passed by reference), and savelen is the number of
12536 * characters on the top of the stack which must be preserved.
12537 */
Eric Andersenc470f442003-07-28 09:56:35 +000012538parsebackq: {
12539 struct nodelist **nlpp;
Eric Andersenc470f442003-07-28 09:56:35 +000012540 union node *n;
Ron Yorston072fc602015-07-01 16:46:18 +010012541 char *str;
Eric Andersenc470f442003-07-28 09:56:35 +000012542 size_t savelen;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000012543 smallint saveprompt = 0;
12544
Eric Andersenc470f442003-07-28 09:56:35 +000012545 str = NULL;
12546 savelen = out - (char *)stackblock();
12547 if (savelen > 0) {
Denys Vlasenko7bc3d392016-09-17 20:53:47 +020012548 /*
12549 * FIXME: this can allocate very large block on stack and SEGV.
12550 * Example:
12551 * echo "..<100kbytes>..`true` $(true) `true` ..."
Denys Vlasenko73737592016-09-17 20:58:22 +020012552 * allocates 100kb for every command subst. With about
Denys Vlasenko7bc3d392016-09-17 20:53:47 +020012553 * a hundred command substitutions stack overflows.
12554 * With larger prepended string, SEGV happens sooner.
12555 */
Ron Yorston072fc602015-07-01 16:46:18 +010012556 str = alloca(savelen);
Eric Andersenc470f442003-07-28 09:56:35 +000012557 memcpy(str, stackblock(), savelen);
12558 }
Denys Vlasenko7bc3d392016-09-17 20:53:47 +020012559
Eric Andersenc470f442003-07-28 09:56:35 +000012560 if (oldstyle) {
12561 /* We must read until the closing backquote, giving special
Denys Vlasenko60cb48c2013-01-14 15:57:44 +010012562 * treatment to some slashes, and then push the string and
12563 * reread it as input, interpreting it normally.
12564 */
Eric Andersenc470f442003-07-28 09:56:35 +000012565 char *pout;
Eric Andersenc470f442003-07-28 09:56:35 +000012566 size_t psavelen;
12567 char *pstr;
12568
Eric Andersenc470f442003-07-28 09:56:35 +000012569 STARTSTACKSTR(pout);
12570 for (;;) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020012571 int pc;
12572
12573 setprompt_if(needprompt, 2);
Denys Vlasenko220be532018-03-31 19:21:31 +020012574 pc = pgetc_eatbnl();
Denis Vlasenko5cedb752007-02-18 19:56:41 +000012575 switch (pc) {
Eric Andersenc470f442003-07-28 09:56:35 +000012576 case '`':
12577 goto done;
12578
12579 case '\\':
Denys Vlasenko220be532018-03-31 19:21:31 +020012580 pc = pgetc(); /* or pgetc_eatbnl()? why (example)? */
Eric Andersenc470f442003-07-28 09:56:35 +000012581 if (pc != '\\' && pc != '`' && pc != '$'
Denys Vlasenko216913c2018-04-02 12:35:04 +020012582 && (!synstack->dblquote || pc != '"')
Denys Vlasenko76bc2d62009-11-29 01:37:46 +010012583 ) {
Eric Andersenc470f442003-07-28 09:56:35 +000012584 STPUTC('\\', pout);
Denys Vlasenko76bc2d62009-11-29 01:37:46 +010012585 }
Denys Vlasenkocd716832009-11-28 22:14:02 +010012586 if (pc <= 255 /* not PEOA or PEOF */) {
Eric Andersenc470f442003-07-28 09:56:35 +000012587 break;
12588 }
12589 /* fall through */
12590
12591 case PEOF:
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010012592 IF_ASH_ALIAS(case PEOA:)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000012593 raise_error_syntax("EOF in backquote substitution");
Eric Andersenc470f442003-07-28 09:56:35 +000012594
12595 case '\n':
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012596 nlnoprompt();
Eric Andersenc470f442003-07-28 09:56:35 +000012597 break;
12598
12599 default:
12600 break;
12601 }
12602 STPUTC(pc, pout);
12603 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +000012604 done:
Eric Andersenc470f442003-07-28 09:56:35 +000012605 STPUTC('\0', pout);
12606 psavelen = pout - (char *)stackblock();
12607 if (psavelen > 0) {
12608 pstr = grabstackstr(pout);
12609 setinputstring(pstr);
12610 }
12611 }
12612 nlpp = &bqlist;
12613 while (*nlpp)
12614 nlpp = &(*nlpp)->next;
Denis Vlasenko597906c2008-02-20 16:38:54 +000012615 *nlpp = stzalloc(sizeof(**nlpp));
12616 /* (*nlpp)->next = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000012617
12618 if (oldstyle) {
12619 saveprompt = doprompt;
12620 doprompt = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000012621 }
12622
Eric Andersenc470f442003-07-28 09:56:35 +000012623 n = list(2);
12624
12625 if (oldstyle)
12626 doprompt = saveprompt;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012627 else if (readtoken() != TRP)
12628 raise_error_unexpected_syntax(TRP);
Eric Andersenc470f442003-07-28 09:56:35 +000012629
12630 (*nlpp)->n = n;
12631 if (oldstyle) {
12632 /*
12633 * Start reading from old file again, ignoring any pushed back
12634 * tokens left from the backquote parsing
12635 */
12636 popfile();
12637 tokpushback = 0;
12638 }
12639 while (stackblocksize() <= savelen)
12640 growstackblock();
12641 STARTSTACKSTR(out);
12642 if (str) {
12643 memcpy(out, str, savelen);
12644 STADJUST(savelen, out);
Eric Andersenc470f442003-07-28 09:56:35 +000012645 }
Ron Yorston549deab2015-05-18 09:57:51 +020012646 USTPUTC(CTLBACKQ, out);
Eric Andersenc470f442003-07-28 09:56:35 +000012647 if (oldstyle)
12648 goto parsebackq_oldreturn;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000012649 goto parsebackq_newreturn;
Eric Andersenc470f442003-07-28 09:56:35 +000012650}
12651
Denys Vlasenko0b883582016-12-23 16:49:07 +010012652#if ENABLE_FEATURE_SH_MATH
Eric Andersencb57d552001-06-28 07:25:16 +000012653/*
12654 * Parse an arithmetic expansion (indicate start of one and set state)
12655 */
Eric Andersenc470f442003-07-28 09:56:35 +000012656parsearith: {
Denys Vlasenko216913c2018-04-02 12:35:04 +020012657
12658 synstack_push(&synstack,
12659 synstack->prev ?: alloca(sizeof(*synstack)),
12660 ARISYNTAX);
12661 synstack->dblquote = 1;
Ron Yorstonad88bde2015-05-18 09:56:16 +020012662 USTPUTC(CTLARI, out);
Eric Andersenc470f442003-07-28 09:56:35 +000012663 goto parsearith_return;
12664}
12665#endif
Eric Andersenc470f442003-07-28 09:56:35 +000012666} /* end of readtoken */
12667
Eric Andersencb57d552001-06-28 07:25:16 +000012668/*
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012669 * Read the next input token.
12670 * If the token is a word, we set backquotelist to the list of cmds in
12671 * backquotes. We set quoteflag to true if any part of the word was
12672 * quoted.
12673 * If the token is TREDIR, then we set redirnode to a structure containing
12674 * the redirection.
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012675 *
12676 * [Change comment: here documents and internal procedures]
12677 * [Readtoken shouldn't have any arguments. Perhaps we should make the
12678 * word parsing code into a separate routine. In this case, readtoken
12679 * doesn't need to have any internal procedures, but parseword does.
12680 * We could also make parseoperator in essence the main routine, and
12681 * have parseword (readtoken1?) handle both words and redirection.]
Eric Andersencb57d552001-06-28 07:25:16 +000012682 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012683#define NEW_xxreadtoken
12684#ifdef NEW_xxreadtoken
12685/* singles must be first! */
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000012686static const char xxreadtoken_chars[7] ALIGN1 = {
Denis Vlasenko834dee72008-10-07 09:18:30 +000012687 '\n', '(', ')', /* singles */
12688 '&', '|', ';', /* doubles */
12689 0
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000012690};
Eric Andersencb57d552001-06-28 07:25:16 +000012691
Denis Vlasenko834dee72008-10-07 09:18:30 +000012692#define xxreadtoken_singles 3
12693#define xxreadtoken_doubles 3
12694
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000012695static const char xxreadtoken_tokens[] ALIGN1 = {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012696 TNL, TLP, TRP, /* only single occurrence allowed */
12697 TBACKGND, TPIPE, TSEMI, /* if single occurrence */
12698 TEOF, /* corresponds to trailing nul */
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000012699 TAND, TOR, TENDCASE /* if double occurrence */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012700};
12701
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012702static int
12703xxreadtoken(void)
12704{
12705 int c;
12706
12707 if (tokpushback) {
12708 tokpushback = 0;
12709 return lasttoken;
Eric Andersencb57d552001-06-28 07:25:16 +000012710 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020012711 setprompt_if(needprompt, 2);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012712 for (;;) { /* until token or start of word found */
Denys Vlasenko220be532018-03-31 19:21:31 +020012713 c = pgetc_eatbnl();
Denis Vlasenko5e34ff22009-04-21 11:09:40 +000012714 if (c == ' ' || c == '\t' IF_ASH_ALIAS( || c == PEOA))
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012715 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012716
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012717 if (c == '#') {
12718 while ((c = pgetc()) != '\n' && c != PEOF)
12719 continue;
12720 pungetc();
12721 } else if (c == '\\') {
Denys Vlasenko220be532018-03-31 19:21:31 +020012722 break; /* return readtoken1(...) */
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012723 } else {
12724 const char *p;
12725
12726 p = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
12727 if (c != PEOF) {
12728 if (c == '\n') {
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012729 nlnoprompt();
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012730 }
12731
12732 p = strchr(xxreadtoken_chars, c);
Denis Vlasenko834dee72008-10-07 09:18:30 +000012733 if (p == NULL)
12734 break; /* return readtoken1(...) */
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012735
Denis Vlasenko834dee72008-10-07 09:18:30 +000012736 if ((int)(p - xxreadtoken_chars) >= xxreadtoken_singles) {
Denys Vlasenko1e5111b2018-04-01 03:04:55 +020012737 int cc = pgetc_eatbnl();
Denis Vlasenko834dee72008-10-07 09:18:30 +000012738 if (cc == c) { /* double occurrence? */
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012739 p += xxreadtoken_doubles + 1;
12740 } else {
12741 pungetc();
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010012742#if BASH_REDIR_OUTPUT
Denis Vlasenko834dee72008-10-07 09:18:30 +000012743 if (c == '&' && cc == '>') /* &> */
12744 break; /* return readtoken1(...) */
12745#endif
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012746 }
12747 }
12748 }
12749 lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
12750 return lasttoken;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012751 }
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012752 } /* for (;;) */
Denis Vlasenko834dee72008-10-07 09:18:30 +000012753
12754 return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012755}
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012756#else /* old xxreadtoken */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012757#define RETURN(token) return lasttoken = token
12758static int
12759xxreadtoken(void)
12760{
12761 int c;
12762
12763 if (tokpushback) {
12764 tokpushback = 0;
12765 return lasttoken;
12766 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020012767 setprompt_if(needprompt, 2);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012768 for (;;) { /* until token or start of word found */
Denys Vlasenko220be532018-03-31 19:21:31 +020012769 c = pgetc_eatbnl();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012770 switch (c) {
12771 case ' ': case '\t':
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010012772 IF_ASH_ALIAS(case PEOA:)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012773 continue;
12774 case '#':
Denis Vlasenkof7d56652008-03-25 05:51:41 +000012775 while ((c = pgetc()) != '\n' && c != PEOF)
12776 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012777 pungetc();
12778 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012779 case '\n':
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012780 nlnoprompt();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012781 RETURN(TNL);
12782 case PEOF:
12783 RETURN(TEOF);
12784 case '&':
Denys Vlasenko220be532018-03-31 19:21:31 +020012785 if (pgetc_eatbnl() == '&')
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012786 RETURN(TAND);
12787 pungetc();
12788 RETURN(TBACKGND);
12789 case '|':
Denys Vlasenko220be532018-03-31 19:21:31 +020012790 if (pgetc_eatbnl() == '|')
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012791 RETURN(TOR);
12792 pungetc();
12793 RETURN(TPIPE);
12794 case ';':
Denys Vlasenko220be532018-03-31 19:21:31 +020012795 if (pgetc_eatbnl() == ';')
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012796 RETURN(TENDCASE);
12797 pungetc();
12798 RETURN(TSEMI);
12799 case '(':
12800 RETURN(TLP);
12801 case ')':
12802 RETURN(TRP);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012803 }
Denys Vlasenko220be532018-03-31 19:21:31 +020012804 break;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012805 }
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012806 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
12807#undef RETURN
12808}
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012809#endif /* old xxreadtoken */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012810
12811static int
12812readtoken(void)
12813{
12814 int t;
Ron Yorston713f07d2015-10-29 16:44:56 +000012815 int kwd = checkkwd;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012816#if DEBUG
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000012817 smallint alreadyseen = tokpushback;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012818#endif
12819
12820#if ENABLE_ASH_ALIAS
12821 top:
12822#endif
12823
12824 t = xxreadtoken();
12825
12826 /*
12827 * eat newlines
12828 */
Ron Yorston713f07d2015-10-29 16:44:56 +000012829 if (kwd & CHKNL) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012830 while (t == TNL) {
12831 parseheredoc();
12832 t = xxreadtoken();
12833 }
12834 }
12835
12836 if (t != TWORD || quoteflag) {
12837 goto out;
12838 }
12839
12840 /*
12841 * check for keywords
12842 */
Ron Yorston713f07d2015-10-29 16:44:56 +000012843 if (kwd & CHKKWD) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012844 const char *const *pp;
12845
12846 pp = findkwd(wordtext);
12847 if (pp) {
12848 lasttoken = t = pp - tokname_array;
Denys Vlasenko888527c2016-10-02 16:54:17 +020012849 TRACE(("keyword '%s' recognized\n", tokname_array[t]));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012850 goto out;
12851 }
12852 }
12853
12854 if (checkkwd & CHKALIAS) {
12855#if ENABLE_ASH_ALIAS
12856 struct alias *ap;
12857 ap = lookupalias(wordtext, 1);
12858 if (ap != NULL) {
12859 if (*ap->val) {
12860 pushstring(ap->val, ap);
12861 }
12862 goto top;
12863 }
12864#endif
12865 }
12866 out:
12867 checkkwd = 0;
12868#if DEBUG
12869 if (!alreadyseen)
Denys Vlasenko888527c2016-10-02 16:54:17 +020012870 TRACE(("token '%s' %s\n", tokname_array[t], t == TWORD ? wordtext : ""));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012871 else
Denys Vlasenko888527c2016-10-02 16:54:17 +020012872 TRACE(("reread token '%s' %s\n", tokname_array[t], t == TWORD ? wordtext : ""));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012873#endif
12874 return t;
Eric Andersencb57d552001-06-28 07:25:16 +000012875}
12876
Ron Yorstonc0e00762015-10-29 11:30:55 +000012877static int
Ron Yorston6bd2fab2015-10-29 11:30:22 +000012878peektoken(void)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012879{
12880 int t;
12881
12882 t = readtoken();
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000012883 tokpushback = 1;
Ron Yorstonc0e00762015-10-29 11:30:55 +000012884 return t;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012885}
Eric Andersencb57d552001-06-28 07:25:16 +000012886
12887/*
Denys Vlasenko86e83ec2009-07-23 22:07:07 +020012888 * Read and parse a command. Returns NODE_EOF on end of file.
12889 * (NULL is a valid parse tree indicating a blank line.)
Eric Andersencb57d552001-06-28 07:25:16 +000012890 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012891static union node *
12892parsecmd(int interact)
Eric Andersen90898442003-08-06 11:20:52 +000012893{
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012894 tokpushback = 0;
Ron Yorstonc0e00762015-10-29 11:30:55 +000012895 checkkwd = 0;
12896 heredoclist = 0;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012897 doprompt = interact;
Denys Vlasenko958581a2010-09-12 15:04:27 +020012898 setprompt_if(doprompt, doprompt);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012899 needprompt = 0;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012900 return list(1);
12901}
12902
12903/*
12904 * Input any here documents.
12905 */
12906static void
12907parseheredoc(void)
12908{
12909 struct heredoc *here;
12910 union node *n;
12911
12912 here = heredoclist;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000012913 heredoclist = NULL;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012914
12915 while (here) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020012916 setprompt_if(needprompt, 2);
12917 readtoken1(pgetc(), here->here->type == NHERE ? SQSYNTAX : DQSYNTAX,
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012918 here->eofmark, here->striptabs);
Denis Vlasenko597906c2008-02-20 16:38:54 +000012919 n = stzalloc(sizeof(struct narg));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012920 n->narg.type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000012921 /*n->narg.next = NULL; - stzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012922 n->narg.text = wordtext;
12923 n->narg.backquote = backquotelist;
12924 here->here->nhere.doc = n;
12925 here = here->next;
Eric Andersencb57d552001-06-28 07:25:16 +000012926 }
Eric Andersencb57d552001-06-28 07:25:16 +000012927}
12928
12929
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012930static const char *
Denys Vlasenko46999802017-07-29 21:12:29 +020012931expandstr(const char *ps, int syntax_type)
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012932{
12933 union node n;
Denys Vlasenko2a6d29a2016-10-25 21:17:52 +020012934 int saveprompt;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012935
Denys Vlasenko46999802017-07-29 21:12:29 +020012936 /* XXX Fix (char *) cast. */
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012937 setinputstring((char *)ps);
Denys Vlasenko2a6d29a2016-10-25 21:17:52 +020012938
12939 saveprompt = doprompt;
12940 doprompt = 0;
Denys Vlasenkoa2e32b32017-10-12 19:20:13 +020012941
12942 /* readtoken1() might die horribly.
Denys Vlasenko3c183a82017-10-12 19:35:42 +020012943 * Try a prompt with syntactically wrong command:
Denys Vlasenkoa2e32b32017-10-12 19:20:13 +020012944 * PS1='$(date "+%H:%M:%S) > '
12945 */
12946 {
12947 volatile int saveint;
12948 struct jmploc *volatile savehandler = exception_handler;
12949 struct jmploc jmploc;
12950 SAVE_INT(saveint);
12951 if (setjmp(jmploc.loc) == 0) {
12952 exception_handler = &jmploc;
12953 readtoken1(pgetc(), syntax_type, FAKEEOFMARK, 0);
12954 }
12955 exception_handler = savehandler;
12956 RESTORE_INT(saveint);
12957 }
12958
Denys Vlasenko2a6d29a2016-10-25 21:17:52 +020012959 doprompt = saveprompt;
12960
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012961 popfile();
12962
12963 n.narg.type = NARG;
12964 n.narg.next = NULL;
12965 n.narg.text = wordtext;
12966 n.narg.backquote = backquotelist;
12967
Ron Yorston549deab2015-05-18 09:57:51 +020012968 expandarg(&n, NULL, EXP_QUOTED);
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012969 return stackblock();
12970}
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012971
Denys Vlasenko1e3e2cc2017-07-25 20:31:14 +020012972static inline int
12973parser_eof(void)
12974{
12975 return tokpushback && lasttoken == TEOF;
12976}
12977
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012978/*
12979 * Execute a command or commands contained in a string.
12980 */
12981static int
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020012982evalstring(char *s, int flags)
Eric Andersenc470f442003-07-28 09:56:35 +000012983{
Denys Vlasenko493b9ca2016-10-30 18:27:14 +010012984 struct jmploc *volatile savehandler;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012985 struct jmploc jmploc;
12986 int ex;
12987
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012988 union node *n;
12989 struct stackmark smark;
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012990 int status;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012991
Denys Vlasenko8e2bc472016-09-28 23:02:57 +020012992 s = sstrdup(s);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012993 setinputstring(s);
12994 setstackmark(&smark);
12995
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012996 status = 0;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012997 /* On exception inside execution loop, we must popfile().
12998 * Try interactively:
12999 * readonly a=a
13000 * command eval "a=b" # throws "is read only" error
13001 * "command BLTIN" is not supposed to abort (even in non-interactive use).
13002 * But if we skip popfile(), we hit EOF in eval's string, and exit.
13003 */
13004 savehandler = exception_handler;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020013005 ex = setjmp(jmploc.loc);
13006 if (ex)
13007 goto out;
Denys Vlasenko493b9ca2016-10-30 18:27:14 +010013008 exception_handler = &jmploc;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020013009
Denys Vlasenko86e83ec2009-07-23 22:07:07 +020013010 while ((n = parsecmd(0)) != NODE_EOF) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020013011 int i;
13012
Denys Vlasenko1e3e2cc2017-07-25 20:31:14 +020013013 i = evaltree(n, flags & ~(parser_eof() ? 0 : EV_EXIT));
Denys Vlasenko928e2a72016-09-29 00:30:31 +020013014 if (n)
13015 status = i;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013016 popstackmark(&smark);
Denys Vlasenko928e2a72016-09-29 00:30:31 +020013017 if (evalskip)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013018 break;
13019 }
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020013020 out:
Denys Vlasenko8e2bc472016-09-28 23:02:57 +020013021 popstackmark(&smark);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013022 popfile();
Denys Vlasenko8e2bc472016-09-28 23:02:57 +020013023 stunalloc(s);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013024
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020013025 exception_handler = savehandler;
13026 if (ex)
Denys Vlasenko14c85eb2017-10-12 19:40:47 +020013027 longjmp(exception_handler->loc, ex);
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020013028
Denys Vlasenko928e2a72016-09-29 00:30:31 +020013029 return status;
Eric Andersenc470f442003-07-28 09:56:35 +000013030}
13031
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013032/*
13033 * The eval command.
13034 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013035static int FAST_FUNC
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020013036evalcmd(int argc UNUSED_PARAM, char **argv, int flags)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013037{
13038 char *p;
13039 char *concat;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013040
Denis Vlasenko68404f12008-03-17 09:00:54 +000013041 if (argv[1]) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013042 p = argv[1];
Denis Vlasenko68404f12008-03-17 09:00:54 +000013043 argv += 2;
13044 if (argv[0]) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013045 STARTSTACKSTR(concat);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013046 for (;;) {
13047 concat = stack_putstr(p, concat);
Denis Vlasenko68404f12008-03-17 09:00:54 +000013048 p = *argv++;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013049 if (p == NULL)
13050 break;
13051 STPUTC(' ', concat);
13052 }
13053 STPUTC('\0', concat);
13054 p = grabstackstr(concat);
13055 }
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020013056 return evalstring(p, flags & EV_TESTED);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013057 }
Denys Vlasenko928e2a72016-09-29 00:30:31 +020013058 return 0;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013059}
13060
13061/*
Denys Vlasenko285ad152009-12-04 23:02:27 +010013062 * Read and execute commands.
13063 * "Top" is nonzero for the top level command loop;
13064 * it turns on prompting if the shell is interactive.
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013065 */
13066static int
13067cmdloop(int top)
13068{
13069 union node *n;
13070 struct stackmark smark;
13071 int inter;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020013072 int status = 0;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013073 int numeof = 0;
13074
13075 TRACE(("cmdloop(%d) called\n", top));
13076 for (;;) {
13077 int skip;
13078
13079 setstackmark(&smark);
13080#if JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +000013081 if (doing_jobctl)
Denys Vlasenko9c541002015-10-07 15:44:36 +020013082 showjobs(SHOW_CHANGED|SHOW_STDERR);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013083#endif
13084 inter = 0;
13085 if (iflag && top) {
13086 inter++;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013087 chkmail();
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013088 }
13089 n = parsecmd(inter);
Denys Vlasenko7cee00e2009-07-24 01:08:03 +020013090#if DEBUG
13091 if (DEBUG > 2 && debug && (n != NODE_EOF))
Denys Vlasenko883cea42009-07-11 15:31:59 +020013092 showtree(n);
Denis Vlasenko135cecb2009-04-12 00:00:57 +000013093#endif
Denys Vlasenko86e83ec2009-07-23 22:07:07 +020013094 if (n == NODE_EOF) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013095 if (!top || numeof >= 50)
13096 break;
13097 if (!stoppedjobs()) {
13098 if (!Iflag)
13099 break;
13100 out2str("\nUse \"exit\" to leave shell.\n");
13101 }
13102 numeof++;
13103 } else if (nflag == 0) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020013104 int i;
13105
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +000013106 /* job_warning can only be 2,1,0. Here 2->1, 1/0->0 */
13107 job_warning >>= 1;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013108 numeof = 0;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020013109 i = evaltree(n, 0);
13110 if (n)
13111 status = i;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013112 }
13113 popstackmark(&smark);
13114 skip = evalskip;
13115
13116 if (skip) {
Denys Vlasenko6a0710e2016-09-30 14:18:34 +020013117 evalskip &= ~SKIPFUNC;
Denys Vlasenko0840c912016-10-01 15:27:44 +020013118 break;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013119 }
13120 }
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020013121 return status;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013122}
13123
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000013124/*
13125 * Take commands from a file. To be compatible we should do a path
13126 * search for the file, which is necessary to find sub-commands.
13127 */
13128static char *
13129find_dot_file(char *name)
13130{
13131 char *fullname;
13132 const char *path = pathval();
13133 struct stat statb;
13134
13135 /* don't try this for absolute or relative paths */
13136 if (strchr(name, '/'))
13137 return name;
13138
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020013139 while ((fullname = path_advance(&path, name)) != NULL) {
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000013140 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
13141 /*
13142 * Don't bother freeing here, since it will
13143 * be freed by the caller.
13144 */
13145 return fullname;
13146 }
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020013147 if (fullname != name)
13148 stunalloc(fullname);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000013149 }
Denys Vlasenko01f7b9e2018-01-26 15:15:43 +010013150 /* not found in PATH */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000013151
Denys Vlasenko01f7b9e2018-01-26 15:15:43 +010013152#if ENABLE_ASH_BASH_SOURCE_CURDIR
13153 return name;
13154#else
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000013155 ash_msg_and_raise_error("%s: not found", name);
13156 /* NOTREACHED */
Denys Vlasenko01f7b9e2018-01-26 15:15:43 +010013157#endif
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000013158}
13159
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013160static int FAST_FUNC
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020013161dotcmd(int argc_ UNUSED_PARAM, char **argv_ UNUSED_PARAM)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013162{
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020013163 /* "false; . empty_file; echo $?" should print 0, not 1: */
13164 int status = 0;
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020013165 char *fullname;
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020013166 char **argv;
Denys Vlasenkofb87d932017-01-09 08:22:06 +010013167 char *args_need_save;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013168 volatile struct shparam saveparam;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013169
Denys Vlasenko981a0562017-07-26 19:53:11 +020013170//???
13171// struct strlist *sp;
13172// for (sp = cmdenviron; sp; sp = sp->next)
13173// setvareq(ckstrdup(sp->text), VSTRFIXED | VTEXTFIXED);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013174
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020013175 nextopt(nullstr); /* handle possible "--" */
13176 argv = argptr;
13177
13178 if (!argv[0]) {
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020013179 /* bash says: "bash: .: filename argument required" */
13180 return 2; /* bash compat */
13181 }
13182
Denys Vlasenko091f8312013-03-17 14:25:22 +010013183 /* This aborts if file isn't found, which is POSIXly correct.
13184 * bash returns exitcode 1 instead.
13185 */
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020013186 fullname = find_dot_file(argv[0]);
13187 argv++;
Denys Vlasenkofb87d932017-01-09 08:22:06 +010013188 args_need_save = argv[0];
Denys Vlasenko5f7c82b2017-02-03 13:00:06 +010013189 if (args_need_save) { /* ". FILE ARGS", and ARGS are not empty */
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020013190 int argc;
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020013191 saveparam = shellparam;
13192 shellparam.malloced = 0;
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020013193 argc = 1;
13194 while (argv[argc])
13195 argc++;
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020013196 shellparam.nparam = argc;
13197 shellparam.p = argv;
13198 };
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013199
Denys Vlasenko091f8312013-03-17 14:25:22 +010013200 /* This aborts if file can't be opened, which is POSIXly correct.
13201 * bash returns exitcode 1 instead.
13202 */
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020013203 setinputfile(fullname, INPUT_PUSH_FILE);
13204 commandname = fullname;
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020013205 status = cmdloop(0);
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020013206 popfile();
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013207
Denys Vlasenkofb87d932017-01-09 08:22:06 +010013208 if (args_need_save) {
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020013209 freeparam(&shellparam);
13210 shellparam = saveparam;
13211 };
13212
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020013213 return status;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013214}
13215
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013216static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013217exitcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013218{
13219 if (stoppedjobs())
13220 return 0;
Denis Vlasenko68404f12008-03-17 09:00:54 +000013221 if (argv[1])
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013222 exitstatus = number(argv[1]);
13223 raise_exception(EXEXIT);
13224 /* NOTREACHED */
13225}
13226
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013227/*
13228 * Read a file containing shell functions.
13229 */
13230static void
13231readcmdfile(char *name)
13232{
13233 setinputfile(name, INPUT_PUSH_FILE);
13234 cmdloop(0);
13235 popfile();
13236}
13237
13238
Denis Vlasenkocc571512007-02-23 21:10:35 +000013239/* ============ find_command inplementation */
13240
13241/*
13242 * Resolve a command name. If you change this routine, you may have to
13243 * change the shellexec routine as well.
13244 */
13245static void
13246find_command(char *name, struct cmdentry *entry, int act, const char *path)
13247{
13248 struct tblentry *cmdp;
13249 int idx;
13250 int prev;
13251 char *fullname;
13252 struct stat statb;
13253 int e;
13254 int updatetbl;
13255 struct builtincmd *bcmd;
13256
13257 /* If name contains a slash, don't use PATH or hash table */
13258 if (strchr(name, '/') != NULL) {
13259 entry->u.index = -1;
13260 if (act & DO_ABS) {
13261 while (stat(name, &statb) < 0) {
13262#ifdef SYSV
13263 if (errno == EINTR)
13264 continue;
13265#endif
13266 entry->cmdtype = CMDUNKNOWN;
13267 return;
13268 }
13269 }
13270 entry->cmdtype = CMDNORMAL;
13271 return;
13272 }
13273
Denis Vlasenkof20de5b2007-04-29 23:42:54 +000013274/* #if ENABLE_FEATURE_SH_STANDALONE... moved after builtin check */
Denis Vlasenkocc571512007-02-23 21:10:35 +000013275
13276 updatetbl = (path == pathval());
13277 if (!updatetbl) {
13278 act |= DO_ALTPATH;
13279 if (strstr(path, "%builtin") != NULL)
13280 act |= DO_ALTBLTIN;
13281 }
13282
13283 /* If name is in the table, check answer will be ok */
13284 cmdp = cmdlookup(name, 0);
13285 if (cmdp != NULL) {
13286 int bit;
13287
13288 switch (cmdp->cmdtype) {
13289 default:
13290#if DEBUG
13291 abort();
13292#endif
13293 case CMDNORMAL:
13294 bit = DO_ALTPATH;
13295 break;
13296 case CMDFUNCTION:
13297 bit = DO_NOFUNC;
13298 break;
13299 case CMDBUILTIN:
13300 bit = DO_ALTBLTIN;
13301 break;
13302 }
13303 if (act & bit) {
13304 updatetbl = 0;
13305 cmdp = NULL;
13306 } else if (cmdp->rehash == 0)
13307 /* if not invalidated by cd, we're done */
13308 goto success;
13309 }
13310
13311 /* If %builtin not in path, check for builtin next */
13312 bcmd = find_builtin(name);
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000013313 if (bcmd) {
13314 if (IS_BUILTIN_REGULAR(bcmd))
13315 goto builtin_success;
13316 if (act & DO_ALTPATH) {
13317 if (!(act & DO_ALTBLTIN))
13318 goto builtin_success;
13319 } else if (builtinloc <= 0) {
13320 goto builtin_success;
Denis Vlasenko8e858e22007-03-07 09:35:43 +000013321 }
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000013322 }
Denis Vlasenkocc571512007-02-23 21:10:35 +000013323
Denis Vlasenkof20de5b2007-04-29 23:42:54 +000013324#if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko7465dbc2008-04-13 02:25:53 +000013325 {
13326 int applet_no = find_applet_by_name(name);
13327 if (applet_no >= 0) {
13328 entry->cmdtype = CMDNORMAL;
13329 entry->u.index = -2 - applet_no;
13330 return;
13331 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +000013332 }
13333#endif
13334
Denis Vlasenkocc571512007-02-23 21:10:35 +000013335 /* We have to search path. */
13336 prev = -1; /* where to start */
13337 if (cmdp && cmdp->rehash) { /* doing a rehash */
13338 if (cmdp->cmdtype == CMDBUILTIN)
13339 prev = builtinloc;
13340 else
13341 prev = cmdp->param.index;
13342 }
13343
13344 e = ENOENT;
13345 idx = -1;
13346 loop:
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020013347 while ((fullname = path_advance(&path, name)) != NULL) {
Denis Vlasenkocc571512007-02-23 21:10:35 +000013348 stunalloc(fullname);
Denis Vlasenkodee82b62007-07-29 14:05:27 +000013349 /* NB: code below will still use fullname
13350 * despite it being "unallocated" */
Denis Vlasenkocc571512007-02-23 21:10:35 +000013351 idx++;
13352 if (pathopt) {
13353 if (prefix(pathopt, "builtin")) {
13354 if (bcmd)
13355 goto builtin_success;
13356 continue;
Denis Vlasenko4a9ca132008-04-12 20:07:08 +000013357 }
13358 if ((act & DO_NOFUNC)
13359 || !prefix(pathopt, "func")
Denys Vlasenkoe4dcba12010-10-28 18:57:19 +020013360 ) { /* ignore unimplemented options */
Denis Vlasenkocc571512007-02-23 21:10:35 +000013361 continue;
13362 }
13363 }
13364 /* if rehash, don't redo absolute path names */
13365 if (fullname[0] == '/' && idx <= prev) {
13366 if (idx < prev)
13367 continue;
13368 TRACE(("searchexec \"%s\": no change\n", name));
13369 goto success;
13370 }
13371 while (stat(fullname, &statb) < 0) {
13372#ifdef SYSV
13373 if (errno == EINTR)
13374 continue;
13375#endif
13376 if (errno != ENOENT && errno != ENOTDIR)
13377 e = errno;
13378 goto loop;
13379 }
13380 e = EACCES; /* if we fail, this will be the error */
13381 if (!S_ISREG(statb.st_mode))
13382 continue;
13383 if (pathopt) { /* this is a %func directory */
13384 stalloc(strlen(fullname) + 1);
Denis Vlasenkodee82b62007-07-29 14:05:27 +000013385 /* NB: stalloc will return space pointed by fullname
13386 * (because we don't have any intervening allocations
13387 * between stunalloc above and this stalloc) */
Denis Vlasenkocc571512007-02-23 21:10:35 +000013388 readcmdfile(fullname);
13389 cmdp = cmdlookup(name, 0);
13390 if (cmdp == NULL || cmdp->cmdtype != CMDFUNCTION)
13391 ash_msg_and_raise_error("%s not defined in %s", name, fullname);
13392 stunalloc(fullname);
13393 goto success;
13394 }
13395 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
13396 if (!updatetbl) {
13397 entry->cmdtype = CMDNORMAL;
13398 entry->u.index = idx;
13399 return;
13400 }
13401 INT_OFF;
13402 cmdp = cmdlookup(name, 1);
13403 cmdp->cmdtype = CMDNORMAL;
13404 cmdp->param.index = idx;
13405 INT_ON;
13406 goto success;
13407 }
13408
13409 /* We failed. If there was an entry for this command, delete it */
13410 if (cmdp && updatetbl)
13411 delete_cmd_entry();
William Pitcockd8fd88a2018-01-24 18:33:18 +010013412 if (act & DO_ERR) {
13413#if ENABLE_ASH_BASH_NOT_FOUND_HOOK
13414 struct tblentry *hookp = cmdlookup("command_not_found_handle", 0);
13415 if (hookp && hookp->cmdtype == CMDFUNCTION) {
13416 char *argv[3];
13417 argv[0] = (char*) "command_not_found_handle";
13418 argv[1] = name;
13419 argv[2] = NULL;
13420 evalfun(hookp->param.func, 2, argv, 0);
13421 entry->cmdtype = CMDUNKNOWN;
13422 return;
13423 }
13424#endif
Denis Vlasenkocc571512007-02-23 21:10:35 +000013425 ash_msg("%s: %s", name, errmsg(e, "not found"));
William Pitcockd8fd88a2018-01-24 18:33:18 +010013426 }
Denis Vlasenkocc571512007-02-23 21:10:35 +000013427 entry->cmdtype = CMDUNKNOWN;
13428 return;
13429
13430 builtin_success:
13431 if (!updatetbl) {
13432 entry->cmdtype = CMDBUILTIN;
13433 entry->u.cmd = bcmd;
13434 return;
13435 }
13436 INT_OFF;
13437 cmdp = cmdlookup(name, 1);
13438 cmdp->cmdtype = CMDBUILTIN;
13439 cmdp->param.cmd = bcmd;
13440 INT_ON;
13441 success:
13442 cmdp->rehash = 0;
13443 entry->cmdtype = cmdp->cmdtype;
13444 entry->u = cmdp->param;
13445}
13446
13447
Eric Andersencb57d552001-06-28 07:25:16 +000013448/*
Eric Andersencb57d552001-06-28 07:25:16 +000013449 * The trap builtin.
13450 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013451static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013452trapcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +000013453{
13454 char *action;
13455 char **ap;
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010013456 int signo, exitcode;
Eric Andersencb57d552001-06-28 07:25:16 +000013457
Eric Andersenc470f442003-07-28 09:56:35 +000013458 nextopt(nullstr);
13459 ap = argptr;
13460 if (!*ap) {
Denis Vlasenko2da584f2007-02-19 22:44:05 +000013461 for (signo = 0; signo < NSIG; signo++) {
Denys Vlasenko21d87d42009-09-25 00:06:51 +020013462 char *tr = trap_ptr[signo];
13463 if (tr) {
Denys Vlasenkoe74aaf92009-09-27 02:05:45 +020013464 /* note: bash adds "SIG", but only if invoked
13465 * as "bash". If called as "sh", or if set -o posix,
13466 * then it prints short signal names.
13467 * We are printing short names: */
13468 out1fmt("trap -- %s %s\n",
Denys Vlasenko21d87d42009-09-25 00:06:51 +020013469 single_quote(tr),
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +000013470 get_signame(signo));
Denys Vlasenko726e1a02009-09-25 02:58:20 +020013471 /* trap_ptr != trap only if we are in special-cased `trap` code.
13472 * In this case, we will exit very soon, no need to free(). */
Denys Vlasenkoe74aaf92009-09-27 02:05:45 +020013473 /* if (trap_ptr != trap && tp[0]) */
Denys Vlasenko726e1a02009-09-25 02:58:20 +020013474 /* free(tr); */
Eric Andersencb57d552001-06-28 07:25:16 +000013475 }
13476 }
Denys Vlasenko726e1a02009-09-25 02:58:20 +020013477 /*
Denys Vlasenko21d87d42009-09-25 00:06:51 +020013478 if (trap_ptr != trap) {
13479 free(trap_ptr);
13480 trap_ptr = trap;
13481 }
Denys Vlasenko726e1a02009-09-25 02:58:20 +020013482 */
Eric Andersencb57d552001-06-28 07:25:16 +000013483 return 0;
13484 }
Denys Vlasenko21d87d42009-09-25 00:06:51 +020013485
Denys Vlasenko86981e32017-07-25 20:06:17 +020013486 /* Why the second check?
13487 * "trap NUM [sig2]..." is the same as "trap - NUM [sig2]..."
13488 * In this case, NUM is signal no, not an action.
13489 */
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +000013490 action = NULL;
Denys Vlasenko86981e32017-07-25 20:06:17 +020013491 if (ap[1] && !is_number(ap[0]))
Eric Andersencb57d552001-06-28 07:25:16 +000013492 action = *ap++;
Denys Vlasenko86981e32017-07-25 20:06:17 +020013493
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010013494 exitcode = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000013495 while (*ap) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000013496 signo = get_signum(*ap);
Denys Vlasenko86981e32017-07-25 20:06:17 +020013497 if (signo < 0) {
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010013498 /* Mimic bash message exactly */
13499 ash_msg("%s: invalid signal specification", *ap);
13500 exitcode = 1;
13501 goto next;
13502 }
Denis Vlasenkob012b102007-02-19 22:43:01 +000013503 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +000013504 if (action) {
Denis Vlasenko9f739442006-12-16 23:49:13 +000013505 if (LONE_DASH(action))
Eric Andersencb57d552001-06-28 07:25:16 +000013506 action = NULL;
Denys Vlasenkob4f51d32016-10-27 12:55:09 +020013507 else {
13508 if (action[0]) /* not NULL and not "" and not "-" */
13509 may_have_traps = 1;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013510 action = ckstrdup(action);
Denys Vlasenkob4f51d32016-10-27 12:55:09 +020013511 }
Eric Andersencb57d552001-06-28 07:25:16 +000013512 }
Denis Vlasenko60818682007-09-28 22:07:23 +000013513 free(trap[signo]);
Eric Andersencb57d552001-06-28 07:25:16 +000013514 trap[signo] = action;
13515 if (signo != 0)
13516 setsignal(signo);
Denis Vlasenkob012b102007-02-19 22:43:01 +000013517 INT_ON;
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010013518 next:
Eric Andersencb57d552001-06-28 07:25:16 +000013519 ap++;
13520 }
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010013521 return exitcode;
Eric Andersencb57d552001-06-28 07:25:16 +000013522}
13523
Eric Andersenc470f442003-07-28 09:56:35 +000013524
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013525/* ============ Builtins */
Eric Andersenc470f442003-07-28 09:56:35 +000013526
Denys Vlasenko2ec34962014-09-08 16:52:39 +020013527#if ENABLE_ASH_HELP
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013528static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013529helpcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000013530{
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000013531 unsigned col;
13532 unsigned i;
Eric Andersenc470f442003-07-28 09:56:35 +000013533
Denys Vlasenkod6b05eb2009-06-06 20:59:55 +020013534 out1fmt(
Denis Vlasenko34d4d892009-04-04 20:24:37 +000013535 "Built-in commands:\n"
13536 "------------------\n");
Denis Vlasenkob71c6682007-07-21 15:08:09 +000013537 for (col = 0, i = 0; i < ARRAY_SIZE(builtintab); i++) {
Eric Andersenc470f442003-07-28 09:56:35 +000013538 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
Denis Vlasenko52764022007-02-24 13:42:56 +000013539 builtintab[i].name + 1);
Eric Andersenc470f442003-07-28 09:56:35 +000013540 if (col > 60) {
13541 out1fmt("\n");
13542 col = 0;
13543 }
13544 }
Denys Vlasenko2ec34962014-09-08 16:52:39 +020013545# if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko1aa7e472007-11-28 06:49:03 +000013546 {
13547 const char *a = applet_names;
13548 while (*a) {
13549 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), a);
13550 if (col > 60) {
13551 out1fmt("\n");
13552 col = 0;
13553 }
Ron Yorston2b919582016-04-08 11:57:20 +010013554 while (*a++ != '\0')
13555 continue;
Eric Andersenc470f442003-07-28 09:56:35 +000013556 }
13557 }
Denys Vlasenko2ec34962014-09-08 16:52:39 +020013558# endif
Denys Vlasenkoebedb942016-10-02 18:45:09 +020013559 newline_and_flush(stdout);
Eric Andersenc470f442003-07-28 09:56:35 +000013560 return EXIT_SUCCESS;
13561}
Denys Vlasenko2ec34962014-09-08 16:52:39 +020013562#endif
Eric Andersenc470f442003-07-28 09:56:35 +000013563
Flemming Madsend96ffda2013-04-07 18:47:24 +020013564#if MAX_HISTORY
13565static int FAST_FUNC
13566historycmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
13567{
13568 show_history(line_input_state);
13569 return EXIT_SUCCESS;
13570}
13571#endif
13572
Eric Andersencb57d552001-06-28 07:25:16 +000013573/*
Eric Andersencb57d552001-06-28 07:25:16 +000013574 * The export and readonly commands.
13575 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013576static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013577exportcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000013578{
13579 struct var *vp;
13580 char *name;
13581 const char *p;
Eric Andersenc470f442003-07-28 09:56:35 +000013582 char **aptr;
Denys Vlasenkod5275882012-10-01 13:41:17 +020013583 char opt;
13584 int flag;
13585 int flag_off;
Eric Andersencb57d552001-06-28 07:25:16 +000013586
Denys Vlasenkod5275882012-10-01 13:41:17 +020013587 /* "readonly" in bash accepts, but ignores -n.
13588 * We do the same: it saves a conditional in nextopt's param.
13589 */
13590 flag_off = 0;
13591 while ((opt = nextopt("np")) != '\0') {
13592 if (opt == 'n')
13593 flag_off = VEXPORT;
13594 }
13595 flag = VEXPORT;
13596 if (argv[0][0] == 'r') {
13597 flag = VREADONLY;
13598 flag_off = 0; /* readonly ignores -n */
13599 }
13600 flag_off = ~flag_off;
13601
Denys Vlasenko10ad6222017-04-17 16:13:32 +020013602 /*if (opt_p_not_specified) - bash doesn't check this. Try "export -p NAME" */
Denys Vlasenkod5275882012-10-01 13:41:17 +020013603 {
Denis Vlasenko2da584f2007-02-19 22:44:05 +000013604 aptr = argptr;
13605 name = *aptr;
13606 if (name) {
13607 do {
13608 p = strchr(name, '=');
13609 if (p != NULL) {
13610 p++;
13611 } else {
13612 vp = *findvar(hashvar(name), name);
13613 if (vp) {
Denys Vlasenkod5275882012-10-01 13:41:17 +020013614 vp->flags = ((vp->flags | flag) & flag_off);
Denis Vlasenko2da584f2007-02-19 22:44:05 +000013615 continue;
13616 }
Eric Andersencb57d552001-06-28 07:25:16 +000013617 }
Denys Vlasenkod5275882012-10-01 13:41:17 +020013618 setvar(name, p, (flag & flag_off));
Denis Vlasenko2da584f2007-02-19 22:44:05 +000013619 } while ((name = *++aptr) != NULL);
13620 return 0;
13621 }
Eric Andersencb57d552001-06-28 07:25:16 +000013622 }
Denys Vlasenkod5275882012-10-01 13:41:17 +020013623
13624 /* No arguments. Show the list of exported or readonly vars.
13625 * -n is ignored.
13626 */
Denis Vlasenko2da584f2007-02-19 22:44:05 +000013627 showvars(argv[0], flag, 0);
Eric Andersencb57d552001-06-28 07:25:16 +000013628 return 0;
13629}
13630
Eric Andersencb57d552001-06-28 07:25:16 +000013631/*
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000013632 * Delete a function if it exists.
Eric Andersencb57d552001-06-28 07:25:16 +000013633 */
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +000013634static void
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000013635unsetfunc(const char *name)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000013636{
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000013637 struct tblentry *cmdp;
Eric Andersencb57d552001-06-28 07:25:16 +000013638
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000013639 cmdp = cmdlookup(name, 0);
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020013640 if (cmdp != NULL && cmdp->cmdtype == CMDFUNCTION)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000013641 delete_cmd_entry();
Eric Andersenc470f442003-07-28 09:56:35 +000013642}
13643
Eric Andersencb57d552001-06-28 07:25:16 +000013644/*
Eric Andersencb57d552001-06-28 07:25:16 +000013645 * The unset builtin command. We unset the function before we unset the
13646 * variable to allow a function to be unset when there is a readonly variable
13647 * with the same name.
13648 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013649static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013650unsetcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +000013651{
13652 char **ap;
13653 int i;
Eric Andersenc470f442003-07-28 09:56:35 +000013654 int flag = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000013655
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020013656 while ((i = nextopt("vf")) != 0) {
Eric Andersenc470f442003-07-28 09:56:35 +000013657 flag = i;
Eric Andersencb57d552001-06-28 07:25:16 +000013658 }
Eric Andersencb57d552001-06-28 07:25:16 +000013659
Denis Vlasenko2da584f2007-02-19 22:44:05 +000013660 for (ap = argptr; *ap; ap++) {
Eric Andersenc470f442003-07-28 09:56:35 +000013661 if (flag != 'f') {
Denys Vlasenkob28d4c32017-07-25 16:29:36 +020013662 unsetvar(*ap);
13663 continue;
Eric Andersenc470f442003-07-28 09:56:35 +000013664 }
13665 if (flag != 'v')
Eric Andersencb57d552001-06-28 07:25:16 +000013666 unsetfunc(*ap);
Eric Andersencb57d552001-06-28 07:25:16 +000013667 }
Denys Vlasenkob28d4c32017-07-25 16:29:36 +020013668 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +000013669}
13670
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000013671static const unsigned char timescmd_str[] ALIGN1 = {
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013672 ' ', offsetof(struct tms, tms_utime),
13673 '\n', offsetof(struct tms, tms_stime),
13674 ' ', offsetof(struct tms, tms_cutime),
13675 '\n', offsetof(struct tms, tms_cstime),
13676 0
13677};
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013678static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013679timescmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013680{
Denys Vlasenko11f2e992017-08-10 16:34:03 +020013681 unsigned clk_tck;
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013682 const unsigned char *p;
13683 struct tms buf;
13684
Bartosz Golaszewski5d2e4092014-06-22 14:01:13 +020013685 clk_tck = bb_clk_tck();
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013686
Denys Vlasenko11f2e992017-08-10 16:34:03 +020013687 times(&buf);
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013688 p = timescmd_str;
13689 do {
Denys Vlasenko11f2e992017-08-10 16:34:03 +020013690 unsigned sec, frac;
13691 unsigned long t;
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013692 t = *(clock_t *)(((char *) &buf) + p[1]);
Denys Vlasenko11f2e992017-08-10 16:34:03 +020013693 sec = t / clk_tck;
13694 frac = t % clk_tck;
13695 out1fmt("%um%u.%03us%c",
13696 sec / 60, sec % 60,
13697 (frac * 1000) / clk_tck,
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013698 p[0]);
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020013699 p += 2;
13700 } while (*p);
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013701
Eric Andersencb57d552001-06-28 07:25:16 +000013702 return 0;
13703}
13704
Denys Vlasenko0b883582016-12-23 16:49:07 +010013705#if ENABLE_FEATURE_SH_MATH
Eric Andersenc470f442003-07-28 09:56:35 +000013706/*
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020013707 * The let builtin. Partially stolen from GNU Bash, the Bourne Again SHell.
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +000013708 * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
Eric Andersen90898442003-08-06 11:20:52 +000013709 *
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +000013710 * Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
Eric Andersenc470f442003-07-28 09:56:35 +000013711 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013712static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013713letcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersenc470f442003-07-28 09:56:35 +000013714{
Denis Vlasenko68404f12008-03-17 09:00:54 +000013715 arith_t i;
Eric Andersenc470f442003-07-28 09:56:35 +000013716
Denis Vlasenko68404f12008-03-17 09:00:54 +000013717 argv++;
13718 if (!*argv)
Denis Vlasenkob012b102007-02-19 22:43:01 +000013719 ash_msg_and_raise_error("expression expected");
Denis Vlasenko68404f12008-03-17 09:00:54 +000013720 do {
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +000013721 i = ash_arith(*argv);
Denis Vlasenko68404f12008-03-17 09:00:54 +000013722 } while (*++argv);
Eric Andersenc470f442003-07-28 09:56:35 +000013723
Denis Vlasenkod9e15f22006-11-27 16:49:55 +000013724 return !i;
Eric Andersenc470f442003-07-28 09:56:35 +000013725}
Eric Andersenc470f442003-07-28 09:56:35 +000013726#endif
Eric Andersen74bcd162001-07-30 21:41:37 +000013727
Eric Andersenc470f442003-07-28 09:56:35 +000013728/*
Denis Vlasenko59f351c2008-03-25 00:07:12 +000013729 * The read builtin. Options:
13730 * -r Do not interpret '\' specially
13731 * -s Turn off echo (tty only)
13732 * -n NCHARS Read NCHARS max
13733 * -p PROMPT Display PROMPT on stderr (if input is from tty)
13734 * -t SECONDS Timeout after SECONDS (tty or pipe only)
13735 * -u FD Read from given FD instead of fd 0
Johannes Schindelin3bef5d82017-08-08 16:46:39 +020013736 * -d DELIM End on DELIM char, not newline
Eric Andersenc470f442003-07-28 09:56:35 +000013737 * This uses unbuffered input, which may be avoidable in some cases.
Denis Vlasenko59f351c2008-03-25 00:07:12 +000013738 * TODO: bash also has:
13739 * -a ARRAY Read into array[0],[1],etc
Denis Vlasenko59f351c2008-03-25 00:07:12 +000013740 * -e Use line editing (tty only)
Eric Andersenc470f442003-07-28 09:56:35 +000013741 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013742static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013743readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000013744{
Denys Vlasenko73067272010-01-12 22:11:24 +010013745 char *opt_n = NULL;
13746 char *opt_p = NULL;
13747 char *opt_t = NULL;
13748 char *opt_u = NULL;
Johannes Schindelin3bef5d82017-08-08 16:46:39 +020013749 char *opt_d = NULL; /* optimized out if !BASH */
Denys Vlasenko73067272010-01-12 22:11:24 +010013750 int read_flags = 0;
13751 const char *r;
Eric Andersenc470f442003-07-28 09:56:35 +000013752 int i;
13753
Johannes Schindelin3bef5d82017-08-08 16:46:39 +020013754 while ((i = nextopt("p:u:rt:n:sd:")) != '\0') {
Denis Vlasenkobf0a2012006-12-26 10:42:51 +000013755 switch (i) {
Paul Fox02eb9342005-09-07 16:56:02 +000013756 case 'p':
Denys Vlasenko73067272010-01-12 22:11:24 +010013757 opt_p = optionarg;
Paul Fox02eb9342005-09-07 16:56:02 +000013758 break;
Paul Fox02eb9342005-09-07 16:56:02 +000013759 case 'n':
Denys Vlasenko73067272010-01-12 22:11:24 +010013760 opt_n = optionarg;
Paul Fox02eb9342005-09-07 16:56:02 +000013761 break;
13762 case 's':
Denys Vlasenko73067272010-01-12 22:11:24 +010013763 read_flags |= BUILTIN_READ_SILENT;
Paul Fox02eb9342005-09-07 16:56:02 +000013764 break;
Paul Fox02eb9342005-09-07 16:56:02 +000013765 case 't':
Denys Vlasenko73067272010-01-12 22:11:24 +010013766 opt_t = optionarg;
Paul Fox02eb9342005-09-07 16:56:02 +000013767 break;
Paul Fox02eb9342005-09-07 16:56:02 +000013768 case 'r':
Denys Vlasenko73067272010-01-12 22:11:24 +010013769 read_flags |= BUILTIN_READ_RAW;
Paul Fox02eb9342005-09-07 16:56:02 +000013770 break;
Denis Vlasenko59f351c2008-03-25 00:07:12 +000013771 case 'u':
Denys Vlasenko73067272010-01-12 22:11:24 +010013772 opt_u = optionarg;
Denis Vlasenko59f351c2008-03-25 00:07:12 +000013773 break;
Johannes Schindelin3bef5d82017-08-08 16:46:39 +020013774#if BASH_READ_D
13775 case 'd':
13776 opt_d = optionarg;
13777 break;
13778#endif
Paul Fox02eb9342005-09-07 16:56:02 +000013779 default:
13780 break;
13781 }
Eric Andersenc470f442003-07-28 09:56:35 +000013782 }
Paul Fox02eb9342005-09-07 16:56:02 +000013783
Denys Vlasenko9e71e3c2012-09-06 13:28:10 +020013784 /* "read -s" needs to save/restore termios, can't allow ^C
13785 * to jump out of it.
13786 */
Denys Vlasenkof5470412017-05-22 19:34:45 +020013787 again:
Denys Vlasenko9e71e3c2012-09-06 13:28:10 +020013788 INT_OFF;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020013789 r = shell_builtin_read(setvar0,
Denys Vlasenko73067272010-01-12 22:11:24 +010013790 argptr,
13791 bltinlookup("IFS"), /* can be NULL */
13792 read_flags,
13793 opt_n,
13794 opt_p,
13795 opt_t,
Johannes Schindelin3bef5d82017-08-08 16:46:39 +020013796 opt_u,
13797 opt_d
Denys Vlasenko73067272010-01-12 22:11:24 +010013798 );
Denys Vlasenko9e71e3c2012-09-06 13:28:10 +020013799 INT_ON;
Denis Vlasenko46aeab92009-03-31 19:18:17 +000013800
Denys Vlasenkof5470412017-05-22 19:34:45 +020013801 if ((uintptr_t)r == 1 && errno == EINTR) {
Denys Vlasenko49e6bf22017-08-04 14:28:16 +020013802 /* To get SIGCHLD: sleep 1 & read x; echo $x
13803 * Correct behavior is to not exit "read"
13804 */
Denys Vlasenkof5470412017-05-22 19:34:45 +020013805 if (pending_sig == 0)
13806 goto again;
13807 }
13808
Denys Vlasenko73067272010-01-12 22:11:24 +010013809 if ((uintptr_t)r > 1)
13810 ash_msg_and_raise_error(r);
Denis Vlasenko037576d2007-10-20 18:30:38 +000013811
Denys Vlasenko73067272010-01-12 22:11:24 +010013812 return (uintptr_t)r;
Eric Andersenc470f442003-07-28 09:56:35 +000013813}
13814
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013815static int FAST_FUNC
Denys Vlasenko6283f982015-10-07 16:56:20 +020013816umaskcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000013817{
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013818 static const char permuser[3] ALIGN1 = "ogu";
Eric Andersenc470f442003-07-28 09:56:35 +000013819
Eric Andersenc470f442003-07-28 09:56:35 +000013820 mode_t mask;
Eric Andersenc470f442003-07-28 09:56:35 +000013821 int symbolic_mode = 0;
13822
13823 while (nextopt("S") != '\0') {
13824 symbolic_mode = 1;
13825 }
13826
Denis Vlasenkob012b102007-02-19 22:43:01 +000013827 INT_OFF;
Eric Andersenc470f442003-07-28 09:56:35 +000013828 mask = umask(0);
13829 umask(mask);
Denis Vlasenkob012b102007-02-19 22:43:01 +000013830 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +000013831
Denys Vlasenko6283f982015-10-07 16:56:20 +020013832 if (*argptr == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +000013833 if (symbolic_mode) {
Denys Vlasenko005c4922015-10-10 20:17:12 +020013834 char buf[sizeof(",u=rwx,g=rwx,o=rwx")];
Eric Andersenc470f442003-07-28 09:56:35 +000013835 char *p = buf;
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013836 int i;
Eric Andersenc470f442003-07-28 09:56:35 +000013837
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013838 i = 2;
13839 for (;;) {
Denys Vlasenko005c4922015-10-10 20:17:12 +020013840 *p++ = ',';
Eric Andersenc470f442003-07-28 09:56:35 +000013841 *p++ = permuser[i];
13842 *p++ = '=';
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013843 /* mask is 0..0uuugggooo. i=2 selects uuu bits */
Denys Vlasenko005c4922015-10-10 20:17:12 +020013844 if (!(mask & 0400)) *p++ = 'r';
13845 if (!(mask & 0200)) *p++ = 'w';
13846 if (!(mask & 0100)) *p++ = 'x';
13847 mask <<= 3;
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013848 if (--i < 0)
13849 break;
Eric Andersenc470f442003-07-28 09:56:35 +000013850 }
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013851 *p = '\0';
Denys Vlasenko005c4922015-10-10 20:17:12 +020013852 puts(buf + 1);
Eric Andersenc470f442003-07-28 09:56:35 +000013853 } else {
Denys Vlasenkoec046f72015-10-07 17:57:53 +020013854 out1fmt("%04o\n", mask);
Eric Andersenc470f442003-07-28 09:56:35 +000013855 }
13856 } else {
Denys Vlasenko6283f982015-10-07 16:56:20 +020013857 char *modestr = *argptr;
Denys Vlasenko14c85eb2017-10-12 19:40:47 +020013858 /* numeric umasks are taken as-is */
13859 /* symbolic umasks are inverted: "umask a=rx" calls umask(222) */
Denys Vlasenko6283f982015-10-07 16:56:20 +020013860 if (!isdigit(modestr[0]))
13861 mask ^= 0777;
Denys Vlasenko5711a2a2015-10-07 17:55:33 +020013862 mask = bb_parse_mode(modestr, mask);
13863 if ((unsigned)mask > 0777) {
Denys Vlasenko6283f982015-10-07 16:56:20 +020013864 ash_msg_and_raise_error("illegal mode: %s", modestr);
Eric Andersenc470f442003-07-28 09:56:35 +000013865 }
Denys Vlasenko6283f982015-10-07 16:56:20 +020013866 if (!isdigit(modestr[0]))
13867 mask ^= 0777;
13868 umask(mask);
Eric Andersenc470f442003-07-28 09:56:35 +000013869 }
13870 return 0;
13871}
13872
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013873static int FAST_FUNC
Denys Vlasenkof3c742f2010-03-06 20:12:00 +010013874ulimitcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersenc470f442003-07-28 09:56:35 +000013875{
Denys Vlasenkof3c742f2010-03-06 20:12:00 +010013876 return shell_builtin_ulimit(argv);
Eric Andersenc470f442003-07-28 09:56:35 +000013877}
13878
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013879/* ============ main() and helpers */
13880
13881/*
13882 * Called to exit the shell.
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013883 */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013884static void
13885exitshell(void)
13886{
13887 struct jmploc loc;
13888 char *p;
13889 int status;
13890
Denys Vlasenkobede2152011-09-04 16:12:33 +020013891#if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT
13892 save_history(line_input_state);
13893#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013894 status = exitstatus;
13895 TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
13896 if (setjmp(loc.loc)) {
Denis Vlasenko7f88e342009-03-19 03:36:18 +000013897 if (exception_type == EXEXIT)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013898 status = exitstatus;
13899 goto out;
13900 }
13901 exception_handler = &loc;
13902 p = trap[0];
13903 if (p) {
13904 trap[0] = NULL;
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020013905 evalskip = 0;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013906 evalstring(p, 0);
Denys Vlasenkof37e1152016-10-07 03:17:28 +020013907 /*free(p); - we'll exit soon */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013908 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013909 out:
Denys Vlasenkof37e1152016-10-07 03:17:28 +020013910 /* dash wraps setjobctl(0) in "if (setjmp(loc.loc) == 0) {...}".
13911 * our setjobctl(0) does not panic if tcsetpgrp fails inside it.
13912 */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013913 setjobctl(0);
Denys Vlasenkocaee80c2016-10-25 20:49:53 +020013914 flush_stdout_stderr();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013915 _exit(status);
13916 /* NOTREACHED */
13917}
13918
Denys Vlasenko49e6bf22017-08-04 14:28:16 +020013919/* Don't inline: conserve stack of caller from having our locals too */
13920static NOINLINE void
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +000013921init(void)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013922{
Denys Vlasenko82dd14a2010-05-17 10:10:01 +020013923 /* we will never free this */
13924 basepf.next_to_pgetc = basepf.buf = ckmalloc(IBUFSIZ);
Denys Vlasenko0485b672017-08-14 19:46:56 +020013925 basepf.linno = 1;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013926
Denys Vlasenko49e6bf22017-08-04 14:28:16 +020013927 sigmode[SIGCHLD - 1] = S_DFL; /* ensure we install handler even if it is SIG_IGNed */
Denys Vlasenko458c1f22016-10-27 23:51:19 +020013928 setsignal(SIGCHLD);
13929
Denys Vlasenko7a7b0342009-12-04 04:18:31 +010013930 /* bash re-enables SIGHUP which is SIG_IGNed on entry.
13931 * Try: "trap '' HUP; bash; echo RET" and type "kill -HUP $$"
13932 */
Denys Vlasenkocacb2cd2010-10-05 00:13:02 +020013933 signal(SIGHUP, SIG_DFL);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013934
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013935 {
13936 char **envp;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013937 const char *p;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013938
13939 initvar();
13940 for (envp = environ; envp && *envp; envp++) {
Denys Vlasenko9c143ce2017-11-02 12:56:24 +010013941/* Used to have
13942 * p = endofname(*envp);
13943 * if (p != *envp && *p == '=') {
13944 * here to weed out badly-named variables, but this breaks
13945 * scenarios where people do want them passed to children:
13946 * import os
13947 * os.environ["test-test"]="test"
13948 * if os.fork() == 0:
13949 * os.execv("ash", [ 'ash', '-c', 'eval $(export -p); echo OK' ]) # fixes this
13950 * os.execv("ash", [ 'ash', '-c', 'env | grep test-test' ]) # breaks this
13951 */
13952 if (strchr(*envp, '=')) {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013953 setvareq(*envp, VEXPORT|VTEXTFIXED);
13954 }
13955 }
13956
Denys Vlasenkoe627ac92016-09-30 14:36:59 +020013957 setvareq((char*)defoptindvar, VTEXTFIXED);
13958
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020013959 setvar0("PPID", utoa(getppid()));
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010013960#if BASH_SHLVL_VAR
Bernhard Reutner-Fischer80f8cdf2013-11-08 14:25:24 +010013961 p = lookupvar("SHLVL");
Denys Vlasenko5680e982014-01-07 16:12:48 +010013962 setvar("SHLVL", utoa((p ? atoi(p) : 0) + 1), VEXPORT);
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010013963#endif
13964#if BASH_HOSTNAME_VAR
Denys Vlasenko3fa97af2014-04-15 11:43:29 +020013965 if (!lookupvar("HOSTNAME")) {
13966 struct utsname uts;
13967 uname(&uts);
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020013968 setvar0("HOSTNAME", uts.nodename);
Denys Vlasenko3fa97af2014-04-15 11:43:29 +020013969 }
Bernhard Reutner-Fischer80f8cdf2013-11-08 14:25:24 +010013970#endif
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013971 p = lookupvar("PWD");
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013972 if (p) {
Denys Vlasenko49e6bf22017-08-04 14:28:16 +020013973 struct stat st1, st2;
Denys Vlasenkoef159702016-09-01 11:16:22 +020013974 if (p[0] != '/' || stat(p, &st1) || stat(".", &st2)
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013975 || st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino
13976 ) {
Denys Vlasenkoef159702016-09-01 11:16:22 +020013977 p = NULL;
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013978 }
13979 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013980 setpwd(p, 0);
13981 }
13982}
13983
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013984
13985//usage:#define ash_trivial_usage
Denys Vlasenkof2ed39b2018-04-05 16:46:49 +020013986//usage: "[-/+OPTIONS] [-/+o OPT]... [-c 'SCRIPT' [ARG0 [ARGS]] / FILE [ARGS] / -s [ARGS]]"
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013987//usage:#define ash_full_usage "\n\n"
13988//usage: "Unix shell interpreter"
13989
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013990/*
13991 * Process the shell command line arguments.
13992 */
Denys Vlasenkoec05df12017-07-31 19:43:47 +020013993static int
Denis Vlasenko68404f12008-03-17 09:00:54 +000013994procargs(char **argv)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013995{
13996 int i;
13997 const char *xminusc;
13998 char **xargv;
Denys Vlasenkoec05df12017-07-31 19:43:47 +020013999 int login_sh;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014000
14001 xargv = argv;
Denys Vlasenkoec05df12017-07-31 19:43:47 +020014002 login_sh = xargv[0] && xargv[0][0] == '-';
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014003 arg0 = xargv[0];
Denis Vlasenko68404f12008-03-17 09:00:54 +000014004 /* if (xargv[0]) - mmm, this is always true! */
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014005 xargv++;
14006 for (i = 0; i < NOPTS; i++)
14007 optlist[i] = 2;
14008 argptr = xargv;
Denys Vlasenkoec05df12017-07-31 19:43:47 +020014009 if (options(/*cmdline:*/ 1, &login_sh)) {
Denis Vlasenko28bf6712008-02-14 15:01:47 +000014010 /* it already printed err message */
14011 raise_exception(EXERROR);
14012 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014013 xargv = argptr;
14014 xminusc = minusc;
14015 if (*xargv == NULL) {
14016 if (xminusc)
14017 ash_msg_and_raise_error(bb_msg_requires_arg, "-c");
14018 sflag = 1;
14019 }
14020 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
14021 iflag = 1;
14022 if (mflag == 2)
14023 mflag = iflag;
14024 for (i = 0; i < NOPTS; i++)
14025 if (optlist[i] == 2)
14026 optlist[i] = 0;
14027#if DEBUG == 2
14028 debug = 1;
14029#endif
Denys Vlasenko5f7c82b2017-02-03 13:00:06 +010014030 /* POSIX 1003.2: first arg after "-c CMD" is $0, remainder $1... */
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014031 if (xminusc) {
14032 minusc = *xargv++;
14033 if (*xargv)
14034 goto setarg0;
14035 } else if (!sflag) {
14036 setinputfile(*xargv, 0);
14037 setarg0:
14038 arg0 = *xargv++;
14039 commandname = arg0;
14040 }
14041
14042 shellparam.p = xargv;
14043#if ENABLE_ASH_GETOPTS
14044 shellparam.optind = 1;
14045 shellparam.optoff = -1;
14046#endif
Denis Vlasenko01631112007-12-16 17:20:38 +000014047 /* assert(shellparam.malloced == 0 && shellparam.nparam == 0); */
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014048 while (*xargv) {
14049 shellparam.nparam++;
14050 xargv++;
14051 }
14052 optschanged();
Denys Vlasenkoec05df12017-07-31 19:43:47 +020014053
14054 return login_sh;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014055}
14056
14057/*
Denys Vlasenko2eb0a7e2016-10-27 11:28:59 +020014058 * Read /etc/profile, ~/.profile, $ENV.
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014059 */
14060static void
14061read_profile(const char *name)
14062{
Denys Vlasenko46999802017-07-29 21:12:29 +020014063 name = expandstr(name, DQSYNTAX);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014064 if (setinputfile(name, INPUT_PUSH_FILE | INPUT_NOFILE_OK) < 0)
14065 return;
Denys Vlasenko0840c912016-10-01 15:27:44 +020014066 cmdloop(0);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014067 popfile();
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014068}
14069
Denis Vlasenko0c032a42007-02-23 01:03:40 +000014070/*
14071 * This routine is called when an error or an interrupt occurs in an
14072 * interactive shell and control is returned to the main command loop.
Denys Vlasenko5ac04f22016-10-27 14:46:50 +020014073 * (In dash, this function is auto-generated by build machinery).
Denis Vlasenko0c032a42007-02-23 01:03:40 +000014074 */
14075static void
14076reset(void)
14077{
14078 /* from eval.c: */
14079 evalskip = 0;
14080 loopnest = 0;
Denys Vlasenko5ac04f22016-10-27 14:46:50 +020014081
14082 /* from expand.c: */
14083 ifsfree();
14084
Denis Vlasenko0c032a42007-02-23 01:03:40 +000014085 /* from input.c: */
Denis Vlasenko41eb3002008-11-28 03:42:31 +000014086 g_parsefile->left_in_buffer = 0;
14087 g_parsefile->left_in_line = 0; /* clear input buffer */
Denis Vlasenko0c032a42007-02-23 01:03:40 +000014088 popallfiles();
Denys Vlasenko5ac04f22016-10-27 14:46:50 +020014089
Denis Vlasenko0c032a42007-02-23 01:03:40 +000014090 /* from redir.c: */
Denys Vlasenko1c79aeb2017-07-29 22:51:52 +020014091 unwindredir(NULL);
Denys Vlasenkob8ab27b2017-07-26 19:22:34 +020014092
14093 /* from var.c: */
Denys Vlasenko484fc202017-07-26 19:55:31 +020014094 unwindlocalvars(NULL);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000014095}
14096
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014097#if PROFILE
14098static short profile_buf[16384];
14099extern int etext();
14100#endif
14101
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000014102/*
14103 * Main routine. We initialize things, parse the arguments, execute
14104 * profiles if we're a login shell, and then call cmdloop to execute
14105 * commands. The setjmp call sets up the location to jump to when an
14106 * exception occurs. When an exception occurs the variable "state"
14107 * is used to figure out how far we had gotten.
14108 */
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +000014109int ash_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000014110int ash_main(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014111{
Denis Vlasenko4e12b1a2008-12-23 23:36:47 +000014112 volatile smallint state;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014113 struct jmploc jmploc;
14114 struct stackmark smark;
Denys Vlasenkoec05df12017-07-31 19:43:47 +020014115 int login_sh;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014116
Denis Vlasenko01631112007-12-16 17:20:38 +000014117 /* Initialize global data */
14118 INIT_G_misc();
14119 INIT_G_memstack();
14120 INIT_G_var();
Denis Vlasenkoee87ebf2007-12-21 22:18:16 +000014121#if ENABLE_ASH_ALIAS
Denis Vlasenko01631112007-12-16 17:20:38 +000014122 INIT_G_alias();
Denis Vlasenkoee87ebf2007-12-21 22:18:16 +000014123#endif
Denis Vlasenko01631112007-12-16 17:20:38 +000014124 INIT_G_cmdtable();
14125
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014126#if PROFILE
14127 monitor(4, etext, profile_buf, sizeof(profile_buf), 50);
14128#endif
14129
14130#if ENABLE_FEATURE_EDITING
14131 line_input_state = new_line_input_t(FOR_SHELL | WITH_PATH_LOOKUP);
14132#endif
14133 state = 0;
14134 if (setjmp(jmploc.loc)) {
Denis Vlasenko7f88e342009-03-19 03:36:18 +000014135 smallint e;
Denis Vlasenko4e12b1a2008-12-23 23:36:47 +000014136 smallint s;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014137
14138 reset();
14139
Denis Vlasenko7f88e342009-03-19 03:36:18 +000014140 e = exception_type;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014141 s = state;
Denys Vlasenkob563f622010-09-25 17:15:13 +020014142 if (e == EXEXIT || s == 0 || iflag == 0 || shlvl) {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014143 exitshell();
Denys Vlasenkob563f622010-09-25 17:15:13 +020014144 }
14145 if (e == EXINT) {
Denys Vlasenko9c541002015-10-07 15:44:36 +020014146 newline_and_flush(stderr);
Denys Vlasenkob563f622010-09-25 17:15:13 +020014147 }
Denis Vlasenko7f88e342009-03-19 03:36:18 +000014148
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014149 popstackmark(&smark);
14150 FORCE_INT_ON; /* enable interrupts */
14151 if (s == 1)
14152 goto state1;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000014153 if (s == 2)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014154 goto state2;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000014155 if (s == 3)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014156 goto state3;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000014157 goto state4;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014158 }
14159 exception_handler = &jmploc;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014160 rootpid = getpid();
14161
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014162 init();
14163 setstackmark(&smark);
Denys Vlasenkoec05df12017-07-31 19:43:47 +020014164 login_sh = procargs(argv);
Denys Vlasenko474ed062016-10-30 18:30:29 +010014165#if DEBUG
14166 TRACE(("Shell args: "));
14167 trace_puts_args(argv);
14168#endif
Denis Vlasenko68404f12008-03-17 09:00:54 +000014169
Denys Vlasenkoec05df12017-07-31 19:43:47 +020014170 if (login_sh) {
Stefan Hellermann4ef14392013-03-15 02:45:50 +010014171 const char *hp;
14172
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014173 state = 1;
14174 read_profile("/etc/profile");
14175 state1:
14176 state = 2;
Stefan Hellermann4ef14392013-03-15 02:45:50 +010014177 hp = lookupvar("HOME");
Denys Vlasenko2eb0a7e2016-10-27 11:28:59 +020014178 if (hp)
14179 read_profile("$HOME/.profile");
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014180 }
14181 state2:
14182 state = 3;
14183 if (
14184#ifndef linux
Denis Vlasenko0c032a42007-02-23 01:03:40 +000014185 getuid() == geteuid() && getgid() == getegid() &&
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014186#endif
Denis Vlasenko0c032a42007-02-23 01:03:40 +000014187 iflag
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014188 ) {
Denys Vlasenko2eb0a7e2016-10-27 11:28:59 +020014189 const char *shinit = lookupvar("ENV");
14190 if (shinit != NULL && *shinit != '\0')
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014191 read_profile(shinit);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014192 }
Denys Vlasenko2eb0a7e2016-10-27 11:28:59 +020014193 popstackmark(&smark);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014194 state3:
14195 state = 4;
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000014196 if (minusc) {
14197 /* evalstring pushes parsefile stack.
14198 * Ensure we don't falsely claim that 0 (stdin)
Denis Vlasenko5368ad52009-03-20 10:20:08 +000014199 * is one of stacked source fds.
14200 * Testcase: ash -c 'exec 1>&0' must not complain. */
Denys Vlasenko79b3d422010-06-03 04:29:08 +020014201 // if (!sflag) g_parsefile->pf_fd = -1;
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +020014202 // ^^ not necessary since now we special-case fd 0
Denys Vlasenko035486c2017-07-31 04:09:19 +020014203 // in save_fd_on_redirect()
Denys Vlasenko1e3e2cc2017-07-25 20:31:14 +020014204 evalstring(minusc, sflag ? 0 : EV_EXIT);
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000014205 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014206
14207 if (sflag || minusc == NULL) {
Denys Vlasenko4840ae82011-09-04 15:28:03 +020014208#if MAX_HISTORY > 0 && ENABLE_FEATURE_EDITING_SAVEHISTORY
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +000014209 if (iflag) {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014210 const char *hp = lookupvar("HISTFILE");
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010014211 if (!hp) {
14212 hp = lookupvar("HOME");
Stefan Hellermann4ef14392013-03-15 02:45:50 +010014213 if (hp) {
Denys Vlasenko5f7c82b2017-02-03 13:00:06 +010014214 INT_OFF;
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010014215 hp = concat_path_file(hp, ".ash_history");
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020014216 setvar0("HISTFILE", hp);
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010014217 free((char*)hp);
Denys Vlasenko5f7c82b2017-02-03 13:00:06 +010014218 INT_ON;
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010014219 hp = lookupvar("HISTFILE");
14220 }
14221 }
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000014222 if (hp)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014223 line_input_state->hist_file = hp;
Denys Vlasenko2c4de5b2011-03-31 13:16:52 +020014224# if ENABLE_FEATURE_SH_HISTFILESIZE
14225 hp = lookupvar("HISTFILESIZE");
14226 line_input_state->max_history = size_from_HISTFILESIZE(hp);
14227# endif
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014228 }
14229#endif
14230 state4: /* XXX ??? - why isn't this before the "if" statement */
14231 cmdloop(1);
14232 }
14233#if PROFILE
14234 monitor(0);
14235#endif
14236#ifdef GPROF
14237 {
14238 extern void _mcleanup(void);
14239 _mcleanup();
14240 }
14241#endif
Denys Vlasenkob563f622010-09-25 17:15:13 +020014242 TRACE(("End of main reached\n"));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014243 exitshell();
14244 /* NOTREACHED */
14245}
14246
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014247
Eric Andersendf82f612001-06-28 07:46:40 +000014248/*-
14249 * Copyright (c) 1989, 1991, 1993, 1994
Eric Andersen2870d962001-07-02 17:27:21 +000014250 * The Regents of the University of California. All rights reserved.
Eric Andersendf82f612001-06-28 07:46:40 +000014251 *
14252 * This code is derived from software contributed to Berkeley by
14253 * Kenneth Almquist.
14254 *
14255 * Redistribution and use in source and binary forms, with or without
14256 * modification, are permitted provided that the following conditions
14257 * are met:
14258 * 1. Redistributions of source code must retain the above copyright
14259 * notice, this list of conditions and the following disclaimer.
14260 * 2. Redistributions in binary form must reproduce the above copyright
14261 * notice, this list of conditions and the following disclaimer in the
14262 * documentation and/or other materials provided with the distribution.
"Vladimir N. Oleynik"ddc280e2005-12-15 12:01:49 +000014263 * 3. Neither the name of the University nor the names of its contributors
Eric Andersendf82f612001-06-28 07:46:40 +000014264 * may be used to endorse or promote products derived from this software
14265 * without specific prior written permission.
14266 *
Denys Vlasenko95f79532017-08-02 14:26:33 +020014267 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND
Eric Andersendf82f612001-06-28 07:46:40 +000014268 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
14269 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
14270 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
14271 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
14272 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
14273 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
14274 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
14275 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
14276 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
14277 * SUCH DAMAGE.
14278 */