blob: 5586015439cf5d58030731d43c838702fba74c2a [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
180#include <setjmp.h>
181#include <fnmatch.h>
182#include <sys/times.h>
183#include <sys/utsname.h> /* for setting $HOSTNAME */
Denys Vlasenko67047462016-12-22 15:21:58 +0100184#include "busybox.h" /* for applet_names */
185
Denys Vlasenko7d4aec02017-01-11 14:00:38 +0100186/* So far, all bash compat is controlled by one config option */
187/* Separate defines document which part of code implements what */
188/* function keyword */
189#define BASH_FUNCTION ENABLE_ASH_BASH_COMPAT
190#define IF_BASH_FUNCTION IF_ASH_BASH_COMPAT
191/* &>file */
192#define BASH_REDIR_OUTPUT ENABLE_ASH_BASH_COMPAT
193#define IF_BASH_REDIR_OUTPUT IF_ASH_BASH_COMPAT
194/* $'...' */
195#define BASH_DOLLAR_SQUOTE ENABLE_ASH_BASH_COMPAT
196#define IF_BASH_DOLLAR_SQUOTE IF_ASH_BASH_COMPAT
197#define BASH_PATTERN_SUBST ENABLE_ASH_BASH_COMPAT
198#define IF_BASH_PATTERN_SUBST IF_ASH_BASH_COMPAT
199#define BASH_SUBSTR ENABLE_ASH_BASH_COMPAT
200#define IF_BASH_SUBSTR IF_ASH_BASH_COMPAT
201/* [[ EXPR ]] */
202#define BASH_TEST2 (ENABLE_ASH_BASH_COMPAT * ENABLE_ASH_TEST)
203#define BASH_SOURCE ENABLE_ASH_BASH_COMPAT
204#define BASH_PIPEFAIL ENABLE_ASH_BASH_COMPAT
205#define BASH_HOSTNAME_VAR ENABLE_ASH_BASH_COMPAT
206#define BASH_SHLVL_VAR ENABLE_ASH_BASH_COMPAT
Denys Vlasenkof8cdc7a2017-08-04 15:24:49 +0200207#define BASH_XTRACEFD ENABLE_ASH_BASH_COMPAT
Johannes Schindelin3bef5d82017-08-08 16:46:39 +0200208#define BASH_READ_D ENABLE_ASH_BASH_COMPAT
209#define IF_BASH_READ_D IF_ASH_BASH_COMPAT
Denys Vlasenko7d4aec02017-01-11 14:00:38 +0100210
Denys Vlasenko67047462016-12-22 15:21:58 +0100211#if defined(__ANDROID_API__) && __ANDROID_API__ <= 24
212/* Bionic at least up to version 24 has no glob() */
213# undef ENABLE_ASH_INTERNAL_GLOB
214# define ENABLE_ASH_INTERNAL_GLOB 1
215#endif
216
217#if !ENABLE_ASH_INTERNAL_GLOB && defined(__UCLIBC__)
218# error uClibc glob() is buggy, use ASH_INTERNAL_GLOB.
219# error The bug is: for "$PWD"/<pattern> ash will escape e.g. dashes in "$PWD"
220# error with backslash, even ones which do not need to be: "/a-b" -> "/a\-b"
221# error glob() should unbackslash them and match. uClibc does not unbackslash,
222# error fails to match dirname, subsequently not expanding <pattern> in it.
223// Testcase:
224// if (glob("/etc/polkit\\-1", 0, NULL, &pglob)) - this returns 0 on uclibc, no bug
225// if (glob("/etc/polkit\\-1/*", 0, NULL, &pglob)) printf("uclibc bug!\n");
226#endif
227
228#if !ENABLE_ASH_INTERNAL_GLOB
229# include <glob.h>
230#endif
231
232#include "unicode.h"
233#include "shell_common.h"
Denys Vlasenko0b883582016-12-23 16:49:07 +0100234#if ENABLE_FEATURE_SH_MATH
Denys Vlasenko67047462016-12-22 15:21:58 +0100235# include "math.h"
Denys Vlasenkocf3a7962017-07-26 14:38:19 +0200236#else
237typedef long arith_t;
238# define ARITH_FMT "%ld"
Denys Vlasenko67047462016-12-22 15:21:58 +0100239#endif
240#if ENABLE_ASH_RANDOM_SUPPORT
241# include "random.h"
242#else
243# define CLEAR_RANDOM_T(rnd) ((void)0)
244#endif
245
246#include "NUM_APPLETS.h"
247#if NUM_APPLETS == 1
248/* STANDALONE does not make sense, and won't compile */
249# undef CONFIG_FEATURE_SH_STANDALONE
250# undef ENABLE_FEATURE_SH_STANDALONE
251# undef IF_FEATURE_SH_STANDALONE
252# undef IF_NOT_FEATURE_SH_STANDALONE
253# define ENABLE_FEATURE_SH_STANDALONE 0
254# define IF_FEATURE_SH_STANDALONE(...)
255# define IF_NOT_FEATURE_SH_STANDALONE(...) __VA_ARGS__
256#endif
257
Denys Vlasenko9acd63c2018-03-28 18:35:07 +0200258#ifndef F_DUPFD_CLOEXEC
259# define F_DUPFD_CLOEXEC F_DUPFD
260#endif
Denys Vlasenko60fb98e2018-03-30 22:15:14 +0200261#ifndef O_CLOEXEC
262# define O_CLOEXEC 0
263#endif
Denys Vlasenko67047462016-12-22 15:21:58 +0100264#ifndef PIPE_BUF
265# define PIPE_BUF 4096 /* amount of buffering in a pipe */
266#endif
267
268#if !BB_MMU
269# error "Do not even bother, ash will not run on NOMMU machine"
270#endif
271
Denys Vlasenko6f9442f2018-01-28 20:41:23 +0100272/* We use a trick to have more optimized code (fewer pointer reloads):
273 * ash.c: extern struct globals *const ash_ptr_to_globals;
274 * ash_ptr_hack.c: struct globals *ash_ptr_to_globals;
275 * This way, compiler in ash.c knows the pointer can not change.
276 *
277 * However, this may break on weird arches or toolchains. In this case,
278 * set "-DBB_GLOBAL_CONST=''" in CONFIG_EXTRA_CFLAGS to disable
279 * this optimization.
280 */
281#ifndef BB_GLOBAL_CONST
282# define BB_GLOBAL_CONST const
283#endif
284
Denis Vlasenkob012b102007-02-19 22:43:01 +0000285
Denis Vlasenko01631112007-12-16 17:20:38 +0000286/* ============ Hash table sizes. Configurable. */
287
288#define VTABSIZE 39
289#define ATABSIZE 39
290#define CMDTABLESIZE 31 /* should be prime */
291
292
Denis Vlasenkob012b102007-02-19 22:43:01 +0000293/* ============ Shell options */
294
295static const char *const optletters_optnames[] = {
296 "e" "errexit",
297 "f" "noglob",
298 "I" "ignoreeof",
299 "i" "interactive",
300 "m" "monitor",
301 "n" "noexec",
302 "s" "stdin",
303 "x" "xtrace",
304 "v" "verbose",
305 "C" "noclobber",
306 "a" "allexport",
307 "b" "notify",
308 "u" "nounset",
Denys Vlasenkoe9ac32a2009-12-05 02:01:25 +0100309 "\0" "vi"
Denys Vlasenko7d4aec02017-01-11 14:00:38 +0100310#if BASH_PIPEFAIL
Denys Vlasenkoe9ac32a2009-12-05 02:01:25 +0100311 ,"\0" "pipefail"
Michael Abbott359da5e2009-12-04 23:03:29 +0100312#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +0000313#if DEBUG
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000314 ,"\0" "nolog"
315 ,"\0" "debug"
Denis Vlasenkob012b102007-02-19 22:43:01 +0000316#endif
317};
318
Denys Vlasenko285ad152009-12-04 23:02:27 +0100319#define optletters(n) optletters_optnames[n][0]
320#define optnames(n) (optletters_optnames[n] + 1)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000321
Denis Vlasenko80b8b392007-06-25 10:55:35 +0000322enum { NOPTS = ARRAY_SIZE(optletters_optnames) };
Denis Vlasenkob012b102007-02-19 22:43:01 +0000323
Eric Andersenc470f442003-07-28 09:56:35 +0000324
Denis Vlasenkob012b102007-02-19 22:43:01 +0000325/* ============ Misc data */
Eric Andersenc470f442003-07-28 09:56:35 +0000326
Denys Vlasenkoea8b2522010-06-02 12:57:26 +0200327#define msg_illnum "Illegal number: %s"
Denis Vlasenkoaa744452007-02-23 01:04:22 +0000328
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +0000329/*
Eric Andersenc470f442003-07-28 09:56:35 +0000330 * We enclose jmp_buf in a structure so that we can declare pointers to
331 * jump locations. The global variable handler contains the location to
Denis Vlasenkof1733952009-03-19 23:21:55 +0000332 * jump to when an exception occurs, and the global variable exception_type
Eric Andersenaff114c2004-04-14 17:51:38 +0000333 * contains a code identifying the exception. To implement nested
Eric Andersenc470f442003-07-28 09:56:35 +0000334 * exception handlers, the user should save the value of handler on entry
335 * to an inner scope, set handler to point to a jmploc structure for the
336 * inner scope, and restore handler on exit from the scope.
337 */
Eric Andersenc470f442003-07-28 09:56:35 +0000338struct jmploc {
339 jmp_buf loc;
340};
Denis Vlasenko01631112007-12-16 17:20:38 +0000341
342struct globals_misc {
Denys Vlasenko4d12e942016-10-01 16:03:11 +0200343 uint8_t exitstatus; /* exit status of last command */
344 uint8_t back_exitstatus;/* exit status of backquoted command */
345 smallint job_warning; /* user was warned about stopped jobs (can be 2, 1 or 0). */
346 int rootpid; /* pid of main shell */
Denis Vlasenko01631112007-12-16 17:20:38 +0000347 /* shell level: 0 for the main shell, 1 for its children, and so on */
348 int shlvl;
349#define rootshell (!shlvl)
Denys Vlasenko675d24a2018-01-27 22:02:05 +0100350 int errlinno;
351
Denis Vlasenko01631112007-12-16 17:20:38 +0000352 char *minusc; /* argument to -c option */
353
354 char *curdir; // = nullstr; /* current working directory */
355 char *physdir; // = nullstr; /* physical working directory */
356
357 char *arg0; /* value of $0 */
358
359 struct jmploc *exception_handler;
Denis Vlasenko991a1da2008-02-10 19:02:53 +0000360
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200361 volatile int suppress_int; /* counter */
362 volatile /*sig_atomic_t*/ smallint pending_int; /* 1 = got SIGINT */
Denys Vlasenko458c1f22016-10-27 23:51:19 +0200363 volatile /*sig_atomic_t*/ smallint got_sigchld; /* 1 = got SIGCHLD */
Denys Vlasenko8f7b0242016-10-28 17:16:11 +0200364 volatile /*sig_atomic_t*/ smallint pending_sig; /* last pending signal */
Denis Vlasenko7f88e342009-03-19 03:36:18 +0000365 smallint exception_type; /* kind of exception (0..5) */
Denis Vlasenko01631112007-12-16 17:20:38 +0000366 /* exceptions */
Eric Andersenc470f442003-07-28 09:56:35 +0000367#define EXINT 0 /* SIGINT received */
368#define EXERROR 1 /* a generic error */
Eric Andersenc470f442003-07-28 09:56:35 +0000369#define EXEXIT 4 /* exit the shell */
Eric Andersen2870d962001-07-02 17:27:21 +0000370
Denis Vlasenkob07a4962008-06-22 13:16:23 +0000371 char nullstr[1]; /* zero length string */
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000372
373 char optlist[NOPTS];
374#define eflag optlist[0]
375#define fflag optlist[1]
376#define Iflag optlist[2]
377#define iflag optlist[3]
378#define mflag optlist[4]
379#define nflag optlist[5]
380#define sflag optlist[6]
381#define xflag optlist[7]
382#define vflag optlist[8]
383#define Cflag optlist[9]
384#define aflag optlist[10]
385#define bflag optlist[11]
386#define uflag optlist[12]
387#define viflag optlist[13]
Denys Vlasenko7d4aec02017-01-11 14:00:38 +0100388#if BASH_PIPEFAIL
Michael Abbott359da5e2009-12-04 23:03:29 +0100389# define pipefail optlist[14]
390#else
391# define pipefail 0
392#endif
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000393#if DEBUG
Denys Vlasenko7d4aec02017-01-11 14:00:38 +0100394# define nolog optlist[14 + BASH_PIPEFAIL]
395# define debug optlist[15 + BASH_PIPEFAIL]
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000396#endif
397
398 /* trap handler commands */
Denis Vlasenko01631112007-12-16 17:20:38 +0000399 /*
400 * Sigmode records the current value of the signal handlers for the various
401 * modes. A value of zero means that the current handler is not known.
Denis Vlasenkof8535cc2008-12-03 10:36:26 +0000402 * S_HARD_IGN indicates that the signal was ignored on entry to the shell.
Denis Vlasenko01631112007-12-16 17:20:38 +0000403 */
404 char sigmode[NSIG - 1];
Denis Vlasenkof8535cc2008-12-03 10:36:26 +0000405#define S_DFL 1 /* default signal handling (SIG_DFL) */
406#define S_CATCH 2 /* signal is caught */
407#define S_IGN 3 /* signal is ignored (SIG_IGN) */
Denys Vlasenko0f14f412017-08-06 20:06:19 +0200408#define S_HARD_IGN 4 /* signal is ignored permanently (it was SIG_IGN on entry to shell) */
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +0000409
Denis Vlasenko01631112007-12-16 17:20:38 +0000410 /* indicates specified signal received */
Denis Vlasenko4b875702009-03-19 13:30:04 +0000411 uint8_t gotsig[NSIG - 1]; /* offset by 1: "signal" 0 is meaningless */
Denys Vlasenko238bf182010-05-18 15:49:07 +0200412 uint8_t may_have_traps; /* 0: definitely no traps are set, 1: some traps may be set */
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000413 char *trap[NSIG];
Denys Vlasenko21d87d42009-09-25 00:06:51 +0200414 char **trap_ptr; /* used only by "trap hack" */
Denis Vlasenko448d30e2008-06-27 00:24:11 +0000415
416 /* Rarely referenced stuff */
417#if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenko3ea2e822009-10-09 20:59:04 +0200418 random_t random_gen;
Denis Vlasenko448d30e2008-06-27 00:24:11 +0000419#endif
420 pid_t backgndpid; /* pid of last background process */
Denis Vlasenko01631112007-12-16 17:20:38 +0000421};
Denys Vlasenko6f9442f2018-01-28 20:41:23 +0100422extern struct globals_misc *BB_GLOBAL_CONST ash_ptr_to_globals_misc;
Denis Vlasenko574f2f42008-02-27 18:41:59 +0000423#define G_misc (*ash_ptr_to_globals_misc)
Denys Vlasenko4d12e942016-10-01 16:03:11 +0200424#define exitstatus (G_misc.exitstatus )
425#define back_exitstatus (G_misc.back_exitstatus )
426#define job_warning (G_misc.job_warning)
Denis Vlasenko26bc57d2008-06-27 00:29:34 +0000427#define rootpid (G_misc.rootpid )
428#define shlvl (G_misc.shlvl )
Denys Vlasenko675d24a2018-01-27 22:02:05 +0100429#define errlinno (G_misc.errlinno )
Denis Vlasenko26bc57d2008-06-27 00:29:34 +0000430#define minusc (G_misc.minusc )
431#define curdir (G_misc.curdir )
432#define physdir (G_misc.physdir )
433#define arg0 (G_misc.arg0 )
Denis Vlasenko01631112007-12-16 17:20:38 +0000434#define exception_handler (G_misc.exception_handler)
Denis Vlasenko7f88e342009-03-19 03:36:18 +0000435#define exception_type (G_misc.exception_type )
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200436#define suppress_int (G_misc.suppress_int )
437#define pending_int (G_misc.pending_int )
Denys Vlasenko458c1f22016-10-27 23:51:19 +0200438#define got_sigchld (G_misc.got_sigchld )
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200439#define pending_sig (G_misc.pending_sig )
Denis Vlasenko26bc57d2008-06-27 00:29:34 +0000440#define nullstr (G_misc.nullstr )
441#define optlist (G_misc.optlist )
442#define sigmode (G_misc.sigmode )
443#define gotsig (G_misc.gotsig )
Denys Vlasenko238bf182010-05-18 15:49:07 +0200444#define may_have_traps (G_misc.may_have_traps )
Denis Vlasenko26bc57d2008-06-27 00:29:34 +0000445#define trap (G_misc.trap )
Denys Vlasenko21d87d42009-09-25 00:06:51 +0200446#define trap_ptr (G_misc.trap_ptr )
Denys Vlasenko3ea2e822009-10-09 20:59:04 +0200447#define random_gen (G_misc.random_gen )
Denis Vlasenko448d30e2008-06-27 00:24:11 +0000448#define backgndpid (G_misc.backgndpid )
Denis Vlasenko01631112007-12-16 17:20:38 +0000449#define INIT_G_misc() do { \
Denis Vlasenko574f2f42008-02-27 18:41:59 +0000450 (*(struct globals_misc**)&ash_ptr_to_globals_misc) = xzalloc(sizeof(G_misc)); \
451 barrier(); \
Denis Vlasenko01631112007-12-16 17:20:38 +0000452 curdir = nullstr; \
453 physdir = nullstr; \
Denys Vlasenko21d87d42009-09-25 00:06:51 +0200454 trap_ptr = trap; \
Denis Vlasenko01631112007-12-16 17:20:38 +0000455} while (0)
456
457
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000458/* ============ DEBUG */
459#if DEBUG
460static void trace_printf(const char *fmt, ...);
461static void trace_vprintf(const char *fmt, va_list va);
462# define TRACE(param) trace_printf param
463# define TRACEV(param) trace_vprintf param
Denis Vlasenko1bb3d7e2009-03-20 07:45:36 +0000464# define close(fd) do { \
465 int dfd = (fd); \
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +0000466 if (close(dfd) < 0) \
Denys Vlasenko883cea42009-07-11 15:31:59 +0200467 bb_error_msg("bug on %d: closing %d(0x%x)", \
Denis Vlasenko1bb3d7e2009-03-20 07:45:36 +0000468 __LINE__, dfd, dfd); \
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +0000469} while (0)
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000470#else
471# define TRACE(param)
472# define TRACEV(param)
473#endif
474
475
Denis Vlasenko559691a2008-10-05 18:39:31 +0000476/* ============ Utility functions */
Denys Vlasenko1961aea2013-02-26 00:36:53 +0100477#define is_name(c) ((c) == '_' || isalpha((unsigned char)(c)))
478#define is_in_name(c) ((c) == '_' || isalnum((unsigned char)(c)))
479
Denys Vlasenko37dc08b2016-10-02 04:38:07 +0200480static int
481isdigit_str9(const char *str)
Denis Vlasenko559691a2008-10-05 18:39:31 +0000482{
483 int maxlen = 9 + 1; /* max 9 digits: 999999999 */
484 while (--maxlen && isdigit(*str))
485 str++;
486 return (*str == '\0');
487}
Denis Vlasenko01631112007-12-16 17:20:38 +0000488
Denys Vlasenko37dc08b2016-10-02 04:38:07 +0200489static const char *
490var_end(const char *var)
Denys Vlasenko8837c5d2010-06-02 12:56:18 +0200491{
492 while (*var)
493 if (*var++ == '=')
494 break;
495 return var;
496}
497
Denis Vlasenko559691a2008-10-05 18:39:31 +0000498
499/* ============ Interrupts / exceptions */
Denys Vlasenko66c5b122011-02-08 05:07:02 +0100500
501static void exitshell(void) NORETURN;
502
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +0000503/*
Eric Andersen2870d962001-07-02 17:27:21 +0000504 * These macros allow the user to suspend the handling of interrupt signals
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +0000505 * over a period of time. This is similar to SIGHOLD or to sigblock, but
Eric Andersen2870d962001-07-02 17:27:21 +0000506 * much more efficient and portable. (But hacking the kernel is so much
507 * more fun than worrying about efficiency and portability. :-))
508 */
Denys Vlasenko06b11492016-11-04 16:43:18 +0100509#if DEBUG_INTONOFF
510# define INT_OFF do { \
511 TRACE(("%s:%d INT_OFF(%d)\n", __func__, __LINE__, suppress_int)); \
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200512 suppress_int++; \
Denys Vlasenkode892052016-10-02 01:49:13 +0200513 barrier(); \
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000514} while (0)
Denys Vlasenko06b11492016-11-04 16:43:18 +0100515#else
516# define INT_OFF do { \
517 suppress_int++; \
518 barrier(); \
519} while (0)
520#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +0000521
522/*
523 * Called to raise an exception. Since C doesn't include exceptions, we
524 * just do a longjmp to the exception handler. The type of exception is
Denis Vlasenko4b875702009-03-19 13:30:04 +0000525 * stored in the global variable "exception_type".
Denis Vlasenkob012b102007-02-19 22:43:01 +0000526 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000527static void raise_exception(int) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +0000528static void
529raise_exception(int e)
530{
531#if DEBUG
Denis Vlasenko2da584f2007-02-19 22:44:05 +0000532 if (exception_handler == NULL)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000533 abort();
534#endif
535 INT_OFF;
Denis Vlasenko7f88e342009-03-19 03:36:18 +0000536 exception_type = e;
Denis Vlasenko2da584f2007-02-19 22:44:05 +0000537 longjmp(exception_handler->loc, 1);
Denis Vlasenkob012b102007-02-19 22:43:01 +0000538}
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000539#if DEBUG
540#define raise_exception(e) do { \
541 TRACE(("raising exception %d on line %d\n", (e), __LINE__)); \
542 raise_exception(e); \
543} while (0)
544#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +0000545
546/*
Denys Vlasenkof37e1152016-10-07 03:17:28 +0200547 * Called when a SIGINT is received. (If the user specifies
Denis Vlasenkob012b102007-02-19 22:43:01 +0000548 * that SIGINT is to be trapped or ignored using the trap builtin, then
549 * this routine is not called.) Suppressint is nonzero when interrupts
550 * are held using the INT_OFF macro. (The test for iflag is just
551 * defensive programming.)
552 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000553static void raise_interrupt(void) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +0000554static void
555raise_interrupt(void)
556{
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200557 pending_int = 0;
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +0000558 /* Signal is not automatically unmasked after it is raised,
559 * do it ourself - unmask all signals */
Denis Vlasenko3f165fa2008-03-17 08:29:08 +0000560 sigprocmask_allsigs(SIG_UNBLOCK);
Denys Vlasenko238bf182010-05-18 15:49:07 +0200561 /* pending_sig = 0; - now done in signal_handler() */
Denis Vlasenko7c139b42007-03-21 20:17:27 +0000562
Denys Vlasenkoc0663c72016-10-27 21:09:01 +0200563 if (!(rootshell && iflag)) {
564 /* Kill ourself with SIGINT */
565 signal(SIGINT, SIG_DFL);
566 raise(SIGINT);
Denis Vlasenkob012b102007-02-19 22:43:01 +0000567 }
Denys Vlasenko4d12e942016-10-01 16:03:11 +0200568 /* bash: ^C even on empty command line sets $? */
569 exitstatus = SIGINT + 128;
Denys Vlasenkoc0663c72016-10-27 21:09:01 +0200570 raise_exception(EXINT);
Denis Vlasenkob012b102007-02-19 22:43:01 +0000571 /* NOTREACHED */
572}
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000573#if DEBUG
574#define raise_interrupt() do { \
575 TRACE(("raising interrupt on line %d\n", __LINE__)); \
576 raise_interrupt(); \
577} while (0)
578#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +0000579
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000580static IF_ASH_OPTIMIZE_FOR_SIZE(inline) void
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000581int_on(void)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000582{
Denys Vlasenkode892052016-10-02 01:49:13 +0200583 barrier();
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200584 if (--suppress_int == 0 && pending_int) {
Denis Vlasenkob012b102007-02-19 22:43:01 +0000585 raise_interrupt();
586 }
587}
Denys Vlasenko06b11492016-11-04 16:43:18 +0100588#if DEBUG_INTONOFF
589# define INT_ON do { \
590 TRACE(("%s:%d INT_ON(%d)\n", __func__, __LINE__, suppress_int-1)); \
591 int_on(); \
592} while (0)
593#else
594# define INT_ON int_on()
595#endif
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000596static IF_ASH_OPTIMIZE_FOR_SIZE(inline) void
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000597force_int_on(void)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000598{
Denys Vlasenkode892052016-10-02 01:49:13 +0200599 barrier();
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200600 suppress_int = 0;
601 if (pending_int)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000602 raise_interrupt();
603}
604#define FORCE_INT_ON force_int_on()
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000605
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200606#define SAVE_INT(v) ((v) = suppress_int)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000607
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000608#define RESTORE_INT(v) do { \
Denys Vlasenkode892052016-10-02 01:49:13 +0200609 barrier(); \
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200610 suppress_int = (v); \
611 if (suppress_int == 0 && pending_int) \
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000612 raise_interrupt(); \
613} while (0)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000614
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000615
Denis Vlasenkobc54cff2007-02-23 01:05:52 +0000616/* ============ Stdout/stderr output */
Eric Andersenc470f442003-07-28 09:56:35 +0000617
Eric Andersenc470f442003-07-28 09:56:35 +0000618static void
Denis Vlasenkob012b102007-02-19 22:43:01 +0000619outstr(const char *p, FILE *file)
Denis Vlasenkoe5570da2007-02-19 22:41:55 +0000620{
Denis Vlasenkob012b102007-02-19 22:43:01 +0000621 INT_OFF;
622 fputs(p, file);
623 INT_ON;
624}
625
626static void
627flush_stdout_stderr(void)
628{
629 INT_OFF;
Denys Vlasenko8131eea2009-11-02 14:19:51 +0100630 fflush_all();
Denis Vlasenkob012b102007-02-19 22:43:01 +0000631 INT_ON;
632}
633
Denys Vlasenko9c541002015-10-07 15:44:36 +0200634/* Was called outcslow(c,FILE*), but c was always '\n' */
Denis Vlasenkob012b102007-02-19 22:43:01 +0000635static void
Denys Vlasenko9c541002015-10-07 15:44:36 +0200636newline_and_flush(FILE *dest)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000637{
638 INT_OFF;
Denys Vlasenko9c541002015-10-07 15:44:36 +0200639 putc('\n', dest);
Denis Vlasenkob012b102007-02-19 22:43:01 +0000640 fflush(dest);
641 INT_ON;
642}
643
644static int out1fmt(const char *, ...) __attribute__((__format__(__printf__,1,2)));
645static int
646out1fmt(const char *fmt, ...)
647{
648 va_list ap;
649 int r;
650
651 INT_OFF;
652 va_start(ap, fmt);
653 r = vprintf(fmt, ap);
654 va_end(ap);
655 INT_ON;
656 return r;
657}
658
659static int fmtstr(char *, size_t, const char *, ...) __attribute__((__format__(__printf__,3,4)));
660static int
661fmtstr(char *outbuf, size_t length, const char *fmt, ...)
662{
663 va_list ap;
664 int ret;
665
Denis Vlasenkob012b102007-02-19 22:43:01 +0000666 INT_OFF;
Denys Vlasenkocf3a7962017-07-26 14:38:19 +0200667 va_start(ap, fmt);
Denis Vlasenkob012b102007-02-19 22:43:01 +0000668 ret = vsnprintf(outbuf, length, fmt, ap);
669 va_end(ap);
670 INT_ON;
671 return ret;
672}
673
674static void
675out1str(const char *p)
676{
677 outstr(p, stdout);
678}
679
680static void
681out2str(const char *p)
682{
683 outstr(p, stderr);
Denys Vlasenko8131eea2009-11-02 14:19:51 +0100684 flush_stdout_stderr();
Denis Vlasenkob012b102007-02-19 22:43:01 +0000685}
686
687
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +0000688/* ============ Parser structures */
Denis Vlasenko4d2183b2007-02-23 01:05:38 +0000689
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000690/* control characters in argument strings */
Denys Vlasenko2ce42e92009-11-29 02:18:13 +0100691#define CTL_FIRST CTLESC
Denys Vlasenkob6c84342009-08-29 20:23:20 +0200692#define CTLESC ((unsigned char)'\201') /* escape next character */
693#define CTLVAR ((unsigned char)'\202') /* variable defn */
694#define CTLENDVAR ((unsigned char)'\203')
695#define CTLBACKQ ((unsigned char)'\204')
Denys Vlasenkob6c84342009-08-29 20:23:20 +0200696#define CTLARI ((unsigned char)'\206') /* arithmetic expression */
697#define CTLENDARI ((unsigned char)'\207')
698#define CTLQUOTEMARK ((unsigned char)'\210')
Denys Vlasenko2ce42e92009-11-29 02:18:13 +0100699#define CTL_LAST CTLQUOTEMARK
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000700
701/* variable substitution byte (follows CTLVAR) */
702#define VSTYPE 0x0f /* type of variable substitution */
703#define VSNUL 0x10 /* colon--treat the empty string as unset */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000704
705/* values of VSTYPE field */
Denis Vlasenko92e13c22008-03-25 01:17:40 +0000706#define VSNORMAL 0x1 /* normal variable: $var or ${var} */
707#define VSMINUS 0x2 /* ${var-text} */
708#define VSPLUS 0x3 /* ${var+text} */
709#define VSQUESTION 0x4 /* ${var?message} */
710#define VSASSIGN 0x5 /* ${var=text} */
711#define VSTRIMRIGHT 0x6 /* ${var%pattern} */
712#define VSTRIMRIGHTMAX 0x7 /* ${var%%pattern} */
713#define VSTRIMLEFT 0x8 /* ${var#pattern} */
714#define VSTRIMLEFTMAX 0x9 /* ${var##pattern} */
715#define VSLENGTH 0xa /* ${#var} */
Denys Vlasenko7d4aec02017-01-11 14:00:38 +0100716#if BASH_SUBSTR
Denis Vlasenko92e13c22008-03-25 01:17:40 +0000717#define VSSUBSTR 0xc /* ${var:position:length} */
Denys Vlasenko7d4aec02017-01-11 14:00:38 +0100718#endif
719#if BASH_PATTERN_SUBST
Denis Vlasenko92e13c22008-03-25 01:17:40 +0000720#define VSREPLACE 0xd /* ${var/pattern/replacement} */
721#define VSREPLACEALL 0xe /* ${var//pattern/replacement} */
722#endif
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000723
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000724static const char dolatstr[] ALIGN1 = {
Ron Yorston549deab2015-05-18 09:57:51 +0200725 CTLQUOTEMARK, CTLVAR, VSNORMAL, '@', '=', CTLQUOTEMARK, '\0'
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000726};
Ron Yorston549deab2015-05-18 09:57:51 +0200727#define DOLATSTRLEN 6
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +0000728
Denis Vlasenko559691a2008-10-05 18:39:31 +0000729#define NCMD 0
730#define NPIPE 1
731#define NREDIR 2
732#define NBACKGND 3
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000733#define NSUBSHELL 4
Denis Vlasenko559691a2008-10-05 18:39:31 +0000734#define NAND 5
735#define NOR 6
736#define NSEMI 7
737#define NIF 8
738#define NWHILE 9
739#define NUNTIL 10
740#define NFOR 11
741#define NCASE 12
742#define NCLIST 13
743#define NDEFUN 14
744#define NARG 15
745#define NTO 16
Denys Vlasenko7d4aec02017-01-11 14:00:38 +0100746#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +0000747#define NTO2 17
748#endif
749#define NCLOBBER 18
750#define NFROM 19
751#define NFROMTO 20
752#define NAPPEND 21
753#define NTOFD 22
754#define NFROMFD 23
755#define NHERE 24
756#define NXHERE 25
757#define NNOT 26
Denis Vlasenko340299a2008-11-21 10:36:36 +0000758#define N_NUMBER 27
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000759
760union node;
761
762struct ncmd {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000763 smallint type; /* Nxxxx */
Denys Vlasenko675d24a2018-01-27 22:02:05 +0100764 int linno;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000765 union node *assign;
766 union node *args;
767 union node *redirect;
768};
769
770struct npipe {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000771 smallint type;
772 smallint pipe_backgnd;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000773 struct nodelist *cmdlist;
774};
775
776struct nredir {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000777 smallint type;
Denys Vlasenko675d24a2018-01-27 22:02:05 +0100778 int linno;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000779 union node *n;
780 union node *redirect;
781};
782
783struct nbinary {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000784 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000785 union node *ch1;
786 union node *ch2;
787};
788
789struct nif {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000790 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000791 union node *test;
792 union node *ifpart;
793 union node *elsepart;
794};
795
796struct nfor {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000797 smallint type;
Denys Vlasenko675d24a2018-01-27 22:02:05 +0100798 int linno;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000799 union node *args;
800 union node *body;
801 char *var;
802};
803
804struct ncase {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000805 smallint type;
Denys Vlasenko675d24a2018-01-27 22:02:05 +0100806 int linno;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000807 union node *expr;
808 union node *cases;
809};
810
811struct nclist {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000812 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000813 union node *next;
814 union node *pattern;
815 union node *body;
816};
817
Denys Vlasenko675d24a2018-01-27 22:02:05 +0100818struct ndefun {
819 smallint type;
820 int linno;
821 char *text;
822 union node *body;
823};
824
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000825struct narg {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000826 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000827 union node *next;
828 char *text;
829 struct nodelist *backquote;
830};
831
Denis Vlasenko559691a2008-10-05 18:39:31 +0000832/* nfile and ndup layout must match!
833 * NTOFD (>&fdnum) uses ndup structure, but we may discover mid-flight
834 * that it is actually NTO2 (>&file), and change its type.
835 */
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000836struct nfile {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000837 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000838 union node *next;
839 int fd;
Denis Vlasenko559691a2008-10-05 18:39:31 +0000840 int _unused_dupfd;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000841 union node *fname;
842 char *expfname;
843};
844
845struct ndup {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000846 smallint type;
Denis Vlasenko559691a2008-10-05 18:39:31 +0000847 union node *next;
848 int fd;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000849 int dupfd;
850 union node *vname;
Denis Vlasenko559691a2008-10-05 18:39:31 +0000851 char *_unused_expfname;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000852};
853
854struct nhere {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000855 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000856 union node *next;
857 int fd;
858 union node *doc;
859};
860
861struct nnot {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000862 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000863 union node *com;
864};
865
866union node {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000867 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000868 struct ncmd ncmd;
869 struct npipe npipe;
870 struct nredir nredir;
871 struct nbinary nbinary;
872 struct nif nif;
873 struct nfor nfor;
874 struct ncase ncase;
875 struct nclist nclist;
Denys Vlasenko675d24a2018-01-27 22:02:05 +0100876 struct ndefun ndefun;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000877 struct narg narg;
878 struct nfile nfile;
879 struct ndup ndup;
880 struct nhere nhere;
881 struct nnot nnot;
882};
883
Denys Vlasenko86e83ec2009-07-23 22:07:07 +0200884/*
885 * NODE_EOF is returned by parsecmd when it encounters an end of file.
886 * It must be distinct from NULL.
887 */
888#define NODE_EOF ((union node *) -1L)
889
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000890struct nodelist {
891 struct nodelist *next;
892 union node *n;
893};
894
895struct funcnode {
896 int count;
897 union node n;
898};
899
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000900/*
901 * Free a parse tree.
902 */
903static void
904freefunc(struct funcnode *f)
905{
906 if (f && --f->count < 0)
907 free(f);
908}
909
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000910
911/* ============ Debugging output */
912
913#if DEBUG
914
915static FILE *tracefile;
916
917static void
918trace_printf(const char *fmt, ...)
919{
920 va_list va;
921
922 if (debug != 1)
923 return;
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000924 if (DEBUG_TIME)
925 fprintf(tracefile, "%u ", (int) time(NULL));
926 if (DEBUG_PID)
927 fprintf(tracefile, "[%u] ", (int) getpid());
928 if (DEBUG_SIG)
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200929 fprintf(tracefile, "pending s:%d i:%d(supp:%d) ", pending_sig, pending_int, suppress_int);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000930 va_start(va, fmt);
931 vfprintf(tracefile, fmt, va);
932 va_end(va);
933}
934
935static void
936trace_vprintf(const char *fmt, va_list va)
937{
938 if (debug != 1)
939 return;
940 vfprintf(tracefile, fmt, va);
Denys Vlasenko474ed062016-10-30 18:30:29 +0100941 fprintf(tracefile, "\n");
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000942}
943
944static void
945trace_puts(const char *s)
946{
947 if (debug != 1)
948 return;
949 fputs(s, tracefile);
950}
951
952static void
953trace_puts_quoted(char *s)
954{
955 char *p;
956 char c;
957
958 if (debug != 1)
959 return;
960 putc('"', tracefile);
961 for (p = s; *p; p++) {
Denys Vlasenkocd716832009-11-28 22:14:02 +0100962 switch ((unsigned char)*p) {
963 case '\n': c = 'n'; goto backslash;
964 case '\t': c = 't'; goto backslash;
965 case '\r': c = 'r'; goto backslash;
966 case '\"': c = '\"'; goto backslash;
967 case '\\': c = '\\'; goto backslash;
968 case CTLESC: c = 'e'; goto backslash;
969 case CTLVAR: c = 'v'; goto backslash;
Denys Vlasenkocd716832009-11-28 22:14:02 +0100970 case CTLBACKQ: c = 'q'; goto backslash;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000971 backslash:
972 putc('\\', tracefile);
973 putc(c, tracefile);
974 break;
975 default:
976 if (*p >= ' ' && *p <= '~')
977 putc(*p, tracefile);
978 else {
979 putc('\\', tracefile);
Denys Vlasenkocd716832009-11-28 22:14:02 +0100980 putc((*p >> 6) & 03, tracefile);
981 putc((*p >> 3) & 07, tracefile);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000982 putc(*p & 07, tracefile);
983 }
984 break;
985 }
986 }
987 putc('"', tracefile);
988}
989
990static void
991trace_puts_args(char **ap)
992{
993 if (debug != 1)
994 return;
995 if (!*ap)
996 return;
997 while (1) {
998 trace_puts_quoted(*ap);
999 if (!*++ap) {
1000 putc('\n', tracefile);
1001 break;
1002 }
1003 putc(' ', tracefile);
1004 }
1005}
1006
1007static void
1008opentrace(void)
1009{
1010 char s[100];
1011#ifdef O_APPEND
1012 int flags;
1013#endif
1014
1015 if (debug != 1) {
1016 if (tracefile)
1017 fflush(tracefile);
1018 /* leave open because libedit might be using it */
1019 return;
1020 }
1021 strcpy(s, "./trace");
1022 if (tracefile) {
1023 if (!freopen(s, "a", tracefile)) {
1024 fprintf(stderr, "Can't re-open %s\n", s);
1025 debug = 0;
1026 return;
1027 }
1028 } else {
1029 tracefile = fopen(s, "a");
1030 if (tracefile == NULL) {
1031 fprintf(stderr, "Can't open %s\n", s);
1032 debug = 0;
1033 return;
1034 }
1035 }
1036#ifdef O_APPEND
Denis Vlasenkod37f2222007-08-19 13:42:08 +00001037 flags = fcntl(fileno(tracefile), F_GETFL);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001038 if (flags >= 0)
1039 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
1040#endif
1041 setlinebuf(tracefile);
1042 fputs("\nTracing started.\n", tracefile);
1043}
1044
1045static void
1046indent(int amount, char *pfx, FILE *fp)
1047{
1048 int i;
1049
1050 for (i = 0; i < amount; i++) {
1051 if (pfx && i == amount - 1)
1052 fputs(pfx, fp);
1053 putc('\t', fp);
1054 }
1055}
1056
1057/* little circular references here... */
1058static void shtree(union node *n, int ind, char *pfx, FILE *fp);
1059
1060static void
1061sharg(union node *arg, FILE *fp)
1062{
1063 char *p;
1064 struct nodelist *bqlist;
Denys Vlasenkocd716832009-11-28 22:14:02 +01001065 unsigned char subtype;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001066
1067 if (arg->type != NARG) {
1068 out1fmt("<node type %d>\n", arg->type);
1069 abort();
1070 }
1071 bqlist = arg->narg.backquote;
1072 for (p = arg->narg.text; *p; p++) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01001073 switch ((unsigned char)*p) {
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001074 case CTLESC:
Dan Fandrich77d48722010-09-07 23:38:28 -07001075 p++;
1076 putc(*p, fp);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001077 break;
1078 case CTLVAR:
1079 putc('$', fp);
1080 putc('{', fp);
1081 subtype = *++p;
1082 if (subtype == VSLENGTH)
1083 putc('#', fp);
1084
Dan Fandrich77d48722010-09-07 23:38:28 -07001085 while (*p != '=') {
1086 putc(*p, fp);
1087 p++;
1088 }
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001089
1090 if (subtype & VSNUL)
1091 putc(':', fp);
1092
1093 switch (subtype & VSTYPE) {
1094 case VSNORMAL:
1095 putc('}', fp);
1096 break;
1097 case VSMINUS:
1098 putc('-', fp);
1099 break;
1100 case VSPLUS:
1101 putc('+', fp);
1102 break;
1103 case VSQUESTION:
1104 putc('?', fp);
1105 break;
1106 case VSASSIGN:
1107 putc('=', fp);
1108 break;
1109 case VSTRIMLEFT:
1110 putc('#', fp);
1111 break;
1112 case VSTRIMLEFTMAX:
1113 putc('#', fp);
1114 putc('#', fp);
1115 break;
1116 case VSTRIMRIGHT:
1117 putc('%', fp);
1118 break;
1119 case VSTRIMRIGHTMAX:
1120 putc('%', fp);
1121 putc('%', fp);
1122 break;
1123 case VSLENGTH:
1124 break;
1125 default:
1126 out1fmt("<subtype %d>", subtype);
1127 }
1128 break;
1129 case CTLENDVAR:
1130 putc('}', fp);
1131 break;
1132 case CTLBACKQ:
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001133 putc('$', fp);
1134 putc('(', fp);
1135 shtree(bqlist->n, -1, NULL, fp);
1136 putc(')', fp);
1137 break;
1138 default:
1139 putc(*p, fp);
1140 break;
1141 }
1142 }
1143}
1144
Denys Vlasenko641dd7b2009-06-11 19:30:19 +02001145static void
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001146shcmd(union node *cmd, FILE *fp)
1147{
1148 union node *np;
1149 int first;
1150 const char *s;
1151 int dftfd;
1152
1153 first = 1;
1154 for (np = cmd->ncmd.args; np; np = np->narg.next) {
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001155 if (!first)
1156 putc(' ', fp);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001157 sharg(np, fp);
1158 first = 0;
1159 }
1160 for (np = cmd->ncmd.redirect; np; np = np->nfile.next) {
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001161 if (!first)
1162 putc(' ', fp);
1163 dftfd = 0;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001164 switch (np->nfile.type) {
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001165 case NTO: s = ">>"+1; dftfd = 1; break;
1166 case NCLOBBER: s = ">|"; dftfd = 1; break;
1167 case NAPPEND: s = ">>"; dftfd = 1; break;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01001168#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00001169 case NTO2:
1170#endif
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001171 case NTOFD: s = ">&"; dftfd = 1; break;
Denis Vlasenko559691a2008-10-05 18:39:31 +00001172 case NFROM: s = "<"; break;
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001173 case NFROMFD: s = "<&"; break;
1174 case NFROMTO: s = "<>"; break;
1175 default: s = "*error*"; break;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001176 }
1177 if (np->nfile.fd != dftfd)
1178 fprintf(fp, "%d", np->nfile.fd);
1179 fputs(s, fp);
1180 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
1181 fprintf(fp, "%d", np->ndup.dupfd);
1182 } else {
1183 sharg(np->nfile.fname, fp);
1184 }
1185 first = 0;
1186 }
1187}
1188
1189static void
1190shtree(union node *n, int ind, char *pfx, FILE *fp)
1191{
1192 struct nodelist *lp;
1193 const char *s;
1194
1195 if (n == NULL)
1196 return;
1197
1198 indent(ind, pfx, fp);
Denys Vlasenko86e83ec2009-07-23 22:07:07 +02001199
1200 if (n == NODE_EOF) {
1201 fputs("<EOF>", fp);
1202 return;
1203 }
1204
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001205 switch (n->type) {
1206 case NSEMI:
1207 s = "; ";
1208 goto binop;
1209 case NAND:
1210 s = " && ";
1211 goto binop;
1212 case NOR:
1213 s = " || ";
1214 binop:
1215 shtree(n->nbinary.ch1, ind, NULL, fp);
1216 /* if (ind < 0) */
1217 fputs(s, fp);
1218 shtree(n->nbinary.ch2, ind, NULL, fp);
1219 break;
1220 case NCMD:
1221 shcmd(n, fp);
1222 if (ind >= 0)
1223 putc('\n', fp);
1224 break;
1225 case NPIPE:
1226 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
Denys Vlasenko7cee00e2009-07-24 01:08:03 +02001227 shtree(lp->n, 0, NULL, fp);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001228 if (lp->next)
1229 fputs(" | ", fp);
1230 }
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00001231 if (n->npipe.pipe_backgnd)
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001232 fputs(" &", fp);
1233 if (ind >= 0)
1234 putc('\n', fp);
1235 break;
1236 default:
1237 fprintf(fp, "<node type %d>", n->type);
1238 if (ind >= 0)
1239 putc('\n', fp);
1240 break;
1241 }
1242}
1243
1244static void
1245showtree(union node *n)
1246{
1247 trace_puts("showtree called\n");
Denys Vlasenko883cea42009-07-11 15:31:59 +02001248 shtree(n, 1, NULL, stderr);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001249}
1250
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001251#endif /* DEBUG */
1252
1253
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00001254/* ============ Parser data */
1255
1256/*
Denis Vlasenkob012b102007-02-19 22:43:01 +00001257 * ash_vmsg() needs parsefile->fd, hence parsefile definition is moved up.
1258 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001259struct strlist {
1260 struct strlist *next;
1261 char *text;
1262};
1263
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001264struct alias;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001265
Denis Vlasenkob012b102007-02-19 22:43:01 +00001266struct strpush {
1267 struct strpush *prev; /* preceding string on stack */
Denis Vlasenko41eb3002008-11-28 03:42:31 +00001268 char *prev_string;
1269 int prev_left_in_line;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001270#if ENABLE_ASH_ALIAS
1271 struct alias *ap; /* if push was associated with an alias */
1272#endif
1273 char *string; /* remember the string since it may change */
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02001274
1275 /* Remember last two characters for pungetc. */
1276 int lastc[2];
1277
1278 /* Number of outstanding calls to pungetc. */
1279 int unget;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001280};
1281
Denys Vlasenko0485b672017-08-14 19:46:56 +02001282/*
1283 * The parsefile structure pointed to by the global variable parsefile
1284 * contains information about the current file being read.
1285 */
Denis Vlasenkob012b102007-02-19 22:43:01 +00001286struct parsefile {
1287 struct parsefile *prev; /* preceding file on stack */
1288 int linno; /* current line */
Denys Vlasenko79b3d422010-06-03 04:29:08 +02001289 int pf_fd; /* file descriptor (or -1 if string) */
Denis Vlasenko41eb3002008-11-28 03:42:31 +00001290 int left_in_line; /* number of chars left in this line */
1291 int left_in_buffer; /* number of chars left in this buffer past the line */
1292 char *next_to_pgetc; /* next char in buffer */
Denis Vlasenkob012b102007-02-19 22:43:01 +00001293 char *buf; /* input buffer */
1294 struct strpush *strpush; /* for pushing strings at this level */
1295 struct strpush basestrpush; /* so pushing one is fast */
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02001296
1297 /* Remember last two characters for pungetc. */
1298 int lastc[2];
1299
1300 /* Number of outstanding calls to pungetc. */
1301 int unget;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001302};
1303
Denis Vlasenko448d30e2008-06-27 00:24:11 +00001304static struct parsefile basepf; /* top level input file */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00001305static struct parsefile *g_parsefile = &basepf; /* current input file */
Denis Vlasenkob012b102007-02-19 22:43:01 +00001306static char *commandname; /* currently executing command */
Denis Vlasenkob012b102007-02-19 22:43:01 +00001307
1308
1309/* ============ Message printing */
1310
1311static void
1312ash_vmsg(const char *msg, va_list ap)
1313{
1314 fprintf(stderr, "%s: ", arg0);
1315 if (commandname) {
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00001316 if (strcmp(arg0, commandname))
1317 fprintf(stderr, "%s: ", commandname);
Denys Vlasenko79b3d422010-06-03 04:29:08 +02001318 if (!iflag || g_parsefile->pf_fd > 0)
Denys Vlasenko675d24a2018-01-27 22:02:05 +01001319 fprintf(stderr, "line %d: ", errlinno);
Eric Andersenc470f442003-07-28 09:56:35 +00001320 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00001321 vfprintf(stderr, msg, ap);
Denys Vlasenko9c541002015-10-07 15:44:36 +02001322 newline_and_flush(stderr);
Eric Andersenc470f442003-07-28 09:56:35 +00001323}
Denis Vlasenkob012b102007-02-19 22:43:01 +00001324
1325/*
1326 * Exverror is called to raise the error exception. If the second argument
1327 * is not NULL then error prints an error message using printf style
1328 * formatting. It then raises the error exception.
1329 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00001330static void ash_vmsg_and_raise(int, const char *, va_list) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001331static void
1332ash_vmsg_and_raise(int cond, const char *msg, va_list ap)
Eric Andersenc470f442003-07-28 09:56:35 +00001333{
Denis Vlasenkob012b102007-02-19 22:43:01 +00001334#if DEBUG
1335 if (msg) {
Denys Vlasenko474ed062016-10-30 18:30:29 +01001336 TRACE(("ash_vmsg_and_raise(%d):", cond));
Denis Vlasenkob012b102007-02-19 22:43:01 +00001337 TRACEV((msg, ap));
Denis Vlasenkob012b102007-02-19 22:43:01 +00001338 } else
Denys Vlasenko474ed062016-10-30 18:30:29 +01001339 TRACE(("ash_vmsg_and_raise(%d):NULL\n", cond));
Denis Vlasenkob012b102007-02-19 22:43:01 +00001340 if (msg)
1341#endif
1342 ash_vmsg(msg, ap);
1343
1344 flush_stdout_stderr();
1345 raise_exception(cond);
1346 /* NOTREACHED */
Eric Andersenc470f442003-07-28 09:56:35 +00001347}
Denis Vlasenkob012b102007-02-19 22:43:01 +00001348
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00001349static void ash_msg_and_raise_error(const char *, ...) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001350static void
1351ash_msg_and_raise_error(const char *msg, ...)
1352{
1353 va_list ap;
1354
Ron Yorstonea7d2f62017-01-03 11:18:23 +01001355 exitstatus = 2;
1356
Denis Vlasenkob012b102007-02-19 22:43:01 +00001357 va_start(ap, msg);
1358 ash_vmsg_and_raise(EXERROR, msg, ap);
1359 /* NOTREACHED */
1360 va_end(ap);
1361}
1362
Ron Yorstonbe366e52017-07-27 13:53:39 +01001363/*
Ron Yorstonbe366e52017-07-27 13:53:39 +01001364 * 'fmt' must be a string literal.
1365 */
Denys Vlasenko6f97b302017-09-29 18:17:25 +02001366#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 +01001367
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00001368static void raise_error_syntax(const char *) NORETURN;
1369static void
1370raise_error_syntax(const char *msg)
1371{
Denys Vlasenko675d24a2018-01-27 22:02:05 +01001372 errlinno = g_parsefile->linno;
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00001373 ash_msg_and_raise_error("syntax error: %s", msg);
1374 /* NOTREACHED */
1375}
1376
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00001377static void ash_msg_and_raise(int, const char *, ...) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001378static void
1379ash_msg_and_raise(int cond, const char *msg, ...)
1380{
1381 va_list ap;
1382
1383 va_start(ap, msg);
1384 ash_vmsg_and_raise(cond, msg, ap);
1385 /* NOTREACHED */
1386 va_end(ap);
1387}
1388
1389/*
1390 * error/warning routines for external builtins
1391 */
1392static void
1393ash_msg(const char *fmt, ...)
1394{
1395 va_list ap;
1396
1397 va_start(ap, fmt);
1398 ash_vmsg(fmt, ap);
1399 va_end(ap);
1400}
1401
1402/*
1403 * Return a string describing an error. The returned string may be a
1404 * pointer to a static buffer that will be overwritten on the next call.
1405 * Action describes the operation that got the error.
1406 */
1407static const char *
1408errmsg(int e, const char *em)
1409{
1410 if (e == ENOENT || e == ENOTDIR) {
1411 return em;
1412 }
1413 return strerror(e);
1414}
1415
1416
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001417/* ============ Memory allocation */
1418
Denys Vlasenkoe7670ff2009-10-11 00:45:25 +02001419#if 0
1420/* I consider these wrappers nearly useless:
1421 * ok, they return you to nearest exception handler, but
1422 * how much memory do you leak in the process, making
1423 * memory starvation worse?
1424 */
1425static void *
1426ckrealloc(void * p, size_t nbytes)
1427{
1428 p = realloc(p, nbytes);
1429 if (!p)
1430 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1431 return p;
1432}
1433
1434static void *
1435ckmalloc(size_t nbytes)
1436{
1437 return ckrealloc(NULL, nbytes);
1438}
1439
1440static void *
1441ckzalloc(size_t nbytes)
1442{
1443 return memset(ckmalloc(nbytes), 0, nbytes);
1444}
1445
1446static char *
1447ckstrdup(const char *s)
1448{
1449 char *p = strdup(s);
1450 if (!p)
1451 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1452 return p;
1453}
1454#else
1455/* Using bbox equivalents. They exit if out of memory */
1456# define ckrealloc xrealloc
1457# define ckmalloc xmalloc
1458# define ckzalloc xzalloc
1459# define ckstrdup xstrdup
1460#endif
1461
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001462/*
1463 * It appears that grabstackstr() will barf with such alignments
1464 * because stalloc() will return a string allocated in a new stackblock.
1465 */
1466#define SHELL_ALIGN(nbytes) (((nbytes) + SHELL_SIZE) & ~SHELL_SIZE)
1467enum {
1468 /* Most machines require the value returned from malloc to be aligned
1469 * in some way. The following macro will get this right
1470 * on many machines. */
Denys Vlasenko0e5e4ea2009-10-11 00:36:20 +02001471 SHELL_SIZE = sizeof(union { int i; char *cp; double d; }) - 1,
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001472 /* Minimum size of a block */
Denis Vlasenko01631112007-12-16 17:20:38 +00001473 MINSIZE = SHELL_ALIGN(504),
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001474};
1475
1476struct stack_block {
1477 struct stack_block *prev;
1478 char space[MINSIZE];
1479};
1480
1481struct stackmark {
1482 struct stack_block *stackp;
1483 char *stacknxt;
1484 size_t stacknleft;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001485};
1486
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001487
Denis Vlasenko01631112007-12-16 17:20:38 +00001488struct globals_memstack {
1489 struct stack_block *g_stackp; // = &stackbase;
Denis Vlasenko01631112007-12-16 17:20:38 +00001490 char *g_stacknxt; // = stackbase.space;
1491 char *sstrend; // = stackbase.space + MINSIZE;
1492 size_t g_stacknleft; // = MINSIZE;
Denis Vlasenko01631112007-12-16 17:20:38 +00001493 struct stack_block stackbase;
1494};
Denys Vlasenko6f9442f2018-01-28 20:41:23 +01001495extern struct globals_memstack *BB_GLOBAL_CONST ash_ptr_to_globals_memstack;
Denis Vlasenko574f2f42008-02-27 18:41:59 +00001496#define G_memstack (*ash_ptr_to_globals_memstack)
Denis Vlasenko01631112007-12-16 17:20:38 +00001497#define g_stackp (G_memstack.g_stackp )
Denis Vlasenko01631112007-12-16 17:20:38 +00001498#define g_stacknxt (G_memstack.g_stacknxt )
1499#define sstrend (G_memstack.sstrend )
1500#define g_stacknleft (G_memstack.g_stacknleft)
Denis Vlasenko01631112007-12-16 17:20:38 +00001501#define stackbase (G_memstack.stackbase )
1502#define INIT_G_memstack() do { \
Denis Vlasenko574f2f42008-02-27 18:41:59 +00001503 (*(struct globals_memstack**)&ash_ptr_to_globals_memstack) = xzalloc(sizeof(G_memstack)); \
1504 barrier(); \
Denis Vlasenko01631112007-12-16 17:20:38 +00001505 g_stackp = &stackbase; \
1506 g_stacknxt = stackbase.space; \
1507 g_stacknleft = MINSIZE; \
1508 sstrend = stackbase.space + MINSIZE; \
Denis Vlasenko01631112007-12-16 17:20:38 +00001509} while (0)
1510
Denys Vlasenkoe7670ff2009-10-11 00:45:25 +02001511
Denis Vlasenko01631112007-12-16 17:20:38 +00001512#define stackblock() ((void *)g_stacknxt)
1513#define stackblocksize() g_stacknleft
1514
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001515/*
1516 * Parse trees for commands are allocated in lifo order, so we use a stack
1517 * to make this more efficient, and also to avoid all sorts of exception
1518 * handling code to handle interrupts in the middle of a parse.
1519 *
1520 * The size 504 was chosen because the Ultrix malloc handles that size
1521 * well.
1522 */
1523static void *
1524stalloc(size_t nbytes)
1525{
1526 char *p;
1527 size_t aligned;
1528
1529 aligned = SHELL_ALIGN(nbytes);
Denis Vlasenko01631112007-12-16 17:20:38 +00001530 if (aligned > g_stacknleft) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001531 size_t len;
1532 size_t blocksize;
1533 struct stack_block *sp;
1534
1535 blocksize = aligned;
1536 if (blocksize < MINSIZE)
1537 blocksize = MINSIZE;
1538 len = sizeof(struct stack_block) - MINSIZE + blocksize;
1539 if (len < blocksize)
1540 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1541 INT_OFF;
1542 sp = ckmalloc(len);
Denis Vlasenko01631112007-12-16 17:20:38 +00001543 sp->prev = g_stackp;
1544 g_stacknxt = sp->space;
1545 g_stacknleft = blocksize;
1546 sstrend = g_stacknxt + blocksize;
1547 g_stackp = sp;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001548 INT_ON;
1549 }
Denis Vlasenko01631112007-12-16 17:20:38 +00001550 p = g_stacknxt;
1551 g_stacknxt += aligned;
1552 g_stacknleft -= aligned;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001553 return p;
1554}
1555
Denis Vlasenko597906c2008-02-20 16:38:54 +00001556static void *
1557stzalloc(size_t nbytes)
1558{
1559 return memset(stalloc(nbytes), 0, nbytes);
1560}
1561
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001562static void
1563stunalloc(void *p)
1564{
1565#if DEBUG
Denis Vlasenko01631112007-12-16 17:20:38 +00001566 if (!p || (g_stacknxt < (char *)p) || ((char *)p < g_stackp->space)) {
Bernhard Reutner-Fischer5e25ddb2008-05-19 09:48:17 +00001567 write(STDERR_FILENO, "stunalloc\n", 10);
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001568 abort();
1569 }
1570#endif
Denis Vlasenko01631112007-12-16 17:20:38 +00001571 g_stacknleft += g_stacknxt - (char *)p;
1572 g_stacknxt = p;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001573}
1574
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001575/*
1576 * Like strdup but works with the ash stack.
1577 */
1578static char *
Denys Vlasenko8e2bc472016-09-28 23:02:57 +02001579sstrdup(const char *p)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001580{
1581 size_t len = strlen(p) + 1;
1582 return memcpy(stalloc(len), p, len);
1583}
1584
Denys Vlasenko03c36e02018-01-10 15:18:35 +01001585static ALWAYS_INLINE void
Denys Vlasenko60ca8342016-09-30 11:21:21 +02001586grabstackblock(size_t len)
1587{
Denys Vlasenkoa318bba2016-10-26 18:26:27 +02001588 stalloc(len);
Denys Vlasenko60ca8342016-09-30 11:21:21 +02001589}
1590
1591static void
1592pushstackmark(struct stackmark *mark, size_t len)
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001593{
Denis Vlasenko01631112007-12-16 17:20:38 +00001594 mark->stackp = g_stackp;
1595 mark->stacknxt = g_stacknxt;
1596 mark->stacknleft = g_stacknleft;
Denys Vlasenko60ca8342016-09-30 11:21:21 +02001597 grabstackblock(len);
1598}
1599
1600static void
1601setstackmark(struct stackmark *mark)
1602{
1603 pushstackmark(mark, g_stacknxt == g_stackp->space && g_stackp != &stackbase);
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001604}
1605
1606static void
1607popstackmark(struct stackmark *mark)
1608{
1609 struct stack_block *sp;
1610
Denis Vlasenko93ebd4f2007-03-13 20:55:36 +00001611 if (!mark->stackp)
1612 return;
1613
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001614 INT_OFF;
Denis Vlasenko01631112007-12-16 17:20:38 +00001615 while (g_stackp != mark->stackp) {
1616 sp = g_stackp;
1617 g_stackp = sp->prev;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001618 free(sp);
1619 }
Denis Vlasenko01631112007-12-16 17:20:38 +00001620 g_stacknxt = mark->stacknxt;
1621 g_stacknleft = mark->stacknleft;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001622 sstrend = mark->stacknxt + mark->stacknleft;
1623 INT_ON;
1624}
1625
1626/*
1627 * When the parser reads in a string, it wants to stick the string on the
1628 * stack and only adjust the stack pointer when it knows how big the
1629 * string is. Stackblock (defined in stack.h) returns a pointer to a block
1630 * of space on top of the stack and stackblocklen returns the length of
1631 * this block. Growstackblock will grow this space by at least one byte,
1632 * possibly moving it (like realloc). Grabstackblock actually allocates the
1633 * part of the block that has been used.
1634 */
1635static void
1636growstackblock(void)
1637{
1638 size_t newlen;
1639
Denis Vlasenko01631112007-12-16 17:20:38 +00001640 newlen = g_stacknleft * 2;
1641 if (newlen < g_stacknleft)
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001642 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1643 if (newlen < 128)
1644 newlen += 128;
1645
Denis Vlasenko01631112007-12-16 17:20:38 +00001646 if (g_stacknxt == g_stackp->space && g_stackp != &stackbase) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001647 struct stack_block *sp;
1648 struct stack_block *prevstackp;
1649 size_t grosslen;
1650
1651 INT_OFF;
Denis Vlasenko01631112007-12-16 17:20:38 +00001652 sp = g_stackp;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001653 prevstackp = sp->prev;
1654 grosslen = newlen + sizeof(struct stack_block) - MINSIZE;
1655 sp = ckrealloc(sp, grosslen);
1656 sp->prev = prevstackp;
Denis Vlasenko01631112007-12-16 17:20:38 +00001657 g_stackp = sp;
1658 g_stacknxt = sp->space;
1659 g_stacknleft = newlen;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001660 sstrend = sp->space + newlen;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001661 INT_ON;
1662 } else {
Denis Vlasenko01631112007-12-16 17:20:38 +00001663 char *oldspace = g_stacknxt;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001664 size_t oldlen = g_stacknleft;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001665 char *p = stalloc(newlen);
1666
1667 /* free the space we just allocated */
Denis Vlasenko01631112007-12-16 17:20:38 +00001668 g_stacknxt = memcpy(p, oldspace, oldlen);
1669 g_stacknleft += newlen;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001670 }
1671}
1672
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001673/*
1674 * The following routines are somewhat easier to use than the above.
1675 * The user declares a variable of type STACKSTR, which may be declared
1676 * to be a register. The macro STARTSTACKSTR initializes things. Then
1677 * the user uses the macro STPUTC to add characters to the string. In
1678 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
1679 * grown as necessary. When the user is done, she can just leave the
1680 * string there and refer to it using stackblock(). Or she can allocate
1681 * the space for it using grabstackstr(). If it is necessary to allow
1682 * someone else to use the stack temporarily and then continue to grow
1683 * the string, the user should use grabstack to allocate the space, and
1684 * then call ungrabstr(p) to return to the previous mode of operation.
1685 *
1686 * USTPUTC is like STPUTC except that it doesn't check for overflow.
1687 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
1688 * is space for at least one character.
1689 */
1690static void *
1691growstackstr(void)
1692{
1693 size_t len = stackblocksize();
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001694 growstackblock();
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001695 return (char *)stackblock() + len;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001696}
1697
1698/*
1699 * Called from CHECKSTRSPACE.
1700 */
1701static char *
1702makestrspace(size_t newlen, char *p)
1703{
Denis Vlasenko01631112007-12-16 17:20:38 +00001704 size_t len = p - g_stacknxt;
Denys Vlasenko53d6e032016-09-30 11:24:12 +02001705 size_t size;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001706
1707 for (;;) {
1708 size_t nleft;
1709
1710 size = stackblocksize();
1711 nleft = size - len;
1712 if (nleft >= newlen)
1713 break;
1714 growstackblock();
1715 }
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001716 return (char *)stackblock() + len;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001717}
1718
1719static char *
1720stack_nputstr(const char *s, size_t n, char *p)
1721{
1722 p = makestrspace(n, p);
Denys Vlasenko5ace96a2017-07-23 21:46:02 +02001723 p = (char *)mempcpy(p, s, n);
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001724 return p;
1725}
1726
1727static char *
1728stack_putstr(const char *s, char *p)
1729{
1730 return stack_nputstr(s, strlen(s), p);
1731}
1732
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001733static char *
1734_STPUTC(int c, char *p)
1735{
1736 if (p == sstrend)
1737 p = growstackstr();
1738 *p++ = c;
1739 return p;
1740}
1741
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00001742#define STARTSTACKSTR(p) ((p) = stackblock())
1743#define STPUTC(c, p) ((p) = _STPUTC((c), (p)))
Denis Vlasenko843cbd52008-06-27 00:23:18 +00001744#define CHECKSTRSPACE(n, p) do { \
1745 char *q = (p); \
1746 size_t l = (n); \
1747 size_t m = sstrend - q; \
1748 if (l > m) \
1749 (p) = makestrspace(l, q); \
1750} while (0)
Denis Vlasenkoef527f52008-06-23 01:52:30 +00001751#define USTPUTC(c, p) (*(p)++ = (c))
Denis Vlasenko843cbd52008-06-27 00:23:18 +00001752#define STACKSTRNUL(p) do { \
1753 if ((p) == sstrend) \
1754 (p) = growstackstr(); \
1755 *(p) = '\0'; \
1756} while (0)
Denis Vlasenkoef527f52008-06-23 01:52:30 +00001757#define STUNPUTC(p) (--(p))
1758#define STTOPC(p) ((p)[-1])
1759#define STADJUST(amount, p) ((p) += (amount))
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001760
1761#define grabstackstr(p) stalloc((char *)(p) - (char *)stackblock())
Denis Vlasenkoef527f52008-06-23 01:52:30 +00001762#define ungrabstackstr(s, p) stunalloc(s)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001763#define stackstrend() ((void *)sstrend)
1764
1765
1766/* ============ String helpers */
1767
1768/*
1769 * prefix -- see if pfx is a prefix of string.
1770 */
1771static char *
1772prefix(const char *string, const char *pfx)
1773{
1774 while (*pfx) {
1775 if (*pfx++ != *string++)
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00001776 return NULL;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001777 }
1778 return (char *) string;
1779}
1780
1781/*
1782 * Check for a valid number. This should be elsewhere.
1783 */
1784static int
1785is_number(const char *p)
1786{
1787 do {
1788 if (!isdigit(*p))
1789 return 0;
1790 } while (*++p != '\0');
1791 return 1;
1792}
1793
1794/*
1795 * Convert a string of digits to an integer, printing an error message on
1796 * failure.
1797 */
1798static int
1799number(const char *s)
1800{
1801 if (!is_number(s))
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02001802 ash_msg_and_raise_error(msg_illnum, s);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001803 return atoi(s);
1804}
1805
1806/*
Denys Vlasenko42ba7572017-07-21 13:20:14 +02001807 * Produce a single quoted string suitable as input to the shell.
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001808 * The return string is allocated on the stack.
1809 */
1810static char *
1811single_quote(const char *s)
1812{
1813 char *p;
1814
1815 STARTSTACKSTR(p);
1816
1817 do {
1818 char *q;
1819 size_t len;
1820
1821 len = strchrnul(s, '\'') - s;
1822
1823 q = p = makestrspace(len + 3, p);
1824
1825 *q++ = '\'';
Denys Vlasenko94af83e2017-07-23 21:55:40 +02001826 q = (char *)mempcpy(q, s, len);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001827 *q++ = '\'';
1828 s += len;
1829
1830 STADJUST(q - p, p);
1831
Denys Vlasenkocd716832009-11-28 22:14:02 +01001832 if (*s != '\'')
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001833 break;
Denys Vlasenkocd716832009-11-28 22:14:02 +01001834 len = 0;
1835 do len++; while (*++s == '\'');
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001836
1837 q = p = makestrspace(len + 3, p);
1838
1839 *q++ = '"';
Denys Vlasenko5ace96a2017-07-23 21:46:02 +02001840 q = (char *)mempcpy(q, s - len, len);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001841 *q++ = '"';
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001842
1843 STADJUST(q - p, p);
1844 } while (*s);
1845
Denys Vlasenkocd716832009-11-28 22:14:02 +01001846 USTPUTC('\0', p);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001847
1848 return stackblock();
1849}
1850
Denys Vlasenko42ba7572017-07-21 13:20:14 +02001851/*
1852 * Produce a possibly single quoted string suitable as input to the shell.
Denys Vlasenko42ba7572017-07-21 13:20:14 +02001853 * If quoting was done, the return string is allocated on the stack,
1854 * otherwise a pointer to the original string is returned.
1855 */
1856static const char *
1857maybe_single_quote(const char *s)
1858{
1859 const char *p = s;
1860
1861 while (*p) {
1862 /* Assuming ACSII */
1863 /* quote ctrl_chars space !"#$%&'()* */
1864 if (*p < '+')
1865 goto need_quoting;
1866 /* quote ;<=>? */
1867 if (*p >= ';' && *p <= '?')
1868 goto need_quoting;
1869 /* quote `[\ */
1870 if (*p == '`')
1871 goto need_quoting;
1872 if (*p == '[')
1873 goto need_quoting;
1874 if (*p == '\\')
1875 goto need_quoting;
1876 /* quote {|}~ DEL and high bytes */
1877 if (*p > 'z')
1878 goto need_quoting;
1879 /* Not quoting these: +,-./ 0-9 :@ A-Z ]^_ a-z */
1880 /* TODO: maybe avoid quoting % */
1881 p++;
1882 }
1883 return s;
1884
1885 need_quoting:
1886 return single_quote(s);
1887}
1888
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001889
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00001890/* ============ nextopt */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001891
1892static char **argptr; /* argument list for builtin commands */
1893static char *optionarg; /* set by nextopt (like getopt) */
1894static char *optptr; /* used by nextopt */
1895
1896/*
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001897 * XXX - should get rid of. Have all builtins use getopt(3).
1898 * The library getopt must have the BSD extension static variable
1899 * "optreset", otherwise it can't be used within the shell safely.
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001900 *
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001901 * Standard option processing (a la getopt) for builtin routines.
1902 * The only argument that is passed to nextopt is the option string;
1903 * the other arguments are unnecessary. It returns the character,
1904 * or '\0' on end of input.
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001905 */
1906static int
1907nextopt(const char *optstring)
1908{
1909 char *p;
1910 const char *q;
1911 char c;
1912
1913 p = optptr;
1914 if (p == NULL || *p == '\0') {
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001915 /* We ate entire "-param", take next one */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001916 p = *argptr;
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001917 if (p == NULL)
1918 return '\0';
1919 if (*p != '-')
1920 return '\0';
1921 if (*++p == '\0') /* just "-" ? */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001922 return '\0';
1923 argptr++;
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001924 if (LONE_DASH(p)) /* "--" ? */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001925 return '\0';
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001926 /* p => next "-param" */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001927 }
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001928 /* p => some option char in the middle of a "-param" */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001929 c = *p++;
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +00001930 for (q = optstring; *q != c;) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001931 if (*q == '\0')
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00001932 ash_msg_and_raise_error("illegal option -%c", c);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001933 if (*++q == ':')
1934 q++;
1935 }
1936 if (*++q == ':') {
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001937 if (*p == '\0') {
1938 p = *argptr++;
1939 if (p == NULL)
1940 ash_msg_and_raise_error("no arg for -%c option", c);
1941 }
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001942 optionarg = p;
1943 p = NULL;
1944 }
1945 optptr = p;
1946 return c;
1947}
1948
1949
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00001950/* ============ Shell variables */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001951
Denis Vlasenko01631112007-12-16 17:20:38 +00001952struct shparam {
1953 int nparam; /* # of positional parameters (without $0) */
1954#if ENABLE_ASH_GETOPTS
1955 int optind; /* next parameter to be processed by getopts */
1956 int optoff; /* used by getopts */
1957#endif
1958 unsigned char malloced; /* if parameter list dynamically allocated */
1959 char **p; /* parameter list */
1960};
1961
1962/*
1963 * Free the list of positional parameters.
1964 */
1965static void
1966freeparam(volatile struct shparam *param)
1967{
Denis Vlasenko01631112007-12-16 17:20:38 +00001968 if (param->malloced) {
Denis Vlasenko3177ba02008-07-13 20:39:23 +00001969 char **ap, **ap1;
1970 ap = ap1 = param->p;
1971 while (*ap)
1972 free(*ap++);
1973 free(ap1);
Denis Vlasenko01631112007-12-16 17:20:38 +00001974 }
1975}
1976
1977#if ENABLE_ASH_GETOPTS
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02001978static void FAST_FUNC getoptsreset(const char *value);
Denis Vlasenko01631112007-12-16 17:20:38 +00001979#endif
1980
1981struct var {
1982 struct var *next; /* next entry in hash list */
1983 int flags; /* flags are defined above */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001984 const char *var_text; /* name=value */
1985 void (*var_func)(const char *) FAST_FUNC; /* function to be called when */
Denis Vlasenko01631112007-12-16 17:20:38 +00001986 /* the variable gets set/unset */
1987};
1988
1989struct localvar {
1990 struct localvar *next; /* next local variable in list */
1991 struct var *vp; /* the variable that was made local */
1992 int flags; /* saved flags */
1993 const char *text; /* saved text */
1994};
1995
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001996/* flags */
1997#define VEXPORT 0x01 /* variable is exported */
1998#define VREADONLY 0x02 /* variable cannot be modified */
1999#define VSTRFIXED 0x04 /* variable struct is statically allocated */
2000#define VTEXTFIXED 0x08 /* text is statically allocated */
2001#define VSTACK 0x10 /* text is allocated on the stack */
2002#define VUNSET 0x20 /* the variable is not set */
2003#define VNOFUNC 0x40 /* don't call the callback function */
2004#define VNOSET 0x80 /* do not set variable - just readonly test */
2005#define VNOSAVE 0x100 /* when text is on the heap before setvareq */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00002006#if ENABLE_ASH_RANDOM_SUPPORT
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00002007# define VDYNAMIC 0x200 /* dynamic variable */
2008#else
2009# define VDYNAMIC 0
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002010#endif
2011
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00002012
Denis Vlasenko01631112007-12-16 17:20:38 +00002013/* Need to be before varinit_data[] */
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00002014#if ENABLE_LOCALE_SUPPORT
Denys Vlasenko2634bf32009-06-09 18:40:07 +02002015static void FAST_FUNC
Denis Vlasenkoa8915072007-02-23 21:10:06 +00002016change_lc_all(const char *value)
2017{
2018 if (value && *value != '\0')
2019 setlocale(LC_ALL, value);
2020}
Denys Vlasenko2634bf32009-06-09 18:40:07 +02002021static void FAST_FUNC
Denis Vlasenkoa8915072007-02-23 21:10:06 +00002022change_lc_ctype(const char *value)
2023{
2024 if (value && *value != '\0')
2025 setlocale(LC_CTYPE, value);
2026}
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00002027#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002028#if ENABLE_ASH_MAIL
2029static void chkmail(void);
Denys Vlasenko8c52f802011-02-04 17:36:21 +01002030static void changemail(const char *var_value) FAST_FUNC;
2031#else
2032# define chkmail() ((void)0)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002033#endif
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02002034static void changepath(const char *) FAST_FUNC;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002035#if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02002036static void change_random(const char *) FAST_FUNC;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002037#endif
2038
Denis Vlasenko01631112007-12-16 17:20:38 +00002039static const struct {
2040 int flags;
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002041 const char *var_text;
2042 void (*var_func)(const char *) FAST_FUNC;
Denis Vlasenko01631112007-12-16 17:20:38 +00002043} varinit_data[] = {
Denys Vlasenko566a3132012-07-07 21:40:35 +02002044 /*
2045 * Note: VEXPORT would not work correctly here for NOFORK applets:
2046 * some environment strings may be constant.
2047 */
Denis Vlasenko01631112007-12-16 17:20:38 +00002048 { VSTRFIXED|VTEXTFIXED , defifsvar , NULL },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002049#if ENABLE_ASH_MAIL
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002050 { VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL" , changemail },
2051 { VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH" , changemail },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002052#endif
Denis Vlasenko01631112007-12-16 17:20:38 +00002053 { VSTRFIXED|VTEXTFIXED , bb_PATH_root_path, changepath },
2054 { VSTRFIXED|VTEXTFIXED , "PS1=$ " , NULL },
2055 { VSTRFIXED|VTEXTFIXED , "PS2=> " , NULL },
2056 { VSTRFIXED|VTEXTFIXED , "PS4=+ " , NULL },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002057#if ENABLE_ASH_GETOPTS
Denys Vlasenkoe627ac92016-09-30 14:36:59 +02002058 { VSTRFIXED|VTEXTFIXED , defoptindvar, getoptsreset },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002059#endif
Denys Vlasenko675d24a2018-01-27 22:02:05 +01002060 { VSTRFIXED|VTEXTFIXED , NULL /* inited to linenovar */, NULL },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002061#if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002062 { VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM", change_random },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002063#endif
2064#if ENABLE_LOCALE_SUPPORT
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002065 { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_ALL" , change_lc_all },
2066 { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_CTYPE" , change_lc_ctype },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002067#endif
2068#if ENABLE_FEATURE_EDITING_SAVEHISTORY
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002069 { VSTRFIXED|VTEXTFIXED|VUNSET, "HISTFILE" , NULL },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002070#endif
2071};
2072
Denis Vlasenko0b769642008-07-24 07:54:57 +00002073struct redirtab;
Denis Vlasenko01631112007-12-16 17:20:38 +00002074
2075struct globals_var {
2076 struct shparam shellparam; /* $@ current positional parameters */
2077 struct redirtab *redirlist;
Denys Vlasenkod07a15b2017-07-30 16:51:05 +02002078 int preverrout_fd; /* stderr fd: usually 2, unless redirect moved it */
Denis Vlasenko01631112007-12-16 17:20:38 +00002079 struct var *vartab[VTABSIZE];
2080 struct var varinit[ARRAY_SIZE(varinit_data)];
Denys Vlasenko675d24a2018-01-27 22:02:05 +01002081 int lineno;
2082 char linenovar[sizeof("LINENO=") + sizeof(int)*3];
Denis Vlasenko01631112007-12-16 17:20:38 +00002083};
Denys Vlasenko6f9442f2018-01-28 20:41:23 +01002084extern struct globals_var *BB_GLOBAL_CONST ash_ptr_to_globals_var;
Denis Vlasenko574f2f42008-02-27 18:41:59 +00002085#define G_var (*ash_ptr_to_globals_var)
Denis Vlasenko01631112007-12-16 17:20:38 +00002086#define shellparam (G_var.shellparam )
Denis Vlasenko0b769642008-07-24 07:54:57 +00002087//#define redirlist (G_var.redirlist )
Denis Vlasenko01631112007-12-16 17:20:38 +00002088#define preverrout_fd (G_var.preverrout_fd)
2089#define vartab (G_var.vartab )
2090#define varinit (G_var.varinit )
Denys Vlasenko675d24a2018-01-27 22:02:05 +01002091#define lineno (G_var.lineno )
2092#define linenovar (G_var.linenovar )
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002093#define vifs varinit[0]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002094#if ENABLE_ASH_MAIL
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002095# define vmail (&vifs)[1]
2096# define vmpath (&vmail)[1]
2097# define vpath (&vmpath)[1]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002098#else
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002099# define vpath (&vifs)[1]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002100#endif
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002101#define vps1 (&vpath)[1]
2102#define vps2 (&vps1)[1]
2103#define vps4 (&vps2)[1]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002104#if ENABLE_ASH_GETOPTS
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002105# define voptind (&vps4)[1]
Denys Vlasenko675d24a2018-01-27 22:02:05 +01002106# define vlineno (&voptind)[1]
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002107# if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenko675d24a2018-01-27 22:02:05 +01002108# define vrandom (&vlineno)[1]
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002109# endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002110#else
Denys Vlasenko675d24a2018-01-27 22:02:05 +01002111# define vlineno (&vps4)[1]
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002112# if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenko675d24a2018-01-27 22:02:05 +01002113# define vrandom (&vlineno)[1]
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002114# endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002115#endif
Denys Vlasenko675d24a2018-01-27 22:02:05 +01002116#define INIT_G_var() do { \
2117 unsigned i; \
2118 (*(struct globals_var**)&ash_ptr_to_globals_var) = xzalloc(sizeof(G_var)); \
2119 barrier(); \
2120 for (i = 0; i < ARRAY_SIZE(varinit_data); i++) { \
2121 varinit[i].flags = varinit_data[i].flags; \
2122 varinit[i].var_text = varinit_data[i].var_text; \
2123 varinit[i].var_func = varinit_data[i].var_func; \
2124 } \
2125 strcpy(linenovar, "LINENO="); \
2126 vlineno.var_text = linenovar; \
2127} while (0)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002128
2129/*
2130 * The following macros access the values of the above variables.
2131 * They have to skip over the name. They return the null string
2132 * for unset variables.
2133 */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002134#define ifsval() (vifs.var_text + 4)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002135#define ifsset() ((vifs.flags & VUNSET) == 0)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002136#if ENABLE_ASH_MAIL
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002137# define mailval() (vmail.var_text + 5)
2138# define mpathval() (vmpath.var_text + 9)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002139# define mpathset() ((vmpath.flags & VUNSET) == 0)
2140#endif
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002141#define pathval() (vpath.var_text + 5)
2142#define ps1val() (vps1.var_text + 4)
2143#define ps2val() (vps2.var_text + 4)
2144#define ps4val() (vps4.var_text + 4)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002145#if ENABLE_ASH_GETOPTS
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002146# define optindval() (voptind.var_text + 7)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002147#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002148
Denis Vlasenko01631112007-12-16 17:20:38 +00002149#if ENABLE_ASH_GETOPTS
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02002150static void FAST_FUNC
Denis Vlasenko01631112007-12-16 17:20:38 +00002151getoptsreset(const char *value)
2152{
Denys Vlasenko46289452017-08-11 00:59:36 +02002153 shellparam.optind = 1;
2154 if (is_number(value))
2155 shellparam.optind = number(value) ?: 1;
Denis Vlasenko01631112007-12-16 17:20:38 +00002156 shellparam.optoff = -1;
2157}
2158#endif
2159
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002160/*
2161 * Compares two strings up to the first = or '\0'. The first
2162 * string must be terminated by '='; the second may be terminated by
2163 * either '=' or '\0'.
2164 */
2165static int
2166varcmp(const char *p, const char *q)
2167{
2168 int c, d;
2169
2170 while ((c = *p) == (d = *q)) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02002171 if (c == '\0' || c == '=')
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002172 goto out;
2173 p++;
2174 q++;
2175 }
2176 if (c == '=')
Denis Vlasenko9650f362007-02-23 01:04:37 +00002177 c = '\0';
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002178 if (d == '=')
Denis Vlasenko9650f362007-02-23 01:04:37 +00002179 d = '\0';
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002180 out:
2181 return c - d;
2182}
2183
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002184/*
2185 * Find the appropriate entry in the hash table from the name.
2186 */
2187static struct var **
2188hashvar(const char *p)
2189{
2190 unsigned hashval;
2191
2192 hashval = ((unsigned char) *p) << 4;
2193 while (*p && *p != '=')
2194 hashval += (unsigned char) *p++;
2195 return &vartab[hashval % VTABSIZE];
2196}
2197
2198static int
2199vpcmp(const void *a, const void *b)
2200{
2201 return varcmp(*(const char **)a, *(const char **)b);
2202}
2203
2204/*
2205 * This routine initializes the builtin variables.
2206 */
2207static void
2208initvar(void)
2209{
2210 struct var *vp;
2211 struct var *end;
2212 struct var **vpp;
2213
2214 /*
2215 * PS1 depends on uid
2216 */
2217#if ENABLE_FEATURE_EDITING && ENABLE_FEATURE_EDITING_FANCY_PROMPT
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002218 vps1.var_text = "PS1=\\w \\$ ";
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002219#else
2220 if (!geteuid())
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002221 vps1.var_text = "PS1=# ";
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002222#endif
2223 vp = varinit;
Denis Vlasenko80b8b392007-06-25 10:55:35 +00002224 end = vp + ARRAY_SIZE(varinit);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002225 do {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002226 vpp = hashvar(vp->var_text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002227 vp->next = *vpp;
2228 *vpp = vp;
2229 } while (++vp < end);
2230}
2231
2232static struct var **
2233findvar(struct var **vpp, const char *name)
2234{
2235 for (; *vpp; vpp = &(*vpp)->next) {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002236 if (varcmp((*vpp)->var_text, name) == 0) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002237 break;
2238 }
2239 }
2240 return vpp;
2241}
2242
2243/*
2244 * Find the value of a variable. Returns NULL if not set.
2245 */
Denys Vlasenko03dad222010-01-12 23:29:57 +01002246static const char* FAST_FUNC
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002247lookupvar(const char *name)
2248{
2249 struct var *v;
2250
2251 v = *findvar(hashvar(name), name);
2252 if (v) {
Denis Vlasenko448d30e2008-06-27 00:24:11 +00002253#if ENABLE_ASH_RANDOM_SUPPORT
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002254 /*
2255 * Dynamic variables are implemented roughly the same way they are
2256 * in bash. Namely, they're "special" so long as they aren't unset.
2257 * As soon as they're unset, they're no longer dynamic, and dynamic
2258 * lookup will no longer happen at that point. -- PFM.
2259 */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002260 if (v->flags & VDYNAMIC)
2261 v->var_func(NULL);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002262#endif
Denys Vlasenko675d24a2018-01-27 22:02:05 +01002263 if (!(v->flags & VUNSET)) {
2264 if (v == &vlineno && v->var_text == linenovar) {
2265 fmtstr(linenovar+7, sizeof(linenovar)-7, "%d", lineno);
2266 }
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002267 return var_end(v->var_text);
Denys Vlasenko675d24a2018-01-27 22:02:05 +01002268 }
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002269 }
2270 return NULL;
2271}
2272
Denys Vlasenko0b883582016-12-23 16:49:07 +01002273#if ENABLE_UNICODE_SUPPORT
Denys Vlasenko37dc08b2016-10-02 04:38:07 +02002274static void
2275reinit_unicode_for_ash(void)
Denys Vlasenkoe9ab07c2014-08-13 18:00:08 +02002276{
2277 /* Unicode support should be activated even if LANG is set
2278 * _during_ shell execution, not only if it was set when
2279 * shell was started. Therefore, re-check LANG every time:
2280 */
2281 if (ENABLE_FEATURE_CHECK_UNICODE_IN_ENV
2282 || ENABLE_UNICODE_USING_LOCALE
2283 ) {
2284 const char *s = lookupvar("LC_ALL");
2285 if (!s) s = lookupvar("LC_CTYPE");
2286 if (!s) s = lookupvar("LANG");
2287 reinit_unicode(s);
2288 }
2289}
Denys Vlasenko0b883582016-12-23 16:49:07 +01002290#else
2291# define reinit_unicode_for_ash() ((void)0)
2292#endif
Denys Vlasenkoe9ab07c2014-08-13 18:00:08 +02002293
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002294/*
2295 * Search the environment of a builtin command.
2296 */
Denys Vlasenko488e6092017-07-26 23:08:36 +02002297static ALWAYS_INLINE const char *
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002298bltinlookup(const char *name)
2299{
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002300 return lookupvar(name);
2301}
2302
2303/*
2304 * Same as setvar except that the variable and value are passed in
2305 * the first argument as name=value. Since the first argument will
2306 * be actually stored in the table, it should not be a string that
2307 * will go away.
2308 * Called with interrupts off.
2309 */
Denys Vlasenkod04fc712017-07-26 20:06:48 +02002310static struct var *
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002311setvareq(char *s, int flags)
2312{
2313 struct var *vp, **vpp;
2314
2315 vpp = hashvar(s);
2316 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
Denys Vlasenkod04fc712017-07-26 20:06:48 +02002317 vpp = findvar(vpp, s);
2318 vp = *vpp;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002319 if (vp) {
2320 if ((vp->flags & (VREADONLY|VDYNAMIC)) == VREADONLY) {
2321 const char *n;
2322
2323 if (flags & VNOSAVE)
2324 free(s);
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002325 n = vp->var_text;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +02002326 exitstatus = 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002327 ash_msg_and_raise_error("%.*s: is read only", strchrnul(n, '=') - n, n);
2328 }
2329
2330 if (flags & VNOSET)
Denys Vlasenkod04fc712017-07-26 20:06:48 +02002331 goto out;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002332
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002333 if (vp->var_func && !(flags & VNOFUNC))
2334 vp->var_func(var_end(s));
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002335
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002336 if (!(vp->flags & (VTEXTFIXED|VSTACK)))
2337 free((char*)vp->var_text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002338
Denys Vlasenkob28d4c32017-07-25 16:29:36 +02002339 if (((flags & (VEXPORT|VREADONLY|VSTRFIXED|VUNSET)) | (vp->flags & VSTRFIXED)) == VUNSET) {
2340 *vpp = vp->next;
2341 free(vp);
2342 out_free:
2343 if ((flags & (VTEXTFIXED|VSTACK|VNOSAVE)) == VNOSAVE)
2344 free(s);
Denys Vlasenkod04fc712017-07-26 20:06:48 +02002345 goto out;
Denys Vlasenkob28d4c32017-07-25 16:29:36 +02002346 }
2347
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002348 flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
2349 } else {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002350 /* variable s is not found */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002351 if (flags & VNOSET)
Denys Vlasenkod04fc712017-07-26 20:06:48 +02002352 goto out;
Denys Vlasenkob28d4c32017-07-25 16:29:36 +02002353 if ((flags & (VEXPORT|VREADONLY|VSTRFIXED|VUNSET)) == VUNSET)
2354 goto out_free;
Denis Vlasenko597906c2008-02-20 16:38:54 +00002355 vp = ckzalloc(sizeof(*vp));
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002356 vp->next = *vpp;
Denis Vlasenko597906c2008-02-20 16:38:54 +00002357 /*vp->func = NULL; - ckzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002358 *vpp = vp;
2359 }
2360 if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE)))
2361 s = ckstrdup(s);
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002362 vp->var_text = s;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002363 vp->flags = flags;
Denys Vlasenkod04fc712017-07-26 20:06:48 +02002364
2365 out:
2366 return vp;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002367}
2368
2369/*
2370 * Set the value of a variable. The flags argument is ored with the
2371 * flags of the variable. If val is NULL, the variable is unset.
2372 */
Denys Vlasenkod04fc712017-07-26 20:06:48 +02002373static struct var *
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002374setvar(const char *name, const char *val, int flags)
2375{
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002376 const char *q;
2377 char *p;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002378 char *nameeq;
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002379 size_t namelen;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002380 size_t vallen;
Denys Vlasenkod04fc712017-07-26 20:06:48 +02002381 struct var *vp;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002382
2383 q = endofname(name);
2384 p = strchrnul(q, '=');
2385 namelen = p - name;
2386 if (!namelen || p != q)
2387 ash_msg_and_raise_error("%.*s: bad variable name", namelen, name);
2388 vallen = 0;
2389 if (val == NULL) {
2390 flags |= VUNSET;
2391 } else {
2392 vallen = strlen(val);
2393 }
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002394
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002395 INT_OFF;
2396 nameeq = ckmalloc(namelen + vallen + 2);
Denys Vlasenkoda2244f2017-07-21 18:51:29 +02002397 p = mempcpy(nameeq, name, namelen);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002398 if (val) {
2399 *p++ = '=';
Denys Vlasenkoda2244f2017-07-21 18:51:29 +02002400 p = mempcpy(p, val, vallen);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002401 }
2402 *p = '\0';
Denys Vlasenkod04fc712017-07-26 20:06:48 +02002403 vp = setvareq(nameeq, flags | VNOSAVE);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002404 INT_ON;
Denys Vlasenkod04fc712017-07-26 20:06:48 +02002405
2406 return vp;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002407}
2408
Denys Vlasenko03dad222010-01-12 23:29:57 +01002409static void FAST_FUNC
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02002410setvar0(const char *name, const char *val)
Denys Vlasenko03dad222010-01-12 23:29:57 +01002411{
2412 setvar(name, val, 0);
2413}
2414
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002415/*
2416 * Unset the specified variable.
2417 */
Denys Vlasenkob28d4c32017-07-25 16:29:36 +02002418static void
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002419unsetvar(const char *s)
2420{
Denys Vlasenkocf3a7962017-07-26 14:38:19 +02002421 setvar(s, NULL, 0);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002422}
2423
2424/*
2425 * Process a linked list of variable assignments.
2426 */
2427static void
2428listsetvar(struct strlist *list_set_var, int flags)
2429{
2430 struct strlist *lp = list_set_var;
2431
2432 if (!lp)
2433 return;
2434 INT_OFF;
2435 do {
2436 setvareq(lp->text, flags);
Denis Vlasenko9650f362007-02-23 01:04:37 +00002437 lp = lp->next;
2438 } while (lp);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002439 INT_ON;
2440}
2441
2442/*
2443 * Generate a list of variables satisfying the given conditions.
2444 */
Denys Vlasenkoa5060b82017-11-03 14:16:25 +01002445#if !ENABLE_FEATURE_SH_NOFORK
2446# define listvars(on, off, lp, end) listvars(on, off, end)
2447#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002448static char **
Denys Vlasenkoa5060b82017-11-03 14:16:25 +01002449listvars(int on, int off, struct strlist *lp, char ***end)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002450{
2451 struct var **vpp;
2452 struct var *vp;
2453 char **ep;
2454 int mask;
2455
2456 STARTSTACKSTR(ep);
2457 vpp = vartab;
2458 mask = on | off;
2459 do {
2460 for (vp = *vpp; vp; vp = vp->next) {
2461 if ((vp->flags & mask) == on) {
Denys Vlasenkoa5060b82017-11-03 14:16:25 +01002462#if ENABLE_FEATURE_SH_NOFORK
2463 /* If variable with the same name is both
2464 * exported and temporarily set for a command:
2465 * export ZVAR=5
2466 * ZVAR=6 printenv
2467 * then "ZVAR=6" will be both in vartab and
2468 * lp lists. Do not pass it twice to printenv.
2469 */
2470 struct strlist *lp1 = lp;
2471 while (lp1) {
2472 if (strcmp(lp1->text, vp->var_text) == 0)
2473 goto skip;
2474 lp1 = lp1->next;
2475 }
2476#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002477 if (ep == stackstrend())
2478 ep = growstackstr();
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002479 *ep++ = (char*)vp->var_text;
Denys Vlasenkoa5060b82017-11-03 14:16:25 +01002480#if ENABLE_FEATURE_SH_NOFORK
2481 skip: ;
2482#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002483 }
2484 }
2485 } while (++vpp < vartab + VTABSIZE);
Denys Vlasenkoa5060b82017-11-03 14:16:25 +01002486
2487#if ENABLE_FEATURE_SH_NOFORK
2488 while (lp) {
2489 if (ep == stackstrend())
2490 ep = growstackstr();
2491 *ep++ = lp->text;
2492 lp = lp->next;
2493 }
2494#endif
2495
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002496 if (ep == stackstrend())
2497 ep = growstackstr();
2498 if (end)
2499 *end = ep;
2500 *ep++ = NULL;
2501 return grabstackstr(ep);
2502}
2503
2504
2505/* ============ Path search helper
2506 *
2507 * The variable path (passed by reference) should be set to the start
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002508 * of the path before the first call; path_advance will update
2509 * this value as it proceeds. Successive calls to path_advance will return
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002510 * the possible path expansions in sequence. If an option (indicated by
2511 * a percent sign) appears in the path entry then the global variable
2512 * pathopt will be set to point to it; otherwise pathopt will be set to
2513 * NULL.
2514 */
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002515static const char *pathopt; /* set by path_advance */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002516
2517static char *
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002518path_advance(const char **path, const char *name)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002519{
2520 const char *p;
2521 char *q;
2522 const char *start;
2523 size_t len;
2524
2525 if (*path == NULL)
2526 return NULL;
2527 start = *path;
Denis Vlasenkof7d56652008-03-25 05:51:41 +00002528 for (p = start; *p && *p != ':' && *p != '%'; p++)
2529 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002530 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
2531 while (stackblocksize() < len)
2532 growstackblock();
2533 q = stackblock();
2534 if (p != start) {
Denys Vlasenko5ace96a2017-07-23 21:46:02 +02002535 q = mempcpy(q, start, p - start);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002536 *q++ = '/';
2537 }
2538 strcpy(q, name);
2539 pathopt = NULL;
2540 if (*p == '%') {
2541 pathopt = ++p;
Denis Vlasenkof7d56652008-03-25 05:51:41 +00002542 while (*p && *p != ':')
2543 p++;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002544 }
2545 if (*p == ':')
2546 *path = p + 1;
2547 else
2548 *path = NULL;
2549 return stalloc(len);
2550}
2551
2552
2553/* ============ Prompt */
2554
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +00002555static smallint doprompt; /* if set, prompt the user */
2556static smallint needprompt; /* true if interactive and at start of line */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002557
2558#if ENABLE_FEATURE_EDITING
2559static line_input_t *line_input_state;
2560static const char *cmdedit_prompt;
2561static void
2562putprompt(const char *s)
2563{
2564 if (ENABLE_ASH_EXPAND_PRMT) {
2565 free((char*)cmdedit_prompt);
Denis Vlasenko4222ae42007-02-25 02:37:49 +00002566 cmdedit_prompt = ckstrdup(s);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002567 return;
2568 }
2569 cmdedit_prompt = s;
2570}
2571#else
2572static void
2573putprompt(const char *s)
2574{
2575 out2str(s);
2576}
2577#endif
2578
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002579/* expandstr() needs parsing machinery, so it is far away ahead... */
Denys Vlasenko46999802017-07-29 21:12:29 +02002580static const char *expandstr(const char *ps, int syntax_type);
2581/* Values for syntax param */
2582#define BASESYNTAX 0 /* not in quotes */
2583#define DQSYNTAX 1 /* in double quotes */
2584#define SQSYNTAX 2 /* in single quotes */
2585#define ARISYNTAX 3 /* in arithmetic */
Denys Vlasenko5f0a75f2017-07-29 22:58:44 +02002586#if ENABLE_ASH_EXPAND_PRMT
2587# define PSSYNTAX 4 /* prompt. never passed to SIT() */
2588#endif
Denys Vlasenko46999802017-07-29 21:12:29 +02002589/* PSSYNTAX expansion is identical to DQSYNTAX, except keeping '\$' as '\$' */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002590
Denys Vlasenko46999802017-07-29 21:12:29 +02002591/*
2592 * called by editline -- any expansions to the prompt should be added here.
2593 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002594static void
Denys Vlasenko958581a2010-09-12 15:04:27 +02002595setprompt_if(smallint do_set, int whichprompt)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002596{
2597 const char *prompt;
Denys Vlasenko958581a2010-09-12 15:04:27 +02002598 IF_ASH_EXPAND_PRMT(struct stackmark smark;)
2599
2600 if (!do_set)
2601 return;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002602
2603 needprompt = 0;
2604
2605 switch (whichprompt) {
2606 case 1:
2607 prompt = ps1val();
2608 break;
2609 case 2:
2610 prompt = ps2val();
2611 break;
2612 default: /* 0 */
2613 prompt = nullstr;
2614 }
2615#if ENABLE_ASH_EXPAND_PRMT
Denys Vlasenko60ca8342016-09-30 11:21:21 +02002616 pushstackmark(&smark, stackblocksize());
Denys Vlasenko46999802017-07-29 21:12:29 +02002617 putprompt(expandstr(prompt, PSSYNTAX));
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002618 popstackmark(&smark);
Denys Vlasenko48c803a2017-07-01 23:24:48 +02002619#else
2620 putprompt(prompt);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002621#endif
2622}
2623
2624
2625/* ============ The cd and pwd commands */
2626
2627#define CD_PHYSICAL 1
2628#define CD_PRINT 2
2629
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002630static int
2631cdopt(void)
2632{
2633 int flags = 0;
2634 int i, j;
2635
2636 j = 'L';
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02002637 while ((i = nextopt("LP")) != '\0') {
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002638 if (i != j) {
2639 flags ^= CD_PHYSICAL;
2640 j = i;
2641 }
2642 }
2643
2644 return flags;
2645}
2646
2647/*
2648 * Update curdir (the name of the current directory) in response to a
2649 * cd command.
2650 */
2651static const char *
2652updatepwd(const char *dir)
2653{
2654 char *new;
2655 char *p;
2656 char *cdcomppath;
2657 const char *lim;
2658
Denys Vlasenko8e2bc472016-09-28 23:02:57 +02002659 cdcomppath = sstrdup(dir);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002660 STARTSTACKSTR(new);
2661 if (*dir != '/') {
2662 if (curdir == nullstr)
2663 return 0;
2664 new = stack_putstr(curdir, new);
2665 }
2666 new = makestrspace(strlen(dir) + 2, new);
Denis Vlasenko29eb3592008-05-18 14:06:08 +00002667 lim = (char *)stackblock() + 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002668 if (*dir != '/') {
2669 if (new[-1] != '/')
2670 USTPUTC('/', new);
2671 if (new > lim && *lim == '/')
2672 lim++;
2673 } else {
2674 USTPUTC('/', new);
2675 cdcomppath++;
2676 if (dir[1] == '/' && dir[2] != '/') {
2677 USTPUTC('/', new);
2678 cdcomppath++;
2679 lim++;
2680 }
2681 }
2682 p = strtok(cdcomppath, "/");
2683 while (p) {
2684 switch (*p) {
2685 case '.':
2686 if (p[1] == '.' && p[2] == '\0') {
2687 while (new > lim) {
2688 STUNPUTC(new);
2689 if (new[-1] == '/')
2690 break;
2691 }
2692 break;
Denis Vlasenko16abcd92007-04-13 23:59:52 +00002693 }
2694 if (p[1] == '\0')
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002695 break;
2696 /* fall through */
2697 default:
2698 new = stack_putstr(p, new);
2699 USTPUTC('/', new);
2700 }
Denys Vlasenko00da72b2015-10-23 18:43:16 +02002701 p = strtok(NULL, "/");
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002702 }
2703 if (new > lim)
2704 STUNPUTC(new);
2705 *new = 0;
2706 return stackblock();
2707}
2708
2709/*
2710 * Find out what the current directory is. If we already know the current
2711 * directory, this routine returns immediately.
2712 */
2713static char *
2714getpwd(void)
2715{
Denis Vlasenko01631112007-12-16 17:20:38 +00002716 char *dir = getcwd(NULL, 0); /* huh, using glibc extension? */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002717 return dir ? dir : nullstr;
2718}
2719
2720static void
2721setpwd(const char *val, int setold)
2722{
2723 char *oldcur, *dir;
2724
2725 oldcur = dir = curdir;
2726
2727 if (setold) {
2728 setvar("OLDPWD", oldcur, VEXPORT);
2729 }
2730 INT_OFF;
2731 if (physdir != nullstr) {
2732 if (physdir != oldcur)
2733 free(physdir);
2734 physdir = nullstr;
2735 }
2736 if (oldcur == val || !val) {
2737 char *s = getpwd();
2738 physdir = s;
2739 if (!val)
2740 dir = s;
2741 } else
2742 dir = ckstrdup(val);
2743 if (oldcur != dir && oldcur != nullstr) {
2744 free(oldcur);
2745 }
2746 curdir = dir;
2747 INT_ON;
2748 setvar("PWD", dir, VEXPORT);
2749}
2750
2751static void hashcd(void);
2752
2753/*
Denys Vlasenko70392332016-10-27 02:31:55 +02002754 * Actually do the chdir. We also call hashcd to let other routines
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002755 * know that the current directory has changed.
2756 */
2757static int
2758docd(const char *dest, int flags)
2759{
Denys Vlasenko4b1100e2010-03-05 14:10:54 +01002760 const char *dir = NULL;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002761 int err;
2762
2763 TRACE(("docd(\"%s\", %d) called\n", dest, flags));
2764
2765 INT_OFF;
2766 if (!(flags & CD_PHYSICAL)) {
2767 dir = updatepwd(dest);
2768 if (dir)
2769 dest = dir;
2770 }
2771 err = chdir(dest);
2772 if (err)
2773 goto out;
2774 setpwd(dir, 1);
2775 hashcd();
2776 out:
2777 INT_ON;
2778 return err;
2779}
2780
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02002781static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00002782cdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002783{
2784 const char *dest;
2785 const char *path;
2786 const char *p;
2787 char c;
2788 struct stat statb;
2789 int flags;
2790
2791 flags = cdopt();
2792 dest = *argptr;
2793 if (!dest)
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02002794 dest = bltinlookup("HOME");
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002795 else if (LONE_DASH(dest)) {
2796 dest = bltinlookup("OLDPWD");
2797 flags |= CD_PRINT;
2798 }
2799 if (!dest)
2800 dest = nullstr;
2801 if (*dest == '/')
Denys Vlasenko0e081d02016-10-26 19:56:05 +02002802 goto step6;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002803 if (*dest == '.') {
2804 c = dest[1];
2805 dotdot:
2806 switch (c) {
2807 case '\0':
2808 case '/':
2809 goto step6;
2810 case '.':
2811 c = dest[2];
2812 if (c != '.')
2813 goto dotdot;
2814 }
2815 }
2816 if (!*dest)
2817 dest = ".";
2818 path = bltinlookup("CDPATH");
Denys Vlasenko0e081d02016-10-26 19:56:05 +02002819 while (path) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002820 c = *path;
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002821 p = path_advance(&path, dest);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002822 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
2823 if (c && c != ':')
2824 flags |= CD_PRINT;
2825 docd:
2826 if (!docd(p, flags))
2827 goto out;
Denys Vlasenko0e081d02016-10-26 19:56:05 +02002828 goto err;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002829 }
Denys Vlasenko0e081d02016-10-26 19:56:05 +02002830 }
2831
2832 step6:
2833 p = dest;
2834 goto docd;
2835
2836 err:
Johannes Schindelin687aac02017-08-22 22:03:22 +02002837 ash_msg_and_raise_perror("can't cd to %s", dest);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002838 /* NOTREACHED */
2839 out:
2840 if (flags & CD_PRINT)
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02002841 out1fmt("%s\n", curdir);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002842 return 0;
2843}
2844
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02002845static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00002846pwdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002847{
2848 int flags;
2849 const char *dir = curdir;
2850
2851 flags = cdopt();
2852 if (flags) {
2853 if (physdir == nullstr)
2854 setpwd(dir, 0);
2855 dir = physdir;
2856 }
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02002857 out1fmt("%s\n", dir);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002858 return 0;
2859}
2860
Denis Vlasenko0c032a42007-02-23 01:03:40 +00002861
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00002862/* ============ ... */
Eric Andersenc470f442003-07-28 09:56:35 +00002863
Denis Vlasenko834dee72008-10-07 09:18:30 +00002864
Denys Vlasenko82dd14a2010-05-17 10:10:01 +02002865#define IBUFSIZ (ENABLE_FEATURE_EDITING ? CONFIG_FEATURE_EDITING_MAX_LEN : 1024)
Eric Andersenc470f442003-07-28 09:56:35 +00002866
Eric Andersenc470f442003-07-28 09:56:35 +00002867/* Syntax classes */
Denis Vlasenko834dee72008-10-07 09:18:30 +00002868#define CWORD 0 /* character is nothing special */
2869#define CNL 1 /* newline character */
2870#define CBACK 2 /* a backslash character */
2871#define CSQUOTE 3 /* single quote */
2872#define CDQUOTE 4 /* double quote */
Eric Andersenc470f442003-07-28 09:56:35 +00002873#define CENDQUOTE 5 /* a terminating quote */
Denis Vlasenko834dee72008-10-07 09:18:30 +00002874#define CBQUOTE 6 /* backwards single quote */
2875#define CVAR 7 /* a dollar sign */
2876#define CENDVAR 8 /* a '}' character */
2877#define CLP 9 /* a left paren in arithmetic */
2878#define CRP 10 /* a right paren in arithmetic */
Eric Andersenc470f442003-07-28 09:56:35 +00002879#define CENDFILE 11 /* end of file */
Denis Vlasenko834dee72008-10-07 09:18:30 +00002880#define CCTL 12 /* like CWORD, except it must be escaped */
2881#define CSPCL 13 /* these terminate a word */
2882#define CIGN 14 /* character should be ignored */
Eric Andersenc470f442003-07-28 09:56:35 +00002883
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002884#define PEOF 256
Denis Vlasenko131ae172007-02-18 13:00:19 +00002885#if ENABLE_ASH_ALIAS
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002886# define PEOA 257
Eric Andersenc470f442003-07-28 09:56:35 +00002887#endif
2888
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002889#define USE_SIT_FUNCTION ENABLE_ASH_OPTIMIZE_FOR_SIZE
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002890
Denys Vlasenko0b883582016-12-23 16:49:07 +01002891#if ENABLE_FEATURE_SH_MATH
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002892# define SIT_ITEM(a,b,c,d) (a | (b << 4) | (c << 8) | (d << 12))
Eric Andersenc470f442003-07-28 09:56:35 +00002893#else
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002894# define SIT_ITEM(a,b,c,d) (a | (b << 4) | (c << 8))
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002895#endif
Denys Vlasenko3e134eb2016-04-22 18:09:21 +02002896static const uint16_t S_I_T[] ALIGN2 = {
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002897#if ENABLE_ASH_ALIAS
2898 SIT_ITEM(CSPCL , CIGN , CIGN , CIGN ), /* 0, PEOA */
2899#endif
2900 SIT_ITEM(CSPCL , CWORD , CWORD, CWORD ), /* 1, ' ' */
2901 SIT_ITEM(CNL , CNL , CNL , CNL ), /* 2, \n */
2902 SIT_ITEM(CWORD , CCTL , CCTL , CWORD ), /* 3, !*-/:=?[]~ */
2903 SIT_ITEM(CDQUOTE , CENDQUOTE, CWORD, CWORD ), /* 4, '"' */
2904 SIT_ITEM(CVAR , CVAR , CWORD, CVAR ), /* 5, $ */
2905 SIT_ITEM(CSQUOTE , CWORD , CENDQUOTE, CWORD), /* 6, "'" */
2906 SIT_ITEM(CSPCL , CWORD , CWORD, CLP ), /* 7, ( */
2907 SIT_ITEM(CSPCL , CWORD , CWORD, CRP ), /* 8, ) */
2908 SIT_ITEM(CBACK , CBACK , CCTL , CBACK ), /* 9, \ */
2909 SIT_ITEM(CBQUOTE , CBQUOTE , CWORD, CBQUOTE), /* 10, ` */
2910 SIT_ITEM(CENDVAR , CENDVAR , CWORD, CENDVAR), /* 11, } */
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002911#if !USE_SIT_FUNCTION
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002912 SIT_ITEM(CENDFILE, CENDFILE , CENDFILE, CENDFILE),/* 12, PEOF */
2913 SIT_ITEM(CWORD , CWORD , CWORD, CWORD ), /* 13, 0-9A-Za-z */
2914 SIT_ITEM(CCTL , CCTL , CCTL , CCTL ) /* 14, CTLESC ... */
2915#endif
2916#undef SIT_ITEM
Eric Andersenc470f442003-07-28 09:56:35 +00002917};
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002918/* Constants below must match table above */
2919enum {
2920#if ENABLE_ASH_ALIAS
2921 CSPCL_CIGN_CIGN_CIGN , /* 0 */
2922#endif
2923 CSPCL_CWORD_CWORD_CWORD , /* 1 */
2924 CNL_CNL_CNL_CNL , /* 2 */
2925 CWORD_CCTL_CCTL_CWORD , /* 3 */
2926 CDQUOTE_CENDQUOTE_CWORD_CWORD , /* 4 */
2927 CVAR_CVAR_CWORD_CVAR , /* 5 */
2928 CSQUOTE_CWORD_CENDQUOTE_CWORD , /* 6 */
2929 CSPCL_CWORD_CWORD_CLP , /* 7 */
2930 CSPCL_CWORD_CWORD_CRP , /* 8 */
2931 CBACK_CBACK_CCTL_CBACK , /* 9 */
2932 CBQUOTE_CBQUOTE_CWORD_CBQUOTE , /* 10 */
2933 CENDVAR_CENDVAR_CWORD_CENDVAR , /* 11 */
2934 CENDFILE_CENDFILE_CENDFILE_CENDFILE, /* 12 */
2935 CWORD_CWORD_CWORD_CWORD , /* 13 */
2936 CCTL_CCTL_CCTL_CCTL , /* 14 */
2937};
Eric Andersen2870d962001-07-02 17:27:21 +00002938
Denys Vlasenkocd716832009-11-28 22:14:02 +01002939/* c in SIT(c, syntax) must be an *unsigned char* or PEOA or PEOF,
2940 * caller must ensure proper cast on it if c is *char_ptr!
2941 */
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002942#if USE_SIT_FUNCTION
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002943
Denis Vlasenko0c032a42007-02-23 01:03:40 +00002944static int
2945SIT(int c, int syntax)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002946{
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02002947 /* Used to also have '/' in this string: "\t\n !\"$&'()*-/:;<=>?[\\]`|}~" */
2948 static const char spec_symbls[] ALIGN1 = "\t\n !\"$&'()*-:;<=>?[\\]`|}~";
2949 /*
2950 * This causes '/' to be prepended with CTLESC in dquoted string,
2951 * making "./file"* treated incorrectly because we feed
2952 * ".\/file*" string to glob(), confusing it (see expandmeta func).
2953 * The "homegrown" glob implementation is okay with that,
2954 * but glibc one isn't. With '/' always treated as CWORD,
2955 * both work fine.
2956 */
Denys Vlasenkocd716832009-11-28 22:14:02 +01002957# if ENABLE_ASH_ALIAS
2958 static const uint8_t syntax_index_table[] ALIGN1 = {
Eric Andersenc470f442003-07-28 09:56:35 +00002959 1, 2, 1, 3, 4, 5, 1, 6, /* "\t\n !\"$&'" */
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02002960 7, 8, 3, 3,/*3,*/3, 1, 1, /* "()*-/:;<" */
Eric Andersenc470f442003-07-28 09:56:35 +00002961 3, 1, 3, 3, 9, 3, 10, 1, /* "=>?[\\]`|" */
2962 11, 3 /* "}~" */
2963 };
Denys Vlasenkocd716832009-11-28 22:14:02 +01002964# else
2965 static const uint8_t syntax_index_table[] ALIGN1 = {
Eric Andersenc470f442003-07-28 09:56:35 +00002966 0, 1, 0, 2, 3, 4, 0, 5, /* "\t\n !\"$&'" */
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02002967 6, 7, 2, 2,/*2,*/2, 0, 0, /* "()*-/:;<" */
Eric Andersenc470f442003-07-28 09:56:35 +00002968 2, 0, 2, 2, 8, 2, 9, 0, /* "=>?[\\]`|" */
2969 10, 2 /* "}~" */
2970 };
Denys Vlasenkocd716832009-11-28 22:14:02 +01002971# endif
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002972 const char *s;
2973 int indx;
2974
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002975 if (c == PEOF)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002976 return CENDFILE;
Denys Vlasenkocd716832009-11-28 22:14:02 +01002977# if ENABLE_ASH_ALIAS
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002978 if (c == PEOA)
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002979 indx = 0;
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002980 else
Denys Vlasenkocd716832009-11-28 22:14:02 +01002981# endif
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002982 {
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002983 /* Cast is purely for paranoia here,
2984 * just in case someone passed signed char to us */
2985 if ((unsigned char)c >= CTL_FIRST
2986 && (unsigned char)c <= CTL_LAST
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002987 ) {
2988 return CCTL;
2989 }
2990 s = strchrnul(spec_symbls, c);
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002991 if (*s == '\0')
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002992 return CWORD;
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002993 indx = syntax_index_table[s - spec_symbls];
2994 }
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002995 return (S_I_T[indx] >> (syntax*4)) & 0xf;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002996}
2997
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00002998#else /* !USE_SIT_FUNCTION */
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002999
Denys Vlasenko3e134eb2016-04-22 18:09:21 +02003000static const uint8_t syntax_index_table[] ALIGN1 = {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003001 /* BASESYNTAX_DQSYNTAX_SQSYNTAX_ARISYNTAX */
Denys Vlasenkocd716832009-11-28 22:14:02 +01003002 /* 0 */ CWORD_CWORD_CWORD_CWORD,
3003 /* 1 */ CWORD_CWORD_CWORD_CWORD,
3004 /* 2 */ CWORD_CWORD_CWORD_CWORD,
3005 /* 3 */ CWORD_CWORD_CWORD_CWORD,
3006 /* 4 */ CWORD_CWORD_CWORD_CWORD,
3007 /* 5 */ CWORD_CWORD_CWORD_CWORD,
3008 /* 6 */ CWORD_CWORD_CWORD_CWORD,
3009 /* 7 */ CWORD_CWORD_CWORD_CWORD,
3010 /* 8 */ CWORD_CWORD_CWORD_CWORD,
3011 /* 9 "\t" */ CSPCL_CWORD_CWORD_CWORD,
3012 /* 10 "\n" */ CNL_CNL_CNL_CNL,
3013 /* 11 */ CWORD_CWORD_CWORD_CWORD,
3014 /* 12 */ CWORD_CWORD_CWORD_CWORD,
3015 /* 13 */ CWORD_CWORD_CWORD_CWORD,
3016 /* 14 */ CWORD_CWORD_CWORD_CWORD,
3017 /* 15 */ CWORD_CWORD_CWORD_CWORD,
3018 /* 16 */ CWORD_CWORD_CWORD_CWORD,
3019 /* 17 */ CWORD_CWORD_CWORD_CWORD,
3020 /* 18 */ CWORD_CWORD_CWORD_CWORD,
3021 /* 19 */ CWORD_CWORD_CWORD_CWORD,
3022 /* 20 */ CWORD_CWORD_CWORD_CWORD,
3023 /* 21 */ CWORD_CWORD_CWORD_CWORD,
3024 /* 22 */ CWORD_CWORD_CWORD_CWORD,
3025 /* 23 */ CWORD_CWORD_CWORD_CWORD,
3026 /* 24 */ CWORD_CWORD_CWORD_CWORD,
3027 /* 25 */ CWORD_CWORD_CWORD_CWORD,
3028 /* 26 */ CWORD_CWORD_CWORD_CWORD,
3029 /* 27 */ CWORD_CWORD_CWORD_CWORD,
3030 /* 28 */ CWORD_CWORD_CWORD_CWORD,
3031 /* 29 */ CWORD_CWORD_CWORD_CWORD,
3032 /* 30 */ CWORD_CWORD_CWORD_CWORD,
3033 /* 31 */ CWORD_CWORD_CWORD_CWORD,
3034 /* 32 " " */ CSPCL_CWORD_CWORD_CWORD,
3035 /* 33 "!" */ CWORD_CCTL_CCTL_CWORD,
3036 /* 34 """ */ CDQUOTE_CENDQUOTE_CWORD_CWORD,
3037 /* 35 "#" */ CWORD_CWORD_CWORD_CWORD,
3038 /* 36 "$" */ CVAR_CVAR_CWORD_CVAR,
3039 /* 37 "%" */ CWORD_CWORD_CWORD_CWORD,
3040 /* 38 "&" */ CSPCL_CWORD_CWORD_CWORD,
3041 /* 39 "'" */ CSQUOTE_CWORD_CENDQUOTE_CWORD,
3042 /* 40 "(" */ CSPCL_CWORD_CWORD_CLP,
3043 /* 41 ")" */ CSPCL_CWORD_CWORD_CRP,
3044 /* 42 "*" */ CWORD_CCTL_CCTL_CWORD,
3045 /* 43 "+" */ CWORD_CWORD_CWORD_CWORD,
3046 /* 44 "," */ CWORD_CWORD_CWORD_CWORD,
3047 /* 45 "-" */ CWORD_CCTL_CCTL_CWORD,
3048 /* 46 "." */ CWORD_CWORD_CWORD_CWORD,
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02003049/* "/" was CWORD_CCTL_CCTL_CWORD, see comment in SIT() function why this is changed: */
3050 /* 47 "/" */ CWORD_CWORD_CWORD_CWORD,
Denys Vlasenkocd716832009-11-28 22:14:02 +01003051 /* 48 "0" */ CWORD_CWORD_CWORD_CWORD,
3052 /* 49 "1" */ CWORD_CWORD_CWORD_CWORD,
3053 /* 50 "2" */ CWORD_CWORD_CWORD_CWORD,
3054 /* 51 "3" */ CWORD_CWORD_CWORD_CWORD,
3055 /* 52 "4" */ CWORD_CWORD_CWORD_CWORD,
3056 /* 53 "5" */ CWORD_CWORD_CWORD_CWORD,
3057 /* 54 "6" */ CWORD_CWORD_CWORD_CWORD,
3058 /* 55 "7" */ CWORD_CWORD_CWORD_CWORD,
3059 /* 56 "8" */ CWORD_CWORD_CWORD_CWORD,
3060 /* 57 "9" */ CWORD_CWORD_CWORD_CWORD,
3061 /* 58 ":" */ CWORD_CCTL_CCTL_CWORD,
3062 /* 59 ";" */ CSPCL_CWORD_CWORD_CWORD,
3063 /* 60 "<" */ CSPCL_CWORD_CWORD_CWORD,
3064 /* 61 "=" */ CWORD_CCTL_CCTL_CWORD,
3065 /* 62 ">" */ CSPCL_CWORD_CWORD_CWORD,
3066 /* 63 "?" */ CWORD_CCTL_CCTL_CWORD,
3067 /* 64 "@" */ CWORD_CWORD_CWORD_CWORD,
3068 /* 65 "A" */ CWORD_CWORD_CWORD_CWORD,
3069 /* 66 "B" */ CWORD_CWORD_CWORD_CWORD,
3070 /* 67 "C" */ CWORD_CWORD_CWORD_CWORD,
3071 /* 68 "D" */ CWORD_CWORD_CWORD_CWORD,
3072 /* 69 "E" */ CWORD_CWORD_CWORD_CWORD,
3073 /* 70 "F" */ CWORD_CWORD_CWORD_CWORD,
3074 /* 71 "G" */ CWORD_CWORD_CWORD_CWORD,
3075 /* 72 "H" */ CWORD_CWORD_CWORD_CWORD,
3076 /* 73 "I" */ CWORD_CWORD_CWORD_CWORD,
3077 /* 74 "J" */ CWORD_CWORD_CWORD_CWORD,
3078 /* 75 "K" */ CWORD_CWORD_CWORD_CWORD,
3079 /* 76 "L" */ CWORD_CWORD_CWORD_CWORD,
3080 /* 77 "M" */ CWORD_CWORD_CWORD_CWORD,
3081 /* 78 "N" */ CWORD_CWORD_CWORD_CWORD,
3082 /* 79 "O" */ CWORD_CWORD_CWORD_CWORD,
3083 /* 80 "P" */ CWORD_CWORD_CWORD_CWORD,
3084 /* 81 "Q" */ CWORD_CWORD_CWORD_CWORD,
3085 /* 82 "R" */ CWORD_CWORD_CWORD_CWORD,
3086 /* 83 "S" */ CWORD_CWORD_CWORD_CWORD,
3087 /* 84 "T" */ CWORD_CWORD_CWORD_CWORD,
3088 /* 85 "U" */ CWORD_CWORD_CWORD_CWORD,
3089 /* 86 "V" */ CWORD_CWORD_CWORD_CWORD,
3090 /* 87 "W" */ CWORD_CWORD_CWORD_CWORD,
3091 /* 88 "X" */ CWORD_CWORD_CWORD_CWORD,
3092 /* 89 "Y" */ CWORD_CWORD_CWORD_CWORD,
3093 /* 90 "Z" */ CWORD_CWORD_CWORD_CWORD,
3094 /* 91 "[" */ CWORD_CCTL_CCTL_CWORD,
3095 /* 92 "\" */ CBACK_CBACK_CCTL_CBACK,
3096 /* 93 "]" */ CWORD_CCTL_CCTL_CWORD,
3097 /* 94 "^" */ CWORD_CWORD_CWORD_CWORD,
3098 /* 95 "_" */ CWORD_CWORD_CWORD_CWORD,
3099 /* 96 "`" */ CBQUOTE_CBQUOTE_CWORD_CBQUOTE,
3100 /* 97 "a" */ CWORD_CWORD_CWORD_CWORD,
3101 /* 98 "b" */ CWORD_CWORD_CWORD_CWORD,
3102 /* 99 "c" */ CWORD_CWORD_CWORD_CWORD,
3103 /* 100 "d" */ CWORD_CWORD_CWORD_CWORD,
3104 /* 101 "e" */ CWORD_CWORD_CWORD_CWORD,
3105 /* 102 "f" */ CWORD_CWORD_CWORD_CWORD,
3106 /* 103 "g" */ CWORD_CWORD_CWORD_CWORD,
3107 /* 104 "h" */ CWORD_CWORD_CWORD_CWORD,
3108 /* 105 "i" */ CWORD_CWORD_CWORD_CWORD,
3109 /* 106 "j" */ CWORD_CWORD_CWORD_CWORD,
3110 /* 107 "k" */ CWORD_CWORD_CWORD_CWORD,
3111 /* 108 "l" */ CWORD_CWORD_CWORD_CWORD,
3112 /* 109 "m" */ CWORD_CWORD_CWORD_CWORD,
3113 /* 110 "n" */ CWORD_CWORD_CWORD_CWORD,
3114 /* 111 "o" */ CWORD_CWORD_CWORD_CWORD,
3115 /* 112 "p" */ CWORD_CWORD_CWORD_CWORD,
3116 /* 113 "q" */ CWORD_CWORD_CWORD_CWORD,
3117 /* 114 "r" */ CWORD_CWORD_CWORD_CWORD,
3118 /* 115 "s" */ CWORD_CWORD_CWORD_CWORD,
3119 /* 116 "t" */ CWORD_CWORD_CWORD_CWORD,
3120 /* 117 "u" */ CWORD_CWORD_CWORD_CWORD,
3121 /* 118 "v" */ CWORD_CWORD_CWORD_CWORD,
3122 /* 119 "w" */ CWORD_CWORD_CWORD_CWORD,
3123 /* 120 "x" */ CWORD_CWORD_CWORD_CWORD,
3124 /* 121 "y" */ CWORD_CWORD_CWORD_CWORD,
3125 /* 122 "z" */ CWORD_CWORD_CWORD_CWORD,
3126 /* 123 "{" */ CWORD_CWORD_CWORD_CWORD,
3127 /* 124 "|" */ CSPCL_CWORD_CWORD_CWORD,
3128 /* 125 "}" */ CENDVAR_CENDVAR_CWORD_CENDVAR,
3129 /* 126 "~" */ CWORD_CCTL_CCTL_CWORD,
3130 /* 127 del */ CWORD_CWORD_CWORD_CWORD,
3131 /* 128 0x80 */ CWORD_CWORD_CWORD_CWORD,
3132 /* 129 CTLESC */ CCTL_CCTL_CCTL_CCTL,
3133 /* 130 CTLVAR */ CCTL_CCTL_CCTL_CCTL,
3134 /* 131 CTLENDVAR */ CCTL_CCTL_CCTL_CCTL,
3135 /* 132 CTLBACKQ */ CCTL_CCTL_CCTL_CCTL,
3136 /* 133 CTLQUOTE */ CCTL_CCTL_CCTL_CCTL,
3137 /* 134 CTLARI */ CCTL_CCTL_CCTL_CCTL,
3138 /* 135 CTLENDARI */ CCTL_CCTL_CCTL_CCTL,
3139 /* 136 CTLQUOTEMARK */ CCTL_CCTL_CCTL_CCTL,
3140 /* 137 */ CWORD_CWORD_CWORD_CWORD,
3141 /* 138 */ CWORD_CWORD_CWORD_CWORD,
3142 /* 139 */ CWORD_CWORD_CWORD_CWORD,
3143 /* 140 */ CWORD_CWORD_CWORD_CWORD,
3144 /* 141 */ CWORD_CWORD_CWORD_CWORD,
3145 /* 142 */ CWORD_CWORD_CWORD_CWORD,
3146 /* 143 */ CWORD_CWORD_CWORD_CWORD,
3147 /* 144 */ CWORD_CWORD_CWORD_CWORD,
3148 /* 145 */ CWORD_CWORD_CWORD_CWORD,
3149 /* 146 */ CWORD_CWORD_CWORD_CWORD,
3150 /* 147 */ CWORD_CWORD_CWORD_CWORD,
3151 /* 148 */ CWORD_CWORD_CWORD_CWORD,
3152 /* 149 */ CWORD_CWORD_CWORD_CWORD,
3153 /* 150 */ CWORD_CWORD_CWORD_CWORD,
3154 /* 151 */ CWORD_CWORD_CWORD_CWORD,
3155 /* 152 */ CWORD_CWORD_CWORD_CWORD,
3156 /* 153 */ CWORD_CWORD_CWORD_CWORD,
3157 /* 154 */ CWORD_CWORD_CWORD_CWORD,
3158 /* 155 */ CWORD_CWORD_CWORD_CWORD,
3159 /* 156 */ CWORD_CWORD_CWORD_CWORD,
3160 /* 157 */ CWORD_CWORD_CWORD_CWORD,
3161 /* 158 */ CWORD_CWORD_CWORD_CWORD,
3162 /* 159 */ CWORD_CWORD_CWORD_CWORD,
3163 /* 160 */ CWORD_CWORD_CWORD_CWORD,
3164 /* 161 */ CWORD_CWORD_CWORD_CWORD,
3165 /* 162 */ CWORD_CWORD_CWORD_CWORD,
3166 /* 163 */ CWORD_CWORD_CWORD_CWORD,
3167 /* 164 */ CWORD_CWORD_CWORD_CWORD,
3168 /* 165 */ CWORD_CWORD_CWORD_CWORD,
3169 /* 166 */ CWORD_CWORD_CWORD_CWORD,
3170 /* 167 */ CWORD_CWORD_CWORD_CWORD,
3171 /* 168 */ CWORD_CWORD_CWORD_CWORD,
3172 /* 169 */ CWORD_CWORD_CWORD_CWORD,
3173 /* 170 */ CWORD_CWORD_CWORD_CWORD,
3174 /* 171 */ CWORD_CWORD_CWORD_CWORD,
3175 /* 172 */ CWORD_CWORD_CWORD_CWORD,
3176 /* 173 */ CWORD_CWORD_CWORD_CWORD,
3177 /* 174 */ CWORD_CWORD_CWORD_CWORD,
3178 /* 175 */ CWORD_CWORD_CWORD_CWORD,
3179 /* 176 */ CWORD_CWORD_CWORD_CWORD,
3180 /* 177 */ CWORD_CWORD_CWORD_CWORD,
3181 /* 178 */ CWORD_CWORD_CWORD_CWORD,
3182 /* 179 */ CWORD_CWORD_CWORD_CWORD,
3183 /* 180 */ CWORD_CWORD_CWORD_CWORD,
3184 /* 181 */ CWORD_CWORD_CWORD_CWORD,
3185 /* 182 */ CWORD_CWORD_CWORD_CWORD,
3186 /* 183 */ CWORD_CWORD_CWORD_CWORD,
3187 /* 184 */ CWORD_CWORD_CWORD_CWORD,
3188 /* 185 */ CWORD_CWORD_CWORD_CWORD,
3189 /* 186 */ CWORD_CWORD_CWORD_CWORD,
3190 /* 187 */ CWORD_CWORD_CWORD_CWORD,
3191 /* 188 */ CWORD_CWORD_CWORD_CWORD,
3192 /* 189 */ CWORD_CWORD_CWORD_CWORD,
3193 /* 190 */ CWORD_CWORD_CWORD_CWORD,
3194 /* 191 */ CWORD_CWORD_CWORD_CWORD,
3195 /* 192 */ CWORD_CWORD_CWORD_CWORD,
3196 /* 193 */ CWORD_CWORD_CWORD_CWORD,
3197 /* 194 */ CWORD_CWORD_CWORD_CWORD,
3198 /* 195 */ CWORD_CWORD_CWORD_CWORD,
3199 /* 196 */ CWORD_CWORD_CWORD_CWORD,
3200 /* 197 */ CWORD_CWORD_CWORD_CWORD,
3201 /* 198 */ CWORD_CWORD_CWORD_CWORD,
3202 /* 199 */ CWORD_CWORD_CWORD_CWORD,
3203 /* 200 */ CWORD_CWORD_CWORD_CWORD,
3204 /* 201 */ CWORD_CWORD_CWORD_CWORD,
3205 /* 202 */ CWORD_CWORD_CWORD_CWORD,
3206 /* 203 */ CWORD_CWORD_CWORD_CWORD,
3207 /* 204 */ CWORD_CWORD_CWORD_CWORD,
3208 /* 205 */ CWORD_CWORD_CWORD_CWORD,
3209 /* 206 */ CWORD_CWORD_CWORD_CWORD,
3210 /* 207 */ CWORD_CWORD_CWORD_CWORD,
3211 /* 208 */ CWORD_CWORD_CWORD_CWORD,
3212 /* 209 */ CWORD_CWORD_CWORD_CWORD,
3213 /* 210 */ CWORD_CWORD_CWORD_CWORD,
3214 /* 211 */ CWORD_CWORD_CWORD_CWORD,
3215 /* 212 */ CWORD_CWORD_CWORD_CWORD,
3216 /* 213 */ CWORD_CWORD_CWORD_CWORD,
3217 /* 214 */ CWORD_CWORD_CWORD_CWORD,
3218 /* 215 */ CWORD_CWORD_CWORD_CWORD,
3219 /* 216 */ CWORD_CWORD_CWORD_CWORD,
3220 /* 217 */ CWORD_CWORD_CWORD_CWORD,
3221 /* 218 */ CWORD_CWORD_CWORD_CWORD,
3222 /* 219 */ CWORD_CWORD_CWORD_CWORD,
3223 /* 220 */ CWORD_CWORD_CWORD_CWORD,
3224 /* 221 */ CWORD_CWORD_CWORD_CWORD,
3225 /* 222 */ CWORD_CWORD_CWORD_CWORD,
3226 /* 223 */ CWORD_CWORD_CWORD_CWORD,
3227 /* 224 */ CWORD_CWORD_CWORD_CWORD,
3228 /* 225 */ CWORD_CWORD_CWORD_CWORD,
3229 /* 226 */ CWORD_CWORD_CWORD_CWORD,
3230 /* 227 */ CWORD_CWORD_CWORD_CWORD,
3231 /* 228 */ CWORD_CWORD_CWORD_CWORD,
3232 /* 229 */ CWORD_CWORD_CWORD_CWORD,
3233 /* 230 */ CWORD_CWORD_CWORD_CWORD,
3234 /* 231 */ CWORD_CWORD_CWORD_CWORD,
3235 /* 232 */ CWORD_CWORD_CWORD_CWORD,
3236 /* 233 */ CWORD_CWORD_CWORD_CWORD,
3237 /* 234 */ CWORD_CWORD_CWORD_CWORD,
3238 /* 235 */ CWORD_CWORD_CWORD_CWORD,
3239 /* 236 */ CWORD_CWORD_CWORD_CWORD,
3240 /* 237 */ CWORD_CWORD_CWORD_CWORD,
3241 /* 238 */ CWORD_CWORD_CWORD_CWORD,
3242 /* 239 */ CWORD_CWORD_CWORD_CWORD,
3243 /* 230 */ CWORD_CWORD_CWORD_CWORD,
3244 /* 241 */ CWORD_CWORD_CWORD_CWORD,
3245 /* 242 */ CWORD_CWORD_CWORD_CWORD,
3246 /* 243 */ CWORD_CWORD_CWORD_CWORD,
3247 /* 244 */ CWORD_CWORD_CWORD_CWORD,
3248 /* 245 */ CWORD_CWORD_CWORD_CWORD,
3249 /* 246 */ CWORD_CWORD_CWORD_CWORD,
3250 /* 247 */ CWORD_CWORD_CWORD_CWORD,
3251 /* 248 */ CWORD_CWORD_CWORD_CWORD,
3252 /* 249 */ CWORD_CWORD_CWORD_CWORD,
3253 /* 250 */ CWORD_CWORD_CWORD_CWORD,
3254 /* 251 */ CWORD_CWORD_CWORD_CWORD,
3255 /* 252 */ CWORD_CWORD_CWORD_CWORD,
3256 /* 253 */ CWORD_CWORD_CWORD_CWORD,
3257 /* 254 */ CWORD_CWORD_CWORD_CWORD,
3258 /* 255 */ CWORD_CWORD_CWORD_CWORD,
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01003259 /* PEOF */ CENDFILE_CENDFILE_CENDFILE_CENDFILE,
Denys Vlasenkocd716832009-11-28 22:14:02 +01003260# if ENABLE_ASH_ALIAS
3261 /* PEOA */ CSPCL_CIGN_CIGN_CIGN,
3262# endif
Eric Andersen2870d962001-07-02 17:27:21 +00003263};
3264
Denys Vlasenko2fe66b12016-12-12 17:39:12 +01003265#if 1
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01003266# define SIT(c, syntax) ((S_I_T[syntax_index_table[c]] >> ((syntax)*4)) & 0xf)
Denys Vlasenko2fe66b12016-12-12 17:39:12 +01003267#else /* debug version, caught one signed char bug */
3268# define SIT(c, syntax) \
3269 ({ \
3270 if ((c) < 0 || (c) > (PEOF + ENABLE_ASH_ALIAS)) \
3271 bb_error_msg_and_die("line:%d c:%d", __LINE__, (c)); \
Denys Vlasenko0b883582016-12-23 16:49:07 +01003272 if ((syntax) < 0 || (syntax) > (2 + ENABLE_FEATURE_SH_MATH)) \
Denys Vlasenko2fe66b12016-12-12 17:39:12 +01003273 bb_error_msg_and_die("line:%d c:%d", __LINE__, (c)); \
3274 ((S_I_T[syntax_index_table[c]] >> ((syntax)*4)) & 0xf); \
3275 })
3276#endif
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00003277
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01003278#endif /* !USE_SIT_FUNCTION */
Eric Andersenc470f442003-07-28 09:56:35 +00003279
Eric Andersen2870d962001-07-02 17:27:21 +00003280
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00003281/* ============ Alias handling */
Denis Vlasenkofc06f292007-02-23 21:09:35 +00003282
Denis Vlasenko131ae172007-02-18 13:00:19 +00003283#if ENABLE_ASH_ALIAS
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00003284
3285#define ALIASINUSE 1
3286#define ALIASDEAD 2
3287
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00003288struct alias {
3289 struct alias *next;
3290 char *name;
3291 char *val;
3292 int flag;
3293};
3294
Denis Vlasenko01631112007-12-16 17:20:38 +00003295
3296static struct alias **atab; // [ATABSIZE];
3297#define INIT_G_alias() do { \
3298 atab = xzalloc(ATABSIZE * sizeof(atab[0])); \
3299} while (0)
3300
Eric Andersen2870d962001-07-02 17:27:21 +00003301
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00003302static struct alias **
Denys Vlasenko37dc08b2016-10-02 04:38:07 +02003303__lookupalias(const char *name)
3304{
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00003305 unsigned int hashval;
3306 struct alias **app;
3307 const char *p;
3308 unsigned int ch;
3309
3310 p = name;
3311
3312 ch = (unsigned char)*p;
3313 hashval = ch << 4;
3314 while (ch) {
3315 hashval += ch;
3316 ch = (unsigned char)*++p;
3317 }
3318 app = &atab[hashval % ATABSIZE];
3319
3320 for (; *app; app = &(*app)->next) {
3321 if (strcmp(name, (*app)->name) == 0) {
3322 break;
3323 }
3324 }
3325
3326 return app;
3327}
3328
3329static struct alias *
3330lookupalias(const char *name, int check)
3331{
3332 struct alias *ap = *__lookupalias(name);
3333
3334 if (check && ap && (ap->flag & ALIASINUSE))
3335 return NULL;
3336 return ap;
3337}
3338
3339static struct alias *
3340freealias(struct alias *ap)
3341{
3342 struct alias *next;
3343
3344 if (ap->flag & ALIASINUSE) {
3345 ap->flag |= ALIASDEAD;
3346 return ap;
3347 }
3348
3349 next = ap->next;
3350 free(ap->name);
3351 free(ap->val);
3352 free(ap);
3353 return next;
3354}
Eric Andersencb57d552001-06-28 07:25:16 +00003355
Eric Andersenc470f442003-07-28 09:56:35 +00003356static void
3357setalias(const char *name, const char *val)
Eric Andersencb57d552001-06-28 07:25:16 +00003358{
3359 struct alias *ap, **app;
3360
3361 app = __lookupalias(name);
3362 ap = *app;
Denis Vlasenkob012b102007-02-19 22:43:01 +00003363 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +00003364 if (ap) {
3365 if (!(ap->flag & ALIASINUSE)) {
Denis Vlasenkob012b102007-02-19 22:43:01 +00003366 free(ap->val);
Eric Andersencb57d552001-06-28 07:25:16 +00003367 }
Denis Vlasenko0c032a42007-02-23 01:03:40 +00003368 ap->val = ckstrdup(val);
Eric Andersencb57d552001-06-28 07:25:16 +00003369 ap->flag &= ~ALIASDEAD;
3370 } else {
3371 /* not found */
Denis Vlasenko597906c2008-02-20 16:38:54 +00003372 ap = ckzalloc(sizeof(struct alias));
Denis Vlasenko0c032a42007-02-23 01:03:40 +00003373 ap->name = ckstrdup(name);
3374 ap->val = ckstrdup(val);
Denis Vlasenko597906c2008-02-20 16:38:54 +00003375 /*ap->flag = 0; - ckzalloc did it */
3376 /*ap->next = NULL;*/
Eric Andersencb57d552001-06-28 07:25:16 +00003377 *app = ap;
3378 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00003379 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +00003380}
3381
Eric Andersenc470f442003-07-28 09:56:35 +00003382static int
3383unalias(const char *name)
Eric Andersen2870d962001-07-02 17:27:21 +00003384{
Eric Andersencb57d552001-06-28 07:25:16 +00003385 struct alias **app;
3386
3387 app = __lookupalias(name);
3388
3389 if (*app) {
Denis Vlasenkob012b102007-02-19 22:43:01 +00003390 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +00003391 *app = freealias(*app);
Denis Vlasenkob012b102007-02-19 22:43:01 +00003392 INT_ON;
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003393 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003394 }
3395
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003396 return 1;
Eric Andersencb57d552001-06-28 07:25:16 +00003397}
3398
Eric Andersenc470f442003-07-28 09:56:35 +00003399static void
3400rmaliases(void)
Eric Andersen2870d962001-07-02 17:27:21 +00003401{
Eric Andersencb57d552001-06-28 07:25:16 +00003402 struct alias *ap, **app;
3403 int i;
3404
Denis Vlasenkob012b102007-02-19 22:43:01 +00003405 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +00003406 for (i = 0; i < ATABSIZE; i++) {
3407 app = &atab[i];
3408 for (ap = *app; ap; ap = *app) {
3409 *app = freealias(*app);
3410 if (ap == *app) {
3411 app = &ap->next;
3412 }
3413 }
3414 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00003415 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +00003416}
3417
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00003418static void
3419printalias(const struct alias *ap)
3420{
3421 out1fmt("%s=%s\n", ap->name, single_quote(ap->val));
3422}
3423
Eric Andersencb57d552001-06-28 07:25:16 +00003424/*
3425 * TODO - sort output
3426 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02003427static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003428aliascmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003429{
3430 char *n, *v;
3431 int ret = 0;
3432 struct alias *ap;
3433
Denis Vlasenko68404f12008-03-17 09:00:54 +00003434 if (!argv[1]) {
Eric Andersencb57d552001-06-28 07:25:16 +00003435 int i;
3436
Denis Vlasenko68404f12008-03-17 09:00:54 +00003437 for (i = 0; i < ATABSIZE; i++) {
Eric Andersencb57d552001-06-28 07:25:16 +00003438 for (ap = atab[i]; ap; ap = ap->next) {
3439 printalias(ap);
3440 }
Denis Vlasenko68404f12008-03-17 09:00:54 +00003441 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003442 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003443 }
3444 while ((n = *++argv) != NULL) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +00003445 v = strchr(n+1, '=');
3446 if (v == NULL) { /* n+1: funny ksh stuff */
3447 ap = *__lookupalias(n);
3448 if (ap == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00003449 fprintf(stderr, "%s: %s not found\n", "alias", n);
Eric Andersencb57d552001-06-28 07:25:16 +00003450 ret = 1;
3451 } else
3452 printalias(ap);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003453 } else {
Eric Andersencb57d552001-06-28 07:25:16 +00003454 *v++ = '\0';
3455 setalias(n, v);
3456 }
3457 }
3458
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003459 return ret;
Eric Andersencb57d552001-06-28 07:25:16 +00003460}
3461
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02003462static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003463unaliascmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +00003464{
3465 int i;
3466
Denys Vlasenko6c149f42017-04-12 21:31:32 +02003467 while (nextopt("a") != '\0') {
3468 rmaliases();
3469 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003470 }
3471 for (i = 0; *argptr; argptr++) {
3472 if (unalias(*argptr)) {
Eric Andersenc470f442003-07-28 09:56:35 +00003473 fprintf(stderr, "%s: %s not found\n", "unalias", *argptr);
Eric Andersencb57d552001-06-28 07:25:16 +00003474 i = 1;
3475 }
3476 }
3477
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003478 return i;
Eric Andersencb57d552001-06-28 07:25:16 +00003479}
Denis Vlasenkofc06f292007-02-23 21:09:35 +00003480
Denis Vlasenko131ae172007-02-18 13:00:19 +00003481#endif /* ASH_ALIAS */
Eric Andersencb57d552001-06-28 07:25:16 +00003482
Eric Andersenc470f442003-07-28 09:56:35 +00003483
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003484/* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */
Denys Vlasenko285ad152009-12-04 23:02:27 +01003485#define FORK_FG 0
3486#define FORK_BG 1
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003487#define FORK_NOJOB 2
3488
3489/* mode flags for showjob(s) */
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02003490#define SHOW_ONLY_PGID 0x01 /* show only pgid (jobs -p) */
3491#define SHOW_PIDS 0x02 /* show individual pids, not just one line per job */
3492#define SHOW_CHANGED 0x04 /* only jobs whose state has changed */
Denys Vlasenko9c541002015-10-07 15:44:36 +02003493#define SHOW_STDERR 0x08 /* print to stderr (else stdout) */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003494
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003495/*
3496 * A job structure contains information about a job. A job is either a
3497 * single process or a set of processes contained in a pipeline. In the
3498 * latter case, pidlist will be non-NULL, and will point to a -1 terminated
3499 * array of pids.
3500 */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003501struct procstat {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003502 pid_t ps_pid; /* process id */
3503 int ps_status; /* last process status from wait() */
3504 char *ps_cmd; /* text of command being run */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003505};
3506
3507struct job {
3508 struct procstat ps0; /* status of process */
3509 struct procstat *ps; /* status or processes when more than one */
3510#if JOBS
3511 int stopstatus; /* status of a stopped job */
3512#endif
Denys Vlasenko4c179372017-01-11 18:44:15 +01003513 unsigned nprocs; /* number of processes */
3514
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003515#define JOBRUNNING 0 /* at least one proc running */
3516#define JOBSTOPPED 1 /* all procs are stopped */
3517#define JOBDONE 2 /* all procs are completed */
Denys Vlasenko4c179372017-01-11 18:44:15 +01003518 unsigned
3519 state: 8,
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003520#if JOBS
3521 sigint: 1, /* job was killed by SIGINT */
3522 jobctl: 1, /* job running under job control */
3523#endif
3524 waited: 1, /* true if this entry has been waited for */
3525 used: 1, /* true if this entry is in used */
3526 changed: 1; /* true if status has changed */
3527 struct job *prev_job; /* previous job */
3528};
3529
Denis Vlasenko68404f12008-03-17 09:00:54 +00003530static struct job *makejob(/*union node *,*/ int);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003531static int forkshell(struct job *, union node *, int);
3532static int waitforjob(struct job *);
3533
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00003534#if !JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +00003535enum { doing_jobctl = 0 };
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00003536#define setjobctl(on) do {} while (0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003537#else
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003538static smallint doing_jobctl; //references:8
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003539static void setjobctl(int);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003540#endif
3541
3542/*
Denis Vlasenko4b875702009-03-19 13:30:04 +00003543 * Ignore a signal.
3544 */
3545static void
3546ignoresig(int signo)
3547{
3548 /* Avoid unnecessary system calls. Is it already SIG_IGNed? */
3549 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
3550 /* No, need to do it */
3551 signal(signo, SIG_IGN);
3552 }
3553 sigmode[signo - 1] = S_HARD_IGN;
3554}
3555
3556/*
Denys Vlasenko238bf182010-05-18 15:49:07 +02003557 * Only one usage site - in setsignal()
Denis Vlasenko4b875702009-03-19 13:30:04 +00003558 */
3559static void
Denys Vlasenko238bf182010-05-18 15:49:07 +02003560signal_handler(int signo)
Denis Vlasenko4b875702009-03-19 13:30:04 +00003561{
Denys Vlasenko458c1f22016-10-27 23:51:19 +02003562 if (signo == SIGCHLD) {
3563 got_sigchld = 1;
3564 if (!trap[SIGCHLD])
3565 return;
3566 }
3567
Denis Vlasenko4b875702009-03-19 13:30:04 +00003568 gotsig[signo - 1] = 1;
Denys Vlasenko458c1f22016-10-27 23:51:19 +02003569 pending_sig = signo;
Denis Vlasenko4b875702009-03-19 13:30:04 +00003570
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02003571 if (signo == SIGINT && !trap[SIGINT]) {
3572 if (!suppress_int) {
3573 pending_sig = 0;
Denis Vlasenko4b875702009-03-19 13:30:04 +00003574 raise_interrupt(); /* does not return */
3575 }
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02003576 pending_int = 1;
Denis Vlasenko4b875702009-03-19 13:30:04 +00003577 }
3578}
3579
3580/*
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003581 * Set the signal handler for the specified signal. The routine figures
3582 * out what it should be set to.
3583 */
3584static void
3585setsignal(int signo)
3586{
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003587 char *t;
3588 char cur_act, new_act;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003589 struct sigaction act;
3590
3591 t = trap[signo];
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003592 new_act = S_DFL;
3593 if (t != NULL) { /* trap for this sig is set */
3594 new_act = S_CATCH;
3595 if (t[0] == '\0') /* trap is "": ignore this sig */
3596 new_act = S_IGN;
3597 }
3598
3599 if (rootshell && new_act == S_DFL) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003600 switch (signo) {
3601 case SIGINT:
3602 if (iflag || minusc || sflag == 0)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003603 new_act = S_CATCH;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003604 break;
3605 case SIGQUIT:
3606#if DEBUG
3607 if (debug)
3608 break;
3609#endif
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003610 /* man bash:
3611 * "In all cases, bash ignores SIGQUIT. Non-builtin
3612 * commands run by bash have signal handlers
3613 * set to the values inherited by the shell
3614 * from its parent". */
3615 new_act = S_IGN;
3616 break;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003617 case SIGTERM:
3618 if (iflag)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003619 new_act = S_IGN;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003620 break;
3621#if JOBS
3622 case SIGTSTP:
3623 case SIGTTOU:
3624 if (mflag)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003625 new_act = S_IGN;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003626 break;
3627#endif
3628 }
3629 }
Denys Vlasenko49e6bf22017-08-04 14:28:16 +02003630 /* if !rootshell, we reset SIGQUIT to DFL,
3631 * whereas we have to restore it to what shell got on entry.
3632 * This is handled by the fact that if signal was IGNored on entry,
3633 * then cur_act is S_HARD_IGN and we never change its sigaction
3634 * (see code below).
3635 */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003636
Denys Vlasenko458c1f22016-10-27 23:51:19 +02003637 if (signo == SIGCHLD)
3638 new_act = S_CATCH;
3639
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003640 t = &sigmode[signo - 1];
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003641 cur_act = *t;
3642 if (cur_act == 0) {
3643 /* current setting is not yet known */
3644 if (sigaction(signo, NULL, &act)) {
3645 /* pretend it worked; maybe we should give a warning,
3646 * but other shells don't. We don't alter sigmode,
3647 * so we retry every time.
3648 * btw, in Linux it never fails. --vda */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003649 return;
3650 }
3651 if (act.sa_handler == SIG_IGN) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003652 cur_act = S_HARD_IGN;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003653 if (mflag
3654 && (signo == SIGTSTP || signo == SIGTTIN || signo == SIGTTOU)
3655 ) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003656 cur_act = S_IGN; /* don't hard ignore these */
Denis Vlasenko991a1da2008-02-10 19:02:53 +00003657 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003658 }
Denys Vlasenko0f14f412017-08-06 20:06:19 +02003659 if (act.sa_handler == SIG_DFL && new_act == S_DFL) {
3660 /* installing SIG_DFL over SIG_DFL is a no-op */
3661 /* saves one sigaction call in each "sh -c SCRIPT" invocation */
3662 *t = S_DFL;
3663 return;
3664 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003665 }
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003666 if (cur_act == S_HARD_IGN || cur_act == new_act)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003667 return;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003668
Denys Vlasenko49e6bf22017-08-04 14:28:16 +02003669 *t = new_act;
3670
Denis Vlasenko991a1da2008-02-10 19:02:53 +00003671 act.sa_handler = SIG_DFL;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003672 switch (new_act) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003673 case S_CATCH:
Denys Vlasenko238bf182010-05-18 15:49:07 +02003674 act.sa_handler = signal_handler;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003675 break;
3676 case S_IGN:
3677 act.sa_handler = SIG_IGN;
3678 break;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003679 }
Ian Wienand89b3cba2011-04-16 20:05:14 +02003680 /* flags and mask matter only if !DFL and !IGN, but we do it
3681 * for all cases for more deterministic behavior:
3682 */
Denys Vlasenko49e6bf22017-08-04 14:28:16 +02003683 act.sa_flags = 0; //TODO: why not SA_RESTART?
Ian Wienand89b3cba2011-04-16 20:05:14 +02003684 sigfillset(&act.sa_mask);
3685
Denis Vlasenko8e2cfec2008-03-12 23:19:35 +00003686 sigaction_set(signo, &act);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003687}
3688
3689/* mode flags for set_curjob */
3690#define CUR_DELETE 2
3691#define CUR_RUNNING 1
3692#define CUR_STOPPED 0
3693
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003694#if JOBS
3695/* pgrp of shell on invocation */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003696static int initialpgrp; //references:2
3697static int ttyfd = -1; //5
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003698#endif
3699/* array of jobs */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003700static struct job *jobtab; //5
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003701/* size of array */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003702static unsigned njobs; //4
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003703/* current job */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003704static struct job *curjob; //lots
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003705/* number of presumed living untracked jobs */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003706static int jobless; //4
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003707
Denys Vlasenko098b7132017-01-11 19:59:03 +01003708#if 0
3709/* Bash has a feature: it restores termios after a successful wait for
3710 * a foreground job which had at least one stopped or sigkilled member.
3711 * The probable rationale is that SIGSTOP and SIGKILL can preclude task from
3712 * properly restoring tty state. Should we do this too?
3713 * A reproducer: ^Z an interactive python:
3714 *
3715 * # python
3716 * Python 2.7.12 (...)
3717 * >>> ^Z
3718 * { python leaves tty in -icanon -echo state. We do survive that... }
3719 * [1]+ Stopped python
3720 * { ...however, next program (python #2) does not survive it well: }
3721 * # python
3722 * Python 2.7.12 (...)
3723 * >>> Traceback (most recent call last):
3724 * { above, I typed "qwerty<CR>", but -echo state is still in effect }
3725 * File "<stdin>", line 1, in <module>
3726 * NameError: name 'qwerty' is not defined
3727 *
3728 * The implementation below is modeled on bash code and seems to work.
3729 * However, I'm not sure we should do this. For one: what if I'd fg
3730 * the stopped python instead? It'll be confused by "restored" tty state.
3731 */
3732static struct termios shell_tty_info;
3733static void
3734get_tty_state(void)
3735{
3736 if (rootshell && ttyfd >= 0)
3737 tcgetattr(ttyfd, &shell_tty_info);
3738}
3739static void
3740set_tty_state(void)
3741{
3742 /* if (rootshell) - caller ensures this */
3743 if (ttyfd >= 0)
3744 tcsetattr(ttyfd, TCSADRAIN, &shell_tty_info);
3745}
3746static int
3747job_signal_status(struct job *jp)
3748{
3749 int status;
3750 unsigned i;
3751 struct procstat *ps = jp->ps;
3752 for (i = 0; i < jp->nprocs; i++) {
3753 status = ps[i].ps_status;
3754 if (WIFSIGNALED(status) || WIFSTOPPED(status))
3755 return status;
3756 }
3757 return 0;
3758}
3759static void
3760restore_tty_if_stopped_or_signaled(struct job *jp)
3761{
3762//TODO: check what happens if we come from waitforjob() in expbackq()
3763 if (rootshell) {
3764 int s = job_signal_status(jp);
3765 if (s) /* WIFSIGNALED(s) || WIFSTOPPED(s) */
3766 set_tty_state();
3767 }
3768}
3769#else
3770# define get_tty_state() ((void)0)
3771# define restore_tty_if_stopped_or_signaled(jp) ((void)0)
3772#endif
3773
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003774static void
3775set_curjob(struct job *jp, unsigned mode)
3776{
3777 struct job *jp1;
3778 struct job **jpp, **curp;
3779
3780 /* first remove from list */
3781 jpp = curp = &curjob;
Denys Vlasenko940c7202011-03-02 04:07:14 +01003782 while (1) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003783 jp1 = *jpp;
3784 if (jp1 == jp)
3785 break;
3786 jpp = &jp1->prev_job;
Denys Vlasenko940c7202011-03-02 04:07:14 +01003787 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003788 *jpp = jp1->prev_job;
3789
3790 /* Then re-insert in correct position */
3791 jpp = curp;
3792 switch (mode) {
3793 default:
3794#if DEBUG
3795 abort();
3796#endif
3797 case CUR_DELETE:
3798 /* job being deleted */
3799 break;
3800 case CUR_RUNNING:
3801 /* newly created job or backgrounded job,
Denys Vlasenko60cb48c2013-01-14 15:57:44 +01003802 * put after all stopped jobs.
3803 */
Denys Vlasenko940c7202011-03-02 04:07:14 +01003804 while (1) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003805 jp1 = *jpp;
3806#if JOBS
3807 if (!jp1 || jp1->state != JOBSTOPPED)
3808#endif
3809 break;
3810 jpp = &jp1->prev_job;
Denys Vlasenko940c7202011-03-02 04:07:14 +01003811 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003812 /* FALLTHROUGH */
3813#if JOBS
3814 case CUR_STOPPED:
3815#endif
3816 /* newly stopped job - becomes curjob */
3817 jp->prev_job = *jpp;
3818 *jpp = jp;
3819 break;
3820 }
3821}
3822
3823#if JOBS || DEBUG
3824static int
3825jobno(const struct job *jp)
3826{
3827 return jp - jobtab + 1;
3828}
3829#endif
3830
3831/*
3832 * Convert a job name to a job structure.
3833 */
Denis Vlasenko85c24712008-03-17 09:04:04 +00003834#if !JOBS
3835#define getjob(name, getctl) getjob(name)
3836#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003837static struct job *
3838getjob(const char *name, int getctl)
3839{
3840 struct job *jp;
3841 struct job *found;
Denys Vlasenkoffc39202009-08-17 02:12:20 +02003842 const char *err_msg = "%s: no such job";
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003843 unsigned num;
3844 int c;
3845 const char *p;
3846 char *(*match)(const char *, const char *);
3847
3848 jp = curjob;
3849 p = name;
3850 if (!p)
3851 goto currentjob;
3852
3853 if (*p != '%')
3854 goto err;
3855
3856 c = *++p;
3857 if (!c)
3858 goto currentjob;
3859
3860 if (!p[1]) {
3861 if (c == '+' || c == '%') {
3862 currentjob:
3863 err_msg = "No current job";
3864 goto check;
3865 }
3866 if (c == '-') {
3867 if (jp)
3868 jp = jp->prev_job;
3869 err_msg = "No previous job";
3870 check:
3871 if (!jp)
3872 goto err;
3873 goto gotit;
3874 }
3875 }
3876
3877 if (is_number(p)) {
3878 num = atoi(p);
Denys Vlasenko46a45ce2016-09-29 01:10:08 +02003879 if (num > 0 && num <= njobs) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003880 jp = jobtab + num - 1;
3881 if (jp->used)
3882 goto gotit;
3883 goto err;
3884 }
3885 }
3886
3887 match = prefix;
3888 if (*p == '?') {
3889 match = strstr;
3890 p++;
3891 }
3892
Denys Vlasenkoffc39202009-08-17 02:12:20 +02003893 found = NULL;
3894 while (jp) {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003895 if (match(jp->ps[0].ps_cmd, p)) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003896 if (found)
3897 goto err;
3898 found = jp;
3899 err_msg = "%s: ambiguous";
3900 }
3901 jp = jp->prev_job;
3902 }
Denys Vlasenkoffc39202009-08-17 02:12:20 +02003903 if (!found)
3904 goto err;
3905 jp = found;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003906
3907 gotit:
3908#if JOBS
3909 err_msg = "job %s not created under job control";
3910 if (getctl && jp->jobctl == 0)
3911 goto err;
3912#endif
3913 return jp;
3914 err:
3915 ash_msg_and_raise_error(err_msg, name);
3916}
3917
3918/*
3919 * Mark a job structure as unused.
3920 */
3921static void
3922freejob(struct job *jp)
3923{
3924 struct procstat *ps;
3925 int i;
3926
3927 INT_OFF;
3928 for (i = jp->nprocs, ps = jp->ps; --i >= 0; ps++) {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003929 if (ps->ps_cmd != nullstr)
3930 free(ps->ps_cmd);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003931 }
3932 if (jp->ps != &jp->ps0)
3933 free(jp->ps);
3934 jp->used = 0;
3935 set_curjob(jp, CUR_DELETE);
3936 INT_ON;
3937}
3938
3939#if JOBS
3940static void
3941xtcsetpgrp(int fd, pid_t pgrp)
3942{
3943 if (tcsetpgrp(fd, pgrp))
Ron Yorstonbe366e52017-07-27 13:53:39 +01003944 ash_msg_and_raise_perror("can't set tty process group");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003945}
3946
3947/*
3948 * Turn job control on and off.
3949 *
3950 * Note: This code assumes that the third arg to ioctl is a character
3951 * pointer, which is true on Berkeley systems but not System V. Since
3952 * System V doesn't have job control yet, this isn't a problem now.
3953 *
3954 * Called with interrupts off.
3955 */
3956static void
3957setjobctl(int on)
3958{
3959 int fd;
3960 int pgrp;
3961
Denis Vlasenkob07a4962008-06-22 13:16:23 +00003962 if (on == doing_jobctl || rootshell == 0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003963 return;
3964 if (on) {
3965 int ofd;
3966 ofd = fd = open(_PATH_TTY, O_RDWR);
3967 if (fd < 0) {
3968 /* BTW, bash will try to open(ttyname(0)) if open("/dev/tty") fails.
3969 * That sometimes helps to acquire controlling tty.
3970 * Obviously, a workaround for bugs when someone
3971 * failed to provide a controlling tty to bash! :) */
Denis Vlasenkoed270a52007-11-26 05:37:07 +00003972 fd = 2;
3973 while (!isatty(fd))
3974 if (--fd < 0)
3975 goto out;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003976 }
Denys Vlasenko64774602016-10-26 15:24:30 +02003977 /* fd is a tty at this point */
Denys Vlasenko60fb98e2018-03-30 22:15:14 +02003978 fd = fcntl(fd, F_DUPFD_CLOEXEC, 10);
Denys Vlasenko10ad6222017-04-17 16:13:32 +02003979 if (ofd >= 0) /* if it is "/dev/tty", close. If 0/1/2, don't */
Denis Vlasenkoed270a52007-11-26 05:37:07 +00003980 close(ofd);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003981 if (fd < 0)
Denys Vlasenko64774602016-10-26 15:24:30 +02003982 goto out; /* F_DUPFD failed */
Denys Vlasenko60fb98e2018-03-30 22:15:14 +02003983 if (F_DUPFD_CLOEXEC == F_DUPFD) /* if old libc (w/o F_DUPFD_CLOEXEC) */
3984 close_on_exec_on(fd);
Denys Vlasenko940c7202011-03-02 04:07:14 +01003985 while (1) { /* while we are in the background */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003986 pgrp = tcgetpgrp(fd);
3987 if (pgrp < 0) {
3988 out:
3989 ash_msg("can't access tty; job control turned off");
3990 mflag = on = 0;
3991 goto close;
3992 }
3993 if (pgrp == getpgrp())
3994 break;
3995 killpg(0, SIGTTIN);
Denys Vlasenko940c7202011-03-02 04:07:14 +01003996 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003997 initialpgrp = pgrp;
3998
3999 setsignal(SIGTSTP);
4000 setsignal(SIGTTOU);
4001 setsignal(SIGTTIN);
4002 pgrp = rootpid;
4003 setpgid(0, pgrp);
4004 xtcsetpgrp(fd, pgrp);
4005 } else {
4006 /* turning job control off */
4007 fd = ttyfd;
4008 pgrp = initialpgrp;
Denis Vlasenko08c8c1d2007-04-28 22:39:02 +00004009 /* was xtcsetpgrp, but this can make exiting ash
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004010 * loop forever if pty is already deleted */
Denis Vlasenko08c8c1d2007-04-28 22:39:02 +00004011 tcsetpgrp(fd, pgrp);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004012 setpgid(0, pgrp);
4013 setsignal(SIGTSTP);
4014 setsignal(SIGTTOU);
4015 setsignal(SIGTTIN);
4016 close:
Denis Vlasenkoed270a52007-11-26 05:37:07 +00004017 if (fd >= 0)
4018 close(fd);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004019 fd = -1;
4020 }
4021 ttyfd = fd;
Denis Vlasenkob07a4962008-06-22 13:16:23 +00004022 doing_jobctl = on;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004023}
4024
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02004025static int FAST_FUNC
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004026killcmd(int argc, char **argv)
4027{
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00004028 if (argv[1] && strcmp(argv[1], "-l") != 0) {
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004029 int i = 1;
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00004030 do {
4031 if (argv[i][0] == '%') {
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004032 /*
4033 * "kill %N" - job kill
4034 * Converting to pgrp / pid kill
4035 */
4036 struct job *jp;
4037 char *dst;
4038 int j, n;
4039
4040 jp = getjob(argv[i], 0);
4041 /*
4042 * In jobs started under job control, we signal
4043 * entire process group by kill -PGRP_ID.
4044 * This happens, f.e., in interactive shell.
4045 *
4046 * Otherwise, we signal each child via
4047 * kill PID1 PID2 PID3.
4048 * Testcases:
4049 * sh -c 'sleep 1|sleep 1 & kill %1'
4050 * sh -c 'true|sleep 2 & sleep 1; kill %1'
4051 * sh -c 'true|sleep 1 & sleep 2; kill %1'
4052 */
4053 n = jp->nprocs; /* can't be 0 (I hope) */
4054 if (jp->jobctl)
4055 n = 1;
4056 dst = alloca(n * sizeof(int)*4);
4057 argv[i] = dst;
4058 for (j = 0; j < n; j++) {
4059 struct procstat *ps = &jp->ps[j];
4060 /* Skip non-running and not-stopped members
4061 * (i.e. dead members) of the job
4062 */
4063 if (ps->ps_status != -1 && !WIFSTOPPED(ps->ps_status))
4064 continue;
4065 /*
4066 * kill_main has matching code to expect
4067 * leading space. Needed to not confuse
4068 * negative pids with "kill -SIGNAL_NO" syntax
4069 */
4070 dst += sprintf(dst, jp->jobctl ? " -%u" : " %u", (int)ps->ps_pid);
4071 }
4072 *dst = '\0';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004073 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00004074 } while (argv[++i]);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004075 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00004076 return kill_main(argc, argv);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004077}
4078
4079static void
Denys Vlasenko285ad152009-12-04 23:02:27 +01004080showpipe(struct job *jp /*, FILE *out*/)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004081{
Denys Vlasenko285ad152009-12-04 23:02:27 +01004082 struct procstat *ps;
4083 struct procstat *psend;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004084
Denys Vlasenko285ad152009-12-04 23:02:27 +01004085 psend = jp->ps + jp->nprocs;
4086 for (ps = jp->ps + 1; ps < psend; ps++)
4087 printf(" | %s", ps->ps_cmd);
Denys Vlasenko9c541002015-10-07 15:44:36 +02004088 newline_and_flush(stdout);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004089 flush_stdout_stderr();
4090}
4091
4092
4093static int
4094restartjob(struct job *jp, int mode)
4095{
4096 struct procstat *ps;
4097 int i;
4098 int status;
4099 pid_t pgid;
4100
4101 INT_OFF;
4102 if (jp->state == JOBDONE)
4103 goto out;
4104 jp->state = JOBRUNNING;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004105 pgid = jp->ps[0].ps_pid;
Denys Vlasenko098b7132017-01-11 19:59:03 +01004106 if (mode == FORK_FG) {
4107 get_tty_state();
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004108 xtcsetpgrp(ttyfd, pgid);
Denys Vlasenko098b7132017-01-11 19:59:03 +01004109 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004110 killpg(pgid, SIGCONT);
4111 ps = jp->ps;
4112 i = jp->nprocs;
4113 do {
Denys Vlasenko285ad152009-12-04 23:02:27 +01004114 if (WIFSTOPPED(ps->ps_status)) {
4115 ps->ps_status = -1;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004116 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00004117 ps++;
4118 } while (--i);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004119 out:
4120 status = (mode == FORK_FG) ? waitforjob(jp) : 0;
4121 INT_ON;
4122 return status;
4123}
4124
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02004125static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00004126fg_bgcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004127{
4128 struct job *jp;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004129 int mode;
4130 int retval;
4131
4132 mode = (**argv == 'f') ? FORK_FG : FORK_BG;
4133 nextopt(nullstr);
4134 argv = argptr;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004135 do {
4136 jp = getjob(*argv, 1);
4137 if (mode == FORK_BG) {
4138 set_curjob(jp, CUR_RUNNING);
Denys Vlasenko285ad152009-12-04 23:02:27 +01004139 printf("[%d] ", jobno(jp));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004140 }
Denys Vlasenko285ad152009-12-04 23:02:27 +01004141 out1str(jp->ps[0].ps_cmd);
4142 showpipe(jp /*, stdout*/);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004143 retval = restartjob(jp, mode);
4144 } while (*argv && *++argv);
4145 return retval;
4146}
4147#endif
4148
4149static int
Denys Vlasenko9c541002015-10-07 15:44:36 +02004150sprint_status48(char *s, int status, int sigonly)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004151{
4152 int col;
4153 int st;
4154
4155 col = 0;
4156 if (!WIFEXITED(status)) {
Johannes Schindelin9d4dc842017-07-14 22:25:58 +02004157#if JOBS
4158 if (WIFSTOPPED(status))
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004159 st = WSTOPSIG(status);
4160 else
Johannes Schindelin9d4dc842017-07-14 22:25:58 +02004161#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004162 st = WTERMSIG(status);
4163 if (sigonly) {
4164 if (st == SIGINT || st == SIGPIPE)
4165 goto out;
Johannes Schindelin9d4dc842017-07-14 22:25:58 +02004166#if JOBS
4167 if (WIFSTOPPED(status))
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004168 goto out;
Johannes Schindelin9d4dc842017-07-14 22:25:58 +02004169#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004170 }
4171 st &= 0x7f;
Denys Vlasenko7c6f2462011-02-14 17:17:10 +01004172//TODO: use bbox's get_signame? strsignal adds ~600 bytes to text+rodata
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004173 col = fmtstr(s, 32, strsignal(st));
4174 if (WCOREDUMP(status)) {
Denys Vlasenko9c541002015-10-07 15:44:36 +02004175 strcpy(s + col, " (core dumped)");
4176 col += sizeof(" (core dumped)")-1;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004177 }
4178 } else if (!sigonly) {
4179 st = WEXITSTATUS(status);
Denys Vlasenko9c541002015-10-07 15:44:36 +02004180 col = fmtstr(s, 16, (st ? "Done(%d)" : "Done"), st);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004181 }
4182 out:
4183 return col;
4184}
4185
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004186static int
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004187wait_block_or_sig(int *status)
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004188{
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004189 int pid;
4190
4191 do {
Denys Vlasenko1ab7c2f2016-11-03 20:17:23 +01004192 sigset_t mask;
4193
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004194 /* Poll all children for changes in their state */
4195 got_sigchld = 0;
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004196 /* if job control is active, accept stopped processes too */
4197 pid = waitpid(-1, status, doing_jobctl ? (WNOHANG|WUNTRACED) : WNOHANG);
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004198 if (pid != 0)
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004199 break; /* Error (e.g. EINTR, ECHILD) or pid */
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004200
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004201 /* Children exist, but none are ready. Sleep until interesting signal */
Denys Vlasenko1ab7c2f2016-11-03 20:17:23 +01004202#if 1
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004203 sigfillset(&mask);
4204 sigprocmask(SIG_SETMASK, &mask, &mask);
4205 while (!got_sigchld && !pending_sig)
4206 sigsuspend(&mask);
4207 sigprocmask(SIG_SETMASK, &mask, NULL);
Denys Vlasenko1ab7c2f2016-11-03 20:17:23 +01004208#else /* unsafe: a signal can set pending_sig after check, but before pause() */
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004209 while (!got_sigchld && !pending_sig)
4210 pause();
4211#endif
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004212
4213 /* If it was SIGCHLD, poll children again */
4214 } while (got_sigchld);
4215
4216 return pid;
4217}
4218
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004219#define DOWAIT_NONBLOCK 0
4220#define DOWAIT_BLOCK 1
4221#define DOWAIT_BLOCK_OR_SIG 2
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004222
4223static int
Denys Vlasenkob543bda2016-10-27 20:08:28 +02004224dowait(int block, struct job *job)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004225{
4226 int pid;
4227 int status;
4228 struct job *jp;
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004229 struct job *thisjob = NULL;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004230
Denys Vlasenkob543bda2016-10-27 20:08:28 +02004231 TRACE(("dowait(0x%x) called\n", block));
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +00004232
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004233 /* It's wrong to call waitpid() outside of INT_OFF region:
4234 * signal can arrive just after syscall return and handler can
4235 * longjmp away, losing stop/exit notification processing.
4236 * Thus, for "jobs" builtin, and for waiting for a fg job,
4237 * we call waitpid() (blocking or non-blocking) inside INT_OFF.
4238 *
4239 * However, for "wait" builtin it is wrong to simply call waitpid()
4240 * in INT_OFF region: "wait" needs to wait for any running job
4241 * to change state, but should exit on any trap too.
4242 * In INT_OFF region, a signal just before syscall entry can set
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004243 * pending_sig variables, but we can't check them, and we would
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004244 * either enter a sleeping waitpid() (BUG), or need to busy-loop.
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004245 *
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004246 * Because of this, we run inside INT_OFF, but use a special routine
Denys Vlasenko1ab7c2f2016-11-03 20:17:23 +01004247 * which combines waitpid() and sigsuspend().
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004248 * This is the reason why we need to have a handler for SIGCHLD:
Denys Vlasenko1ab7c2f2016-11-03 20:17:23 +01004249 * SIG_DFL handler does not wake sigsuspend().
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004250 */
4251 INT_OFF;
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004252 if (block == DOWAIT_BLOCK_OR_SIG) {
4253 pid = wait_block_or_sig(&status);
4254 } else {
4255 int wait_flags = 0;
4256 if (block == DOWAIT_NONBLOCK)
4257 wait_flags = WNOHANG;
4258 /* if job control is active, accept stopped processes too */
4259 if (doing_jobctl)
4260 wait_flags |= WUNTRACED;
4261 /* NB: _not_ safe_waitpid, we need to detect EINTR */
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004262 pid = waitpid(-1, &status, wait_flags);
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004263 }
Denis Vlasenkob21f3792009-03-19 23:09:58 +00004264 TRACE(("wait returns pid=%d, status=0x%x, errno=%d(%s)\n",
4265 pid, status, errno, strerror(errno)));
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004266 if (pid <= 0)
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004267 goto out;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004268
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004269 thisjob = NULL;
4270 for (jp = curjob; jp; jp = jp->prev_job) {
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004271 int jobstate;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004272 struct procstat *ps;
4273 struct procstat *psend;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004274 if (jp->state == JOBDONE)
4275 continue;
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004276 jobstate = JOBDONE;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004277 ps = jp->ps;
4278 psend = ps + jp->nprocs;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004279 do {
Denys Vlasenko285ad152009-12-04 23:02:27 +01004280 if (ps->ps_pid == pid) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004281 TRACE(("Job %d: changing status of proc %d "
4282 "from 0x%x to 0x%x\n",
Denys Vlasenko285ad152009-12-04 23:02:27 +01004283 jobno(jp), pid, ps->ps_status, status));
4284 ps->ps_status = status;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004285 thisjob = jp;
4286 }
Denys Vlasenko285ad152009-12-04 23:02:27 +01004287 if (ps->ps_status == -1)
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004288 jobstate = JOBRUNNING;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004289#if JOBS
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004290 if (jobstate == JOBRUNNING)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004291 continue;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004292 if (WIFSTOPPED(ps->ps_status)) {
4293 jp->stopstatus = ps->ps_status;
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004294 jobstate = JOBSTOPPED;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004295 }
4296#endif
Denys Vlasenko285ad152009-12-04 23:02:27 +01004297 } while (++ps < psend);
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004298 if (!thisjob)
4299 continue;
4300
4301 /* Found the job where one of its processes changed its state.
4302 * Is there at least one live and running process in this job? */
4303 if (jobstate != JOBRUNNING) {
4304 /* No. All live processes in the job are stopped
4305 * (JOBSTOPPED) or there are no live processes (JOBDONE)
4306 */
4307 thisjob->changed = 1;
4308 if (thisjob->state != jobstate) {
4309 TRACE(("Job %d: changing state from %d to %d\n",
4310 jobno(thisjob), thisjob->state, jobstate));
4311 thisjob->state = jobstate;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004312#if JOBS
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004313 if (jobstate == JOBSTOPPED)
4314 set_curjob(thisjob, CUR_STOPPED);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004315#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004316 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004317 }
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004318 goto out;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004319 }
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004320 /* The process wasn't found in job list */
Johannes Schindelin9d4dc842017-07-14 22:25:58 +02004321#if JOBS
4322 if (!WIFSTOPPED(status))
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004323 jobless--;
Johannes Schindelin9d4dc842017-07-14 22:25:58 +02004324#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004325 out:
4326 INT_ON;
4327
4328 if (thisjob && thisjob == job) {
4329 char s[48 + 1];
4330 int len;
4331
Denys Vlasenko9c541002015-10-07 15:44:36 +02004332 len = sprint_status48(s, status, 1);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004333 if (len) {
4334 s[len] = '\n';
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004335 s[len + 1] = '\0';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004336 out2str(s);
4337 }
4338 }
4339 return pid;
4340}
4341
4342#if JOBS
4343static void
Denys Vlasenko9c541002015-10-07 15:44:36 +02004344showjob(struct job *jp, int mode)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004345{
4346 struct procstat *ps;
4347 struct procstat *psend;
4348 int col;
Denis Vlasenko40ba9982007-07-14 00:48:29 +00004349 int indent_col;
Denys Vlasenko9c541002015-10-07 15:44:36 +02004350 char s[16 + 16 + 48];
4351 FILE *out = (mode & SHOW_STDERR ? stderr : stdout);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004352
4353 ps = jp->ps;
4354
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004355 if (mode & SHOW_ONLY_PGID) { /* jobs -p */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004356 /* just output process (group) id of pipeline */
Denys Vlasenko285ad152009-12-04 23:02:27 +01004357 fprintf(out, "%d\n", ps->ps_pid);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004358 return;
4359 }
4360
4361 col = fmtstr(s, 16, "[%d] ", jobno(jp));
Denis Vlasenko40ba9982007-07-14 00:48:29 +00004362 indent_col = col;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004363
4364 if (jp == curjob)
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004365 s[col - 3] = '+';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004366 else if (curjob && jp == curjob->prev_job)
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004367 s[col - 3] = '-';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004368
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004369 if (mode & SHOW_PIDS)
Denys Vlasenko285ad152009-12-04 23:02:27 +01004370 col += fmtstr(s + col, 16, "%d ", ps->ps_pid);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004371
4372 psend = ps + jp->nprocs;
4373
4374 if (jp->state == JOBRUNNING) {
4375 strcpy(s + col, "Running");
4376 col += sizeof("Running") - 1;
4377 } else {
Denys Vlasenko285ad152009-12-04 23:02:27 +01004378 int status = psend[-1].ps_status;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004379 if (jp->state == JOBSTOPPED)
4380 status = jp->stopstatus;
Denys Vlasenko9c541002015-10-07 15:44:36 +02004381 col += sprint_status48(s + col, status, 0);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004382 }
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004383 /* By now, "[JOBID]* [maybe PID] STATUS" is printed */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004384
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004385 /* This loop either prints "<cmd1> | <cmd2> | <cmd3>" line
4386 * or prints several "PID | <cmdN>" lines,
4387 * depending on SHOW_PIDS bit.
4388 * We do not print status of individual processes
4389 * between PID and <cmdN>. bash does it, but not very well:
4390 * first line shows overall job status, not process status,
4391 * making it impossible to know 1st process status.
4392 */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004393 goto start;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004394 do {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004395 /* for each process */
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004396 s[0] = '\0';
4397 col = 33;
4398 if (mode & SHOW_PIDS)
Denys Vlasenko285ad152009-12-04 23:02:27 +01004399 col = fmtstr(s, 48, "\n%*c%d ", indent_col, ' ', ps->ps_pid) - 1;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004400 start:
Denys Vlasenko285ad152009-12-04 23:02:27 +01004401 fprintf(out, "%s%*c%s%s",
4402 s,
4403 33 - col >= 0 ? 33 - col : 0, ' ',
4404 ps == jp->ps ? "" : "| ",
4405 ps->ps_cmd
4406 );
4407 } while (++ps != psend);
Denys Vlasenko9c541002015-10-07 15:44:36 +02004408 newline_and_flush(out);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004409
4410 jp->changed = 0;
4411
4412 if (jp->state == JOBDONE) {
4413 TRACE(("showjob: freeing job %d\n", jobno(jp)));
4414 freejob(jp);
4415 }
4416}
4417
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004418/*
4419 * Print a list of jobs. If "change" is nonzero, only print jobs whose
4420 * statuses have changed since the last call to showjobs.
4421 */
4422static void
Denys Vlasenko9c541002015-10-07 15:44:36 +02004423showjobs(int mode)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004424{
4425 struct job *jp;
4426
Denys Vlasenko883cea42009-07-11 15:31:59 +02004427 TRACE(("showjobs(0x%x) called\n", mode));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004428
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004429 /* Handle all finished jobs */
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004430 while (dowait(DOWAIT_NONBLOCK, NULL) > 0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004431 continue;
4432
4433 for (jp = curjob; jp; jp = jp->prev_job) {
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004434 if (!(mode & SHOW_CHANGED) || jp->changed) {
Denys Vlasenko9c541002015-10-07 15:44:36 +02004435 showjob(jp, mode);
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004436 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004437 }
4438}
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004439
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02004440static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00004441jobscmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004442{
4443 int mode, m;
4444
4445 mode = 0;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02004446 while ((m = nextopt("lp")) != '\0') {
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004447 if (m == 'l')
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004448 mode |= SHOW_PIDS;
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004449 else
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004450 mode |= SHOW_ONLY_PGID;
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004451 }
4452
4453 argv = argptr;
4454 if (*argv) {
4455 do
Denys Vlasenko9c541002015-10-07 15:44:36 +02004456 showjob(getjob(*argv, 0), mode);
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004457 while (*++argv);
Denys Vlasenko285ad152009-12-04 23:02:27 +01004458 } else {
Denys Vlasenko9c541002015-10-07 15:44:36 +02004459 showjobs(mode);
Denys Vlasenko285ad152009-12-04 23:02:27 +01004460 }
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004461
4462 return 0;
4463}
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004464#endif /* JOBS */
4465
Michael Abbott359da5e2009-12-04 23:03:29 +01004466/* Called only on finished or stopped jobs (no members are running) */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004467static int
4468getstatus(struct job *job)
4469{
4470 int status;
4471 int retval;
Michael Abbott359da5e2009-12-04 23:03:29 +01004472 struct procstat *ps;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004473
Michael Abbott359da5e2009-12-04 23:03:29 +01004474 /* Fetch last member's status */
4475 ps = job->ps + job->nprocs - 1;
4476 status = ps->ps_status;
4477 if (pipefail) {
4478 /* "set -o pipefail" mode: use last _nonzero_ status */
4479 while (status == 0 && --ps >= job->ps)
4480 status = ps->ps_status;
4481 }
4482
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004483 retval = WEXITSTATUS(status);
4484 if (!WIFEXITED(status)) {
4485#if JOBS
4486 retval = WSTOPSIG(status);
4487 if (!WIFSTOPPED(status))
4488#endif
4489 {
4490 /* XXX: limits number of signals */
4491 retval = WTERMSIG(status);
4492#if JOBS
4493 if (retval == SIGINT)
4494 job->sigint = 1;
4495#endif
4496 }
4497 retval += 128;
4498 }
Denys Vlasenko883cea42009-07-11 15:31:59 +02004499 TRACE(("getstatus: job %d, nproc %d, status 0x%x, retval 0x%x\n",
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004500 jobno(job), job->nprocs, status, retval));
4501 return retval;
4502}
4503
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02004504static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00004505waitcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004506{
4507 struct job *job;
4508 int retval;
4509 struct job *jp;
4510
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004511 nextopt(nullstr);
4512 retval = 0;
4513
4514 argv = argptr;
4515 if (!*argv) {
4516 /* wait for all jobs */
4517 for (;;) {
4518 jp = curjob;
4519 while (1) {
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004520 if (!jp) /* no running procs */
4521 goto ret;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004522 if (jp->state == JOBRUNNING)
4523 break;
4524 jp->waited = 1;
4525 jp = jp->prev_job;
4526 }
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004527 /* man bash:
4528 * "When bash is waiting for an asynchronous command via
4529 * the wait builtin, the reception of a signal for which a trap
4530 * has been set will cause the wait builtin to return immediately
4531 * with an exit status greater than 128, immediately after which
4532 * the trap is executed."
Denys Vlasenko69188112016-10-27 20:18:18 +02004533 */
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004534 dowait(DOWAIT_BLOCK_OR_SIG, NULL);
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02004535 /* if child sends us a signal *and immediately exits*,
4536 * dowait() returns pid > 0. Check this case,
4537 * not "if (dowait() < 0)"!
4538 */
Denys Vlasenko7c1ed9f2010-05-17 04:42:40 +02004539 if (pending_sig)
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02004540 goto sigout;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004541 }
4542 }
4543
4544 retval = 127;
4545 do {
4546 if (**argv != '%') {
4547 pid_t pid = number(*argv);
4548 job = curjob;
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004549 while (1) {
4550 if (!job)
4551 goto repeat;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004552 if (job->ps[job->nprocs - 1].ps_pid == pid)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004553 break;
4554 job = job->prev_job;
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004555 }
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004556 } else {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004557 job = getjob(*argv, 0);
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004558 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004559 /* loop until process terminated or stopped */
Denys Vlasenko69188112016-10-27 20:18:18 +02004560 while (job->state == JOBRUNNING) {
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004561 dowait(DOWAIT_BLOCK_OR_SIG, NULL);
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02004562 if (pending_sig)
4563 goto sigout;
Denys Vlasenko69188112016-10-27 20:18:18 +02004564 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004565 job->waited = 1;
4566 retval = getstatus(job);
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004567 repeat: ;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004568 } while (*++argv);
4569
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004570 ret:
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004571 return retval;
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02004572 sigout:
4573 retval = 128 + pending_sig;
4574 return retval;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004575}
4576
4577static struct job *
4578growjobtab(void)
4579{
4580 size_t len;
4581 ptrdiff_t offset;
4582 struct job *jp, *jq;
4583
4584 len = njobs * sizeof(*jp);
4585 jq = jobtab;
4586 jp = ckrealloc(jq, len + 4 * sizeof(*jp));
4587
4588 offset = (char *)jp - (char *)jq;
4589 if (offset) {
4590 /* Relocate pointers */
4591 size_t l = len;
4592
4593 jq = (struct job *)((char *)jq + l);
4594 while (l) {
4595 l -= sizeof(*jp);
4596 jq--;
4597#define joff(p) ((struct job *)((char *)(p) + l))
4598#define jmove(p) (p) = (void *)((char *)(p) + offset)
4599 if (joff(jp)->ps == &jq->ps0)
4600 jmove(joff(jp)->ps);
4601 if (joff(jp)->prev_job)
4602 jmove(joff(jp)->prev_job);
4603 }
4604 if (curjob)
4605 jmove(curjob);
4606#undef joff
4607#undef jmove
4608 }
4609
4610 njobs += 4;
4611 jobtab = jp;
4612 jp = (struct job *)((char *)jp + len);
4613 jq = jp + 3;
4614 do {
4615 jq->used = 0;
4616 } while (--jq >= jp);
4617 return jp;
4618}
4619
4620/*
4621 * Return a new job structure.
4622 * Called with interrupts off.
4623 */
4624static struct job *
Denis Vlasenko68404f12008-03-17 09:00:54 +00004625makejob(/*union node *node,*/ int nprocs)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004626{
4627 int i;
4628 struct job *jp;
4629
4630 for (i = njobs, jp = jobtab; ; jp++) {
4631 if (--i < 0) {
4632 jp = growjobtab();
4633 break;
4634 }
4635 if (jp->used == 0)
4636 break;
4637 if (jp->state != JOBDONE || !jp->waited)
4638 continue;
4639#if JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +00004640 if (doing_jobctl)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004641 continue;
4642#endif
4643 freejob(jp);
4644 break;
4645 }
4646 memset(jp, 0, sizeof(*jp));
4647#if JOBS
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004648 /* jp->jobctl is a bitfield.
Denys Vlasenko098b7132017-01-11 19:59:03 +01004649 * "jp->jobctl |= doing_jobctl" likely to give awful code */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00004650 if (doing_jobctl)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004651 jp->jobctl = 1;
4652#endif
4653 jp->prev_job = curjob;
4654 curjob = jp;
4655 jp->used = 1;
4656 jp->ps = &jp->ps0;
4657 if (nprocs > 1) {
4658 jp->ps = ckmalloc(nprocs * sizeof(struct procstat));
4659 }
Denis Vlasenko68404f12008-03-17 09:00:54 +00004660 TRACE(("makejob(%d) returns %%%d\n", nprocs,
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004661 jobno(jp)));
4662 return jp;
4663}
4664
4665#if JOBS
4666/*
4667 * Return a string identifying a command (to be printed by the
4668 * jobs command).
4669 */
4670static char *cmdnextc;
4671
4672static void
4673cmdputs(const char *s)
4674{
Denis Vlasenko92e13c22008-03-25 01:17:40 +00004675 static const char vstype[VSTYPE + 1][3] = {
4676 "", "}", "-", "+", "?", "=",
4677 "%", "%%", "#", "##"
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01004678 IF_BASH_SUBSTR(, ":")
4679 IF_BASH_PATTERN_SUBST(, "/", "//")
Denis Vlasenko92e13c22008-03-25 01:17:40 +00004680 };
4681
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004682 const char *p, *str;
Denys Vlasenko46a14772009-12-10 21:27:13 +01004683 char cc[2];
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004684 char *nextc;
Denys Vlasenkocd716832009-11-28 22:14:02 +01004685 unsigned char c;
4686 unsigned char subtype = 0;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004687 int quoted = 0;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004688
Denys Vlasenko46a14772009-12-10 21:27:13 +01004689 cc[1] = '\0';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004690 nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
4691 p = s;
Denys Vlasenko46a14772009-12-10 21:27:13 +01004692 while ((c = *p++) != '\0') {
Denis Vlasenkoef527f52008-06-23 01:52:30 +00004693 str = NULL;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004694 switch (c) {
4695 case CTLESC:
4696 c = *p++;
4697 break;
4698 case CTLVAR:
4699 subtype = *p++;
4700 if ((subtype & VSTYPE) == VSLENGTH)
4701 str = "${#";
4702 else
4703 str = "${";
Ron Yorston549deab2015-05-18 09:57:51 +02004704 goto dostr;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004705 case CTLENDVAR:
4706 str = "\"}" + !(quoted & 1);
4707 quoted >>= 1;
4708 subtype = 0;
4709 goto dostr;
4710 case CTLBACKQ:
4711 str = "$(...)";
4712 goto dostr;
Denys Vlasenko0b883582016-12-23 16:49:07 +01004713#if ENABLE_FEATURE_SH_MATH
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004714 case CTLARI:
4715 str = "$((";
4716 goto dostr;
4717 case CTLENDARI:
4718 str = "))";
4719 goto dostr;
4720#endif
4721 case CTLQUOTEMARK:
4722 quoted ^= 1;
4723 c = '"';
4724 break;
4725 case '=':
4726 if (subtype == 0)
4727 break;
4728 if ((subtype & VSTYPE) != VSNORMAL)
4729 quoted <<= 1;
4730 str = vstype[subtype & VSTYPE];
4731 if (subtype & VSNUL)
4732 c = ':';
4733 else
4734 goto checkstr;
4735 break;
4736 case '\'':
4737 case '\\':
4738 case '"':
4739 case '$':
4740 /* These can only happen inside quotes */
4741 cc[0] = c;
4742 str = cc;
Denys Vlasenkod0fff912017-07-31 14:32:18 +02004743//FIXME:
4744// $ true $$ &
4745// $ <cr>
4746// [1]+ Done true ${\$} <<=== BUG: ${\$} is not a valid way to write $$ (${$} would be ok)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004747 c = '\\';
4748 break;
4749 default:
4750 break;
4751 }
4752 USTPUTC(c, nextc);
4753 checkstr:
4754 if (!str)
4755 continue;
4756 dostr:
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02004757 while ((c = *str++) != '\0') {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004758 USTPUTC(c, nextc);
4759 }
Denys Vlasenko46a14772009-12-10 21:27:13 +01004760 } /* while *p++ not NUL */
4761
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004762 if (quoted & 1) {
4763 USTPUTC('"', nextc);
4764 }
4765 *nextc = 0;
4766 cmdnextc = nextc;
4767}
4768
4769/* cmdtxt() and cmdlist() call each other */
4770static void cmdtxt(union node *n);
4771
4772static void
4773cmdlist(union node *np, int sep)
4774{
4775 for (; np; np = np->narg.next) {
4776 if (!sep)
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00004777 cmdputs(" ");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004778 cmdtxt(np);
4779 if (sep && np->narg.next)
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00004780 cmdputs(" ");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004781 }
4782}
4783
4784static void
4785cmdtxt(union node *n)
4786{
4787 union node *np;
4788 struct nodelist *lp;
4789 const char *p;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004790
4791 if (!n)
4792 return;
4793 switch (n->type) {
4794 default:
4795#if DEBUG
4796 abort();
4797#endif
4798 case NPIPE:
4799 lp = n->npipe.cmdlist;
4800 for (;;) {
4801 cmdtxt(lp->n);
4802 lp = lp->next;
4803 if (!lp)
4804 break;
4805 cmdputs(" | ");
4806 }
4807 break;
4808 case NSEMI:
4809 p = "; ";
4810 goto binop;
4811 case NAND:
4812 p = " && ";
4813 goto binop;
4814 case NOR:
4815 p = " || ";
4816 binop:
4817 cmdtxt(n->nbinary.ch1);
4818 cmdputs(p);
4819 n = n->nbinary.ch2;
4820 goto donode;
4821 case NREDIR:
4822 case NBACKGND:
4823 n = n->nredir.n;
4824 goto donode;
4825 case NNOT:
4826 cmdputs("!");
4827 n = n->nnot.com;
4828 donode:
4829 cmdtxt(n);
4830 break;
4831 case NIF:
4832 cmdputs("if ");
4833 cmdtxt(n->nif.test);
4834 cmdputs("; then ");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004835 if (n->nif.elsepart) {
Denys Vlasenko7cee00e2009-07-24 01:08:03 +02004836 cmdtxt(n->nif.ifpart);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004837 cmdputs("; else ");
4838 n = n->nif.elsepart;
Denys Vlasenko7cee00e2009-07-24 01:08:03 +02004839 } else {
4840 n = n->nif.ifpart;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004841 }
4842 p = "; fi";
4843 goto dotail;
4844 case NSUBSHELL:
4845 cmdputs("(");
4846 n = n->nredir.n;
4847 p = ")";
4848 goto dotail;
4849 case NWHILE:
4850 p = "while ";
4851 goto until;
4852 case NUNTIL:
4853 p = "until ";
4854 until:
4855 cmdputs(p);
4856 cmdtxt(n->nbinary.ch1);
4857 n = n->nbinary.ch2;
4858 p = "; done";
4859 dodo:
4860 cmdputs("; do ");
4861 dotail:
4862 cmdtxt(n);
4863 goto dotail2;
4864 case NFOR:
4865 cmdputs("for ");
4866 cmdputs(n->nfor.var);
4867 cmdputs(" in ");
4868 cmdlist(n->nfor.args, 1);
4869 n = n->nfor.body;
4870 p = "; done";
4871 goto dodo;
4872 case NDEFUN:
Denys Vlasenko675d24a2018-01-27 22:02:05 +01004873 cmdputs(n->ndefun.text);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004874 p = "() { ... }";
4875 goto dotail2;
4876 case NCMD:
4877 cmdlist(n->ncmd.args, 1);
4878 cmdlist(n->ncmd.redirect, 0);
4879 break;
4880 case NARG:
4881 p = n->narg.text;
4882 dotail2:
4883 cmdputs(p);
4884 break;
4885 case NHERE:
4886 case NXHERE:
4887 p = "<<...";
4888 goto dotail2;
4889 case NCASE:
4890 cmdputs("case ");
4891 cmdputs(n->ncase.expr->narg.text);
4892 cmdputs(" in ");
4893 for (np = n->ncase.cases; np; np = np->nclist.next) {
4894 cmdtxt(np->nclist.pattern);
4895 cmdputs(") ");
4896 cmdtxt(np->nclist.body);
4897 cmdputs(";; ");
4898 }
4899 p = "esac";
4900 goto dotail2;
4901 case NTO:
4902 p = ">";
4903 goto redir;
4904 case NCLOBBER:
4905 p = ">|";
4906 goto redir;
4907 case NAPPEND:
4908 p = ">>";
4909 goto redir;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01004910#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00004911 case NTO2:
4912#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004913 case NTOFD:
4914 p = ">&";
4915 goto redir;
4916 case NFROM:
4917 p = "<";
4918 goto redir;
4919 case NFROMFD:
4920 p = "<&";
4921 goto redir;
4922 case NFROMTO:
4923 p = "<>";
4924 redir:
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00004925 cmdputs(utoa(n->nfile.fd));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004926 cmdputs(p);
4927 if (n->type == NTOFD || n->type == NFROMFD) {
Denys Vlasenkod0fff912017-07-31 14:32:18 +02004928 if (n->ndup.dupfd >= 0)
4929 cmdputs(utoa(n->ndup.dupfd));
4930 else
4931 cmdputs("-");
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00004932 break;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004933 }
4934 n = n->nfile.fname;
4935 goto donode;
4936 }
4937}
4938
4939static char *
4940commandtext(union node *n)
4941{
4942 char *name;
4943
4944 STARTSTACKSTR(cmdnextc);
4945 cmdtxt(n);
4946 name = stackblock();
Denys Vlasenko6a94cee2016-10-25 17:40:25 +02004947 TRACE(("commandtext: name %p, end %p\n", name, cmdnextc));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004948 return ckstrdup(name);
4949}
4950#endif /* JOBS */
4951
4952/*
4953 * Fork off a subshell. If we are doing job control, give the subshell its
4954 * own process group. Jp is a job structure that the job is to be added to.
4955 * N is the command that will be evaluated by the child. Both jp and n may
4956 * be NULL. The mode parameter can be one of the following:
4957 * FORK_FG - Fork off a foreground process.
4958 * FORK_BG - Fork off a background process.
4959 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
4960 * process group even if job control is on.
4961 *
4962 * When job control is turned off, background processes have their standard
4963 * input redirected to /dev/null (except for the second and later processes
4964 * in a pipeline).
4965 *
4966 * Called with interrupts off.
4967 */
4968/*
4969 * Clear traps on a fork.
4970 */
4971static void
4972clear_traps(void)
4973{
4974 char **tp;
4975
Denys Vlasenkob4f51d32016-10-27 12:55:09 +02004976 INT_OFF;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004977 for (tp = trap; tp < &trap[NSIG]; tp++) {
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004978 if (*tp && **tp) { /* trap not NULL or "" (SIG_IGN) */
Denys Vlasenkoe305c282009-09-25 02:12:27 +02004979 if (trap_ptr == trap)
4980 free(*tp);
4981 /* else: it "belongs" to trap_ptr vector, don't free */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004982 *tp = NULL;
Denys Vlasenko0800e3a2009-09-24 03:09:26 +02004983 if ((tp - trap) != 0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004984 setsignal(tp - trap);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004985 }
4986 }
Alexander Shishkinccb97712010-07-25 13:07:39 +02004987 may_have_traps = 0;
Denys Vlasenkob4f51d32016-10-27 12:55:09 +02004988 INT_ON;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004989}
Denis Vlasenkobdc406d2007-07-15 01:13:25 +00004990
4991/* Lives far away from here, needed for forkchild */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004992static void closescript(void);
Denis Vlasenko41770222007-10-07 18:02:52 +00004993
Denis Vlasenkobdc406d2007-07-15 01:13:25 +00004994/* Called after fork(), in child */
Denys Vlasenko70392332016-10-27 02:31:55 +02004995/* jp and n are NULL when called by openhere() for heredoc support */
Denys Vlasenko21d87d42009-09-25 00:06:51 +02004996static NOINLINE void
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02004997forkchild(struct job *jp, union node *n, int mode)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004998{
4999 int oldlvl;
5000
5001 TRACE(("Child shell %d\n", getpid()));
5002 oldlvl = shlvl;
5003 shlvl++;
5004
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005005 /* man bash: "Non-builtin commands run by bash have signal handlers
5006 * set to the values inherited by the shell from its parent".
5007 * Do we do it correctly? */
5008
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005009 closescript();
Denys Vlasenko844f9902009-09-23 03:25:52 +02005010
5011 if (mode == FORK_NOJOB /* is it `xxx` ? */
5012 && n && n->type == NCMD /* is it single cmd? */
5013 /* && n->ncmd.args->type == NARG - always true? */
Denys Vlasenko74269202010-02-21 01:26:42 +01005014 && n->ncmd.args && strcmp(n->ncmd.args->narg.text, "trap") == 0
Denys Vlasenko844f9902009-09-23 03:25:52 +02005015 && n->ncmd.args->narg.next == NULL /* "trap" with no arguments */
5016 /* && n->ncmd.args->narg.backquote == NULL - do we need to check this? */
5017 ) {
5018 TRACE(("Trap hack\n"));
5019 /* Awful hack for `trap` or $(trap).
5020 *
5021 * http://www.opengroup.org/onlinepubs/009695399/utilities/trap.html
5022 * contains an example where "trap" is executed in a subshell:
5023 *
5024 * save_traps=$(trap)
5025 * ...
5026 * eval "$save_traps"
5027 *
5028 * Standard does not say that "trap" in subshell shall print
5029 * parent shell's traps. It only says that its output
5030 * must have suitable form, but then, in the above example
5031 * (which is not supposed to be normative), it implies that.
5032 *
5033 * bash (and probably other shell) does implement it
5034 * (traps are reset to defaults, but "trap" still shows them),
5035 * but as a result, "trap" logic is hopelessly messed up:
5036 *
5037 * # trap
5038 * trap -- 'echo Ho' SIGWINCH <--- we have a handler
5039 * # (trap) <--- trap is in subshell - no output (correct, traps are reset)
5040 * # true | trap <--- trap is in subshell - no output (ditto)
5041 * # echo `true | trap` <--- in subshell - output (but traps are reset!)
5042 * trap -- 'echo Ho' SIGWINCH
5043 * # echo `(trap)` <--- in subshell in subshell - output
5044 * trap -- 'echo Ho' SIGWINCH
5045 * # echo `true | (trap)` <--- in subshell in subshell in subshell - output!
5046 * trap -- 'echo Ho' SIGWINCH
5047 *
5048 * The rules when to forget and when to not forget traps
5049 * get really complex and nonsensical.
5050 *
5051 * Our solution: ONLY bare $(trap) or `trap` is special.
5052 */
Denys Vlasenko8f88d852009-09-25 12:12:53 +02005053 /* Save trap handler strings for trap builtin to print */
Ron Yorstond840c5d2015-07-19 23:05:20 +02005054 trap_ptr = xmemdup(trap, sizeof(trap));
Denys Vlasenko8f88d852009-09-25 12:12:53 +02005055 /* Fall through into clearing traps */
Denys Vlasenko844f9902009-09-23 03:25:52 +02005056 }
Denys Vlasenkoe305c282009-09-25 02:12:27 +02005057 clear_traps();
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005058#if JOBS
5059 /* do job control only in root shell */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00005060 doing_jobctl = 0;
Denys Vlasenkob12553f2011-02-21 03:22:20 +01005061 if (mode != FORK_NOJOB && jp->jobctl && oldlvl == 0) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005062 pid_t pgrp;
5063
5064 if (jp->nprocs == 0)
5065 pgrp = getpid();
5066 else
Denys Vlasenko285ad152009-12-04 23:02:27 +01005067 pgrp = jp->ps[0].ps_pid;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005068 /* this can fail because we are doing it in the parent also */
5069 setpgid(0, pgrp);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005070 if (mode == FORK_FG)
5071 xtcsetpgrp(ttyfd, pgrp);
5072 setsignal(SIGTSTP);
5073 setsignal(SIGTTOU);
5074 } else
5075#endif
5076 if (mode == FORK_BG) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005077 /* man bash: "When job control is not in effect,
5078 * asynchronous commands ignore SIGINT and SIGQUIT" */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005079 ignoresig(SIGINT);
5080 ignoresig(SIGQUIT);
5081 if (jp->nprocs == 0) {
5082 close(0);
5083 if (open(bb_dev_null, O_RDONLY) != 0)
Denys Vlasenko12ffefb2017-08-23 14:52:56 +02005084 ash_msg_and_raise_perror("can't open '%s'", bb_dev_null);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005085 }
5086 }
Denys Vlasenkob12553f2011-02-21 03:22:20 +01005087 if (oldlvl == 0) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005088 if (iflag) { /* why if iflag only? */
5089 setsignal(SIGINT);
5090 setsignal(SIGTERM);
5091 }
5092 /* man bash:
5093 * "In all cases, bash ignores SIGQUIT. Non-builtin
5094 * commands run by bash have signal handlers
5095 * set to the values inherited by the shell
5096 * from its parent".
5097 * Take care of the second rule: */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005098 setsignal(SIGQUIT);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005099 }
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02005100#if JOBS
Denys Vlasenko844f9902009-09-23 03:25:52 +02005101 if (n && n->type == NCMD
Denys Vlasenko74269202010-02-21 01:26:42 +01005102 && n->ncmd.args && strcmp(n->ncmd.args->narg.text, "jobs") == 0
Denys Vlasenko844f9902009-09-23 03:25:52 +02005103 ) {
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02005104 TRACE(("Job hack\n"));
Denys Vlasenko844f9902009-09-23 03:25:52 +02005105 /* "jobs": we do not want to clear job list for it,
5106 * instead we remove only _its_ own_ job from job list.
5107 * This makes "jobs .... | cat" more useful.
5108 */
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02005109 freejob(curjob);
5110 return;
5111 }
5112#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005113 for (jp = curjob; jp; jp = jp->prev_job)
5114 freejob(jp);
5115 jobless = 0;
5116}
5117
Denis Vlasenkobdc406d2007-07-15 01:13:25 +00005118/* Called after fork(), in parent */
Denis Vlasenko85c24712008-03-17 09:04:04 +00005119#if !JOBS
5120#define forkparent(jp, n, mode, pid) forkparent(jp, mode, pid)
5121#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005122static void
5123forkparent(struct job *jp, union node *n, int mode, pid_t pid)
5124{
5125 TRACE(("In parent shell: child = %d\n", pid));
5126 if (!jp) {
Denys Vlasenko70392332016-10-27 02:31:55 +02005127 /* jp is NULL when called by openhere() for heredoc support */
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00005128 while (jobless && dowait(DOWAIT_NONBLOCK, NULL) > 0)
5129 continue;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005130 jobless++;
5131 return;
5132 }
5133#if JOBS
5134 if (mode != FORK_NOJOB && jp->jobctl) {
5135 int pgrp;
5136
5137 if (jp->nprocs == 0)
5138 pgrp = pid;
5139 else
Denys Vlasenko285ad152009-12-04 23:02:27 +01005140 pgrp = jp->ps[0].ps_pid;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005141 /* This can fail because we are doing it in the child also */
5142 setpgid(pid, pgrp);
5143 }
5144#endif
5145 if (mode == FORK_BG) {
5146 backgndpid = pid; /* set $! */
5147 set_curjob(jp, CUR_RUNNING);
5148 }
5149 if (jp) {
5150 struct procstat *ps = &jp->ps[jp->nprocs++];
Denys Vlasenko285ad152009-12-04 23:02:27 +01005151 ps->ps_pid = pid;
5152 ps->ps_status = -1;
5153 ps->ps_cmd = nullstr;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005154#if JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +00005155 if (doing_jobctl && n)
Denys Vlasenko285ad152009-12-04 23:02:27 +01005156 ps->ps_cmd = commandtext(n);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005157#endif
5158 }
5159}
5160
Denys Vlasenko70392332016-10-27 02:31:55 +02005161/* jp and n are NULL when called by openhere() for heredoc support */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005162static int
5163forkshell(struct job *jp, union node *n, int mode)
5164{
5165 int pid;
5166
5167 TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
5168 pid = fork();
5169 if (pid < 0) {
5170 TRACE(("Fork failed, errno=%d", errno));
5171 if (jp)
5172 freejob(jp);
Denys Vlasenko12ffefb2017-08-23 14:52:56 +02005173 ash_msg_and_raise_perror("can't fork");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005174 }
Denys Vlasenko76ace252009-10-12 15:25:01 +02005175 if (pid == 0) {
5176 CLEAR_RANDOM_T(&random_gen); /* or else $RANDOM repeats in child */
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02005177 forkchild(jp, n, mode);
Denys Vlasenko76ace252009-10-12 15:25:01 +02005178 } else {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005179 forkparent(jp, n, mode, pid);
Denys Vlasenko76ace252009-10-12 15:25:01 +02005180 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005181 return pid;
5182}
5183
5184/*
5185 * Wait for job to finish.
5186 *
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005187 * Under job control we have the problem that while a child process
5188 * is running interrupts generated by the user are sent to the child
5189 * but not to the shell. This means that an infinite loop started by
5190 * an interactive user may be hard to kill. With job control turned off,
5191 * an interactive user may place an interactive program inside a loop.
5192 * If the interactive program catches interrupts, the user doesn't want
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005193 * these interrupts to also abort the loop. The approach we take here
5194 * is to have the shell ignore interrupt signals while waiting for a
5195 * foreground process to terminate, and then send itself an interrupt
5196 * signal if the child process was terminated by an interrupt signal.
5197 * Unfortunately, some programs want to do a bit of cleanup and then
5198 * exit on interrupt; unless these processes terminate themselves by
5199 * sending a signal to themselves (instead of calling exit) they will
5200 * confuse this approach.
5201 *
5202 * Called with interrupts off.
5203 */
5204static int
5205waitforjob(struct job *jp)
5206{
5207 int st;
5208
5209 TRACE(("waitforjob(%%%d) called\n", jobno(jp)));
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005210
5211 INT_OFF;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005212 while (jp->state == JOBRUNNING) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005213 /* In non-interactive shells, we _can_ get
5214 * a keyboard signal here and be EINTRed,
5215 * but we just loop back, waiting for command to complete.
5216 *
5217 * man bash:
5218 * "If bash is waiting for a command to complete and receives
5219 * a signal for which a trap has been set, the trap
5220 * will not be executed until the command completes."
5221 *
5222 * Reality is that even if trap is not set, bash
5223 * will not act on the signal until command completes.
5224 * Try this. sleep5intoff.c:
5225 * #include <signal.h>
5226 * #include <unistd.h>
5227 * int main() {
5228 * sigset_t set;
5229 * sigemptyset(&set);
5230 * sigaddset(&set, SIGINT);
5231 * sigaddset(&set, SIGQUIT);
5232 * sigprocmask(SIG_BLOCK, &set, NULL);
5233 * sleep(5);
5234 * return 0;
5235 * }
5236 * $ bash -c './sleep5intoff; echo hi'
5237 * ^C^C^C^C <--- pressing ^C once a second
5238 * $ _
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005239 * $ bash -c './sleep5intoff; echo hi'
5240 * ^\^\^\^\hi <--- pressing ^\ (SIGQUIT)
5241 * $ _
5242 */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005243 dowait(DOWAIT_BLOCK, jp);
5244 }
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005245 INT_ON;
5246
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005247 st = getstatus(jp);
5248#if JOBS
5249 if (jp->jobctl) {
5250 xtcsetpgrp(ttyfd, rootpid);
Denys Vlasenko098b7132017-01-11 19:59:03 +01005251 restore_tty_if_stopped_or_signaled(jp);
5252
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005253 /*
5254 * This is truly gross.
5255 * If we're doing job control, then we did a TIOCSPGRP which
5256 * caused us (the shell) to no longer be in the controlling
5257 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
5258 * intuit from the subprocess exit status whether a SIGINT
5259 * occurred, and if so interrupt ourselves. Yuck. - mycroft
5260 */
Denis Vlasenko991a1da2008-02-10 19:02:53 +00005261 if (jp->sigint) /* TODO: do the same with all signals */
5262 raise(SIGINT); /* ... by raise(jp->sig) instead? */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005263 }
5264 if (jp->state == JOBDONE)
5265#endif
5266 freejob(jp);
5267 return st;
5268}
5269
5270/*
5271 * return 1 if there are stopped jobs, otherwise 0
5272 */
5273static int
5274stoppedjobs(void)
5275{
5276 struct job *jp;
5277 int retval;
5278
5279 retval = 0;
5280 if (job_warning)
5281 goto out;
5282 jp = curjob;
5283 if (jp && jp->state == JOBSTOPPED) {
5284 out2str("You have stopped jobs.\n");
5285 job_warning = 2;
5286 retval++;
5287 }
5288 out:
5289 return retval;
5290}
5291
5292
Denys Vlasenko70392332016-10-27 02:31:55 +02005293/*
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005294 * Code for dealing with input/output redirection.
5295 */
5296
Denys Vlasenko8d0e0cd2011-01-25 23:21:46 +01005297#undef EMPTY
5298#undef CLOSED
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005299#define EMPTY -2 /* marks an unused slot in redirtab */
Denys Vlasenko035486c2017-07-31 04:09:19 +02005300#define CLOSED -1 /* marks a slot of previously-closed fd */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005301
5302/*
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005303 * Handle here documents. Normally we fork off a process to write the
5304 * data to a pipe. If the document is short, we can stuff the data in
5305 * the pipe without forking.
5306 */
5307/* openhere needs this forward reference */
5308static void expandhere(union node *arg, int fd);
5309static int
5310openhere(union node *redir)
5311{
5312 int pip[2];
5313 size_t len = 0;
5314
5315 if (pipe(pip) < 0)
Denys Vlasenko12ffefb2017-08-23 14:52:56 +02005316 ash_msg_and_raise_perror("can't create pipe");
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005317 if (redir->type == NHERE) {
5318 len = strlen(redir->nhere.doc->narg.text);
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005319 if (len <= PIPE_BUF) {
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005320 full_write(pip[1], redir->nhere.doc->narg.text, len);
5321 goto out;
5322 }
5323 }
5324 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
Denis Vlasenko0b769642008-07-24 07:54:57 +00005325 /* child */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005326 close(pip[0]);
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005327 ignoresig(SIGINT); //signal(SIGINT, SIG_IGN);
5328 ignoresig(SIGQUIT); //signal(SIGQUIT, SIG_IGN);
5329 ignoresig(SIGHUP); //signal(SIGHUP, SIG_IGN);
5330 ignoresig(SIGTSTP); //signal(SIGTSTP, SIG_IGN);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005331 signal(SIGPIPE, SIG_DFL);
5332 if (redir->type == NHERE)
5333 full_write(pip[1], redir->nhere.doc->narg.text, len);
Denis Vlasenko0b769642008-07-24 07:54:57 +00005334 else /* NXHERE */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005335 expandhere(redir->nhere.doc, pip[1]);
Bernhard Reutner-Fischer636a1f82008-05-19 09:29:47 +00005336 _exit(EXIT_SUCCESS);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005337 }
5338 out:
5339 close(pip[1]);
5340 return pip[0];
5341}
5342
5343static int
5344openredirect(union node *redir)
5345{
Denys Vlasenkof1a5cb02017-07-25 17:47:48 +02005346 struct stat sb;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005347 char *fname;
5348 int f;
5349
5350 switch (redir->nfile.type) {
Denys Vlasenko557482c2016-09-25 21:24:04 +02005351/* Can't happen, our single caller does this itself */
5352// case NTOFD:
5353// case NFROMFD:
5354// return -1;
5355 case NHERE:
5356 case NXHERE:
5357 return openhere(redir);
5358 }
5359
5360 /* For N[X]HERE, reading redir->nfile.expfname would touch beyond
5361 * allocated space. Do it only when we know it is safe.
5362 */
5363 fname = redir->nfile.expfname;
5364
5365 switch (redir->nfile.type) {
5366 default:
5367#if DEBUG
5368 abort();
5369#endif
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005370 case NFROM:
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005371 f = open(fname, O_RDONLY);
5372 if (f < 0)
5373 goto eopen;
5374 break;
5375 case NFROMTO:
Andreas Bühmannda75f442010-06-24 04:32:37 +02005376 f = open(fname, O_RDWR|O_CREAT, 0666);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005377 if (f < 0)
5378 goto ecreate;
5379 break;
5380 case NTO:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01005381#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00005382 case NTO2:
5383#endif
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005384 /* Take care of noclobber mode. */
5385 if (Cflag) {
Denys Vlasenkof1a5cb02017-07-25 17:47:48 +02005386 if (stat(fname, &sb) < 0) {
5387 f = open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
5388 if (f < 0)
5389 goto ecreate;
5390 } else if (!S_ISREG(sb.st_mode)) {
5391 f = open(fname, O_WRONLY, 0666);
5392 if (f < 0)
5393 goto ecreate;
Denys Vlasenko355ec352018-04-02 13:34:57 +02005394 if (!fstat(f, &sb) && S_ISREG(sb.st_mode)) {
Denys Vlasenkof1a5cb02017-07-25 17:47:48 +02005395 close(f);
5396 errno = EEXIST;
5397 goto ecreate;
5398 }
5399 } else {
5400 errno = EEXIST;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005401 goto ecreate;
Denys Vlasenkof1a5cb02017-07-25 17:47:48 +02005402 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005403 break;
5404 }
5405 /* FALLTHROUGH */
5406 case NCLOBBER:
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005407 f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666);
5408 if (f < 0)
5409 goto ecreate;
5410 break;
5411 case NAPPEND:
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005412 f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666);
5413 if (f < 0)
5414 goto ecreate;
5415 break;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005416 }
5417
5418 return f;
5419 ecreate:
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +00005420 ash_msg_and_raise_error("can't create %s: %s", fname, errmsg(errno, "nonexistent directory"));
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005421 eopen:
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +00005422 ash_msg_and_raise_error("can't open %s: %s", fname, errmsg(errno, "no such file"));
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005423}
5424
5425/*
Denys Vlasenko64774602016-10-26 15:24:30 +02005426 * Copy a file descriptor to be >= 10. Throws exception on error.
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005427 */
5428static int
Denys Vlasenko64774602016-10-26 15:24:30 +02005429savefd(int from)
5430{
5431 int newfd;
5432 int err;
5433
Denys Vlasenko60fb98e2018-03-30 22:15:14 +02005434 newfd = fcntl(from, F_DUPFD_CLOEXEC, 10);
Denys Vlasenko64774602016-10-26 15:24:30 +02005435 err = newfd < 0 ? errno : 0;
5436 if (err != EBADF) {
5437 if (err)
Ron Yorstonbe366e52017-07-27 13:53:39 +01005438 ash_msg_and_raise_perror("%d", from);
Denys Vlasenko64774602016-10-26 15:24:30 +02005439 close(from);
Denys Vlasenko60fb98e2018-03-30 22:15:14 +02005440 if (F_DUPFD_CLOEXEC == F_DUPFD)
5441 close_on_exec_on(newfd);
Denys Vlasenko64774602016-10-26 15:24:30 +02005442 }
5443
5444 return newfd;
5445}
5446static int
5447dup2_or_raise(int from, int to)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005448{
5449 int newfd;
5450
Denys Vlasenko64774602016-10-26 15:24:30 +02005451 newfd = (from != to) ? dup2(from, to) : to;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005452 if (newfd < 0) {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005453 /* Happens when source fd is not open: try "echo >&99" */
Ron Yorstonbe366e52017-07-27 13:53:39 +01005454 ash_msg_and_raise_perror("%d", from);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005455 }
5456 return newfd;
5457}
Denys Vlasenko035486c2017-07-31 04:09:19 +02005458static int
Denys Vlasenko9acd63c2018-03-28 18:35:07 +02005459dup_CLOEXEC(int fd, int avoid_fd)
Denys Vlasenko035486c2017-07-31 04:09:19 +02005460{
5461 int newfd;
5462 repeat:
Denys Vlasenko9acd63c2018-03-28 18:35:07 +02005463 newfd = fcntl(fd, F_DUPFD_CLOEXEC, avoid_fd + 1);
5464 if (newfd >= 0) {
5465 if (F_DUPFD_CLOEXEC == F_DUPFD) /* if old libc (w/o F_DUPFD_CLOEXEC) */
Denys Vlasenko60fb98e2018-03-30 22:15:14 +02005466 close_on_exec_on(newfd);
Denys Vlasenko9acd63c2018-03-28 18:35:07 +02005467 } else { /* newfd < 0 */
Denys Vlasenko035486c2017-07-31 04:09:19 +02005468 if (errno == EBUSY)
5469 goto repeat;
5470 if (errno == EINTR)
5471 goto repeat;
5472 }
5473 return newfd;
5474}
5475static int
5476xdup_CLOEXEC_and_close(int fd, int avoid_fd)
5477{
5478 int newfd;
5479 repeat:
Denys Vlasenko60fb98e2018-03-30 22:15:14 +02005480 newfd = fcntl(fd, F_DUPFD_CLOEXEC, avoid_fd + 1);
Denys Vlasenko035486c2017-07-31 04:09:19 +02005481 if (newfd < 0) {
5482 if (errno == EBUSY)
5483 goto repeat;
5484 if (errno == EINTR)
5485 goto repeat;
5486 /* fd was not open? */
5487 if (errno == EBADF)
5488 return fd;
5489 ash_msg_and_raise_perror("%d", newfd);
5490 }
Denys Vlasenko60fb98e2018-03-30 22:15:14 +02005491 if (F_DUPFD_CLOEXEC == F_DUPFD)
5492 close_on_exec_on(newfd);
Denys Vlasenko035486c2017-07-31 04:09:19 +02005493 close(fd);
5494 return newfd;
5495}
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005496
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005497/* Struct def and variable are moved down to the first usage site */
Denys Vlasenko035486c2017-07-31 04:09:19 +02005498struct squirrel {
5499 int orig_fd;
5500 int moved_to;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005501};
Denis Vlasenko0b769642008-07-24 07:54:57 +00005502struct redirtab {
5503 struct redirtab *next;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005504 int pair_count;
Denys Vlasenko035486c2017-07-31 04:09:19 +02005505 struct squirrel two_fd[];
Denis Vlasenko0b769642008-07-24 07:54:57 +00005506};
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005507#define redirlist (G_var.redirlist)
Denis Vlasenko0b769642008-07-24 07:54:57 +00005508
Denys Vlasenko035486c2017-07-31 04:09:19 +02005509static void
5510add_squirrel_closed(struct redirtab *sq, int fd)
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005511{
5512 int i;
5513
Denys Vlasenko035486c2017-07-31 04:09:19 +02005514 if (!sq)
5515 return;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005516
Denys Vlasenko035486c2017-07-31 04:09:19 +02005517 for (i = 0; sq->two_fd[i].orig_fd != EMPTY; i++) {
5518 /* If we collide with an already moved fd... */
5519 if (fd == sq->two_fd[i].orig_fd) {
5520 /* Examples:
5521 * "echo 3>FILE 3>&- 3>FILE"
5522 * "echo 3>&- 3>FILE"
5523 * No need for last redirect to insert
5524 * another "need to close 3" indicator.
5525 */
5526 TRACE(("redirect_fd %d: already moved or closed\n", fd));
5527 return;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005528 }
5529 }
Denys Vlasenko035486c2017-07-31 04:09:19 +02005530 TRACE(("redirect_fd %d: previous fd was closed\n", fd));
5531 sq->two_fd[i].orig_fd = fd;
5532 sq->two_fd[i].moved_to = CLOSED;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005533}
5534
Denys Vlasenko37dc08b2016-10-02 04:38:07 +02005535static int
Denys Vlasenko035486c2017-07-31 04:09:19 +02005536save_fd_on_redirect(int fd, int avoid_fd, struct redirtab *sq)
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005537{
Denys Vlasenko035486c2017-07-31 04:09:19 +02005538 int i, new_fd;
Denis Vlasenko34c73c42008-08-16 11:48:02 +00005539
Denys Vlasenko035486c2017-07-31 04:09:19 +02005540 if (avoid_fd < 9) /* the important case here is that it can be -1 */
5541 avoid_fd = 9;
5542
5543#if JOBS
5544 if (fd == ttyfd) {
5545 /* Testcase: "ls -l /proc/$$/fd 10>&-" should work */
5546 ttyfd = xdup_CLOEXEC_and_close(ttyfd, avoid_fd);
5547 TRACE(("redirect_fd %d: matches ttyfd, moving it to %d\n", fd, ttyfd));
5548 return 1; /* "we closed fd" */
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005549 }
Denys Vlasenko035486c2017-07-31 04:09:19 +02005550#endif
5551 /* Are we called from redirect(0)? E.g. redirect
5552 * in a forked child. No need to save fds,
5553 * we aren't going to use them anymore, ok to trash.
5554 */
5555 if (!sq)
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005556 return 0;
Denys Vlasenko035486c2017-07-31 04:09:19 +02005557
5558 /* If this one of script's fds? */
5559 if (fd != 0) {
5560 struct parsefile *pf = g_parsefile;
5561 while (pf) {
5562 /* We skip fd == 0 case because of the following:
5563 * $ ash # running ash interactively
5564 * $ . ./script.sh
5565 * and in script.sh: "exec 9>&0".
5566 * Even though top-level pf_fd _is_ 0,
5567 * it's still ok to use it: "read" builtin uses it,
5568 * why should we cripple "exec" builtin?
5569 */
5570 if (fd == pf->pf_fd) {
5571 pf->pf_fd = xdup_CLOEXEC_and_close(fd, avoid_fd);
5572 return 1; /* "we closed fd" */
5573 }
5574 pf = pf->prev;
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005575 }
5576 }
Denys Vlasenko035486c2017-07-31 04:09:19 +02005577
5578 /* Check whether it collides with any open fds (e.g. stdio), save fds as needed */
5579
5580 /* First: do we collide with some already moved fds? */
5581 for (i = 0; sq->two_fd[i].orig_fd != EMPTY; i++) {
5582 /* If we collide with an already moved fd... */
5583 if (fd == sq->two_fd[i].moved_to) {
Denys Vlasenko9acd63c2018-03-28 18:35:07 +02005584 new_fd = dup_CLOEXEC(fd, avoid_fd);
Denys Vlasenko035486c2017-07-31 04:09:19 +02005585 sq->two_fd[i].moved_to = new_fd;
5586 TRACE(("redirect_fd %d: already busy, moving to %d\n", fd, new_fd));
5587 if (new_fd < 0) /* what? */
5588 xfunc_die();
5589 return 0; /* "we did not close fd" */
5590 }
5591 if (fd == sq->two_fd[i].orig_fd) {
5592 /* Example: echo Hello >/dev/null 1>&2 */
5593 TRACE(("redirect_fd %d: already moved\n", fd));
5594 return 0; /* "we did not close fd" */
5595 }
5596 }
5597
5598 /* 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 +02005599 new_fd = dup_CLOEXEC(fd, avoid_fd);
Denys Vlasenko035486c2017-07-31 04:09:19 +02005600 TRACE(("redirect_fd %d: previous fd is moved to %d (-1 if it was closed)\n", fd, new_fd));
5601 if (new_fd < 0) {
5602 if (errno != EBADF)
5603 xfunc_die();
5604 /* new_fd = CLOSED; - already is -1 */
5605 }
5606 sq->two_fd[i].moved_to = new_fd;
5607 sq->two_fd[i].orig_fd = fd;
5608
5609 /* if we move stderr, let "set -x" code know */
5610 if (fd == preverrout_fd)
5611 preverrout_fd = new_fd;
5612
5613 return 0; /* "we did not close fd" */
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005614}
5615
Denys Vlasenko32fdf2f2017-07-31 04:32:06 +02005616static int
5617internally_opened_fd(int fd, struct redirtab *sq)
5618{
5619 int i;
5620#if JOBS
5621 if (fd == ttyfd)
5622 return 1;
5623#endif
5624 /* If this one of script's fds? */
5625 if (fd != 0) {
5626 struct parsefile *pf = g_parsefile;
5627 while (pf) {
5628 if (fd == pf->pf_fd)
5629 return 1;
5630 pf = pf->prev;
5631 }
5632 }
5633
5634 if (sq) for (i = 0; i < sq->pair_count && sq->two_fd[i].orig_fd != EMPTY; i++) {
5635 if (fd == sq->two_fd[i].moved_to)
5636 return 1;
5637 }
5638 return 0;
5639}
5640
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005641/*
5642 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
5643 * old file descriptors are stashed away so that the redirection can be
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005644 * undone by calling popredir.
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005645 */
5646/* flags passed to redirect */
5647#define REDIR_PUSH 01 /* save previous values of file descriptors */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005648static void
5649redirect(union node *redir, int flags)
5650{
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005651 struct redirtab *sv;
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005652
Denys Vlasenko1c79aeb2017-07-29 22:51:52 +02005653 if (!redir)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005654 return;
Denys Vlasenko035486c2017-07-31 04:09:19 +02005655
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005656 sv = NULL;
5657 INT_OFF;
Denys Vlasenko1c79aeb2017-07-29 22:51:52 +02005658 if (flags & REDIR_PUSH)
5659 sv = redirlist;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005660 do {
Denys Vlasenko035486c2017-07-31 04:09:19 +02005661 int fd;
5662 int newfd;
5663 int close_fd;
5664 int closed;
5665
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00005666 fd = redir->nfile.fd;
Denis Vlasenko0b769642008-07-24 07:54:57 +00005667 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
Denys Vlasenko035486c2017-07-31 04:09:19 +02005668 //bb_error_msg("doing %d > %d", fd, newfd);
5669 newfd = redir->ndup.dupfd;
5670 close_fd = -1;
Denis Vlasenko0b769642008-07-24 07:54:57 +00005671 } else {
5672 newfd = openredirect(redir); /* always >= 0 */
5673 if (fd == newfd) {
Denys Vlasenko035486c2017-07-31 04:09:19 +02005674 /* open() gave us precisely the fd we wanted.
5675 * This means that this fd was not busy
5676 * (not opened to anywhere).
5677 * Remember to close it on restore:
5678 */
5679 add_squirrel_closed(sv, fd);
Denis Vlasenko0b769642008-07-24 07:54:57 +00005680 continue;
5681 }
Denys Vlasenko035486c2017-07-31 04:09:19 +02005682 close_fd = newfd;
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005683 }
Denys Vlasenko035486c2017-07-31 04:09:19 +02005684
5685 if (fd == newfd)
5686 continue;
5687
5688 /* if "N>FILE": move newfd to fd */
5689 /* if "N>&M": dup newfd to fd */
5690 /* if "N>&-": close fd (newfd is -1) */
5691
5692 IF_BASH_REDIR_OUTPUT(redirect_more:)
5693
5694 closed = save_fd_on_redirect(fd, /*avoid:*/ newfd, sv);
5695 if (newfd == -1) {
5696 /* "N>&-" means "close me" */
5697 if (!closed) {
5698 /* ^^^ optimization: saving may already
5699 * have closed it. If not... */
5700 close(fd);
Denis Vlasenko22f74142008-07-24 22:34:43 +00005701 }
Denys Vlasenko035486c2017-07-31 04:09:19 +02005702 } else {
Denys Vlasenko32fdf2f2017-07-31 04:32:06 +02005703 /* if newfd is a script fd or saved fd, simulate EBADF */
5704 if (internally_opened_fd(newfd, sv)) {
5705 errno = EBADF;
5706 ash_msg_and_raise_perror("%d", newfd);
5707 }
Denys Vlasenko64774602016-10-26 15:24:30 +02005708 dup2_or_raise(newfd, fd);
Denys Vlasenko035486c2017-07-31 04:09:19 +02005709 if (close_fd >= 0) /* "N>FILE" or ">&FILE" or heredoc? */
5710 close(close_fd);
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01005711#if BASH_REDIR_OUTPUT
Denys Vlasenko035486c2017-07-31 04:09:19 +02005712 if (redir->nfile.type == NTO2 && fd == 1) {
5713 /* ">&FILE". we already redirected to 1, now copy 1 to 2 */
5714 fd = 2;
5715 newfd = 1;
5716 close_fd = -1;
5717 goto redirect_more;
5718 }
Denis Vlasenko559691a2008-10-05 18:39:31 +00005719#endif
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005720 }
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00005721 } while ((redir = redir->nfile.next) != NULL);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005722 INT_ON;
Denys Vlasenkod07a15b2017-07-30 16:51:05 +02005723
5724//dash:#define REDIR_SAVEFD2 03 /* set preverrout */
5725#define REDIR_SAVEFD2 0
5726 // dash has a bug: since REDIR_SAVEFD2=3 and REDIR_PUSH=1, this test
5727 // triggers for pure REDIR_PUSH too. Thus, this is done almost always,
5728 // not only for calls with flags containing REDIR_SAVEFD2.
Denys Vlasenko035486c2017-07-31 04:09:19 +02005729 // We do this unconditionally (see save_fd_on_redirect()).
Denys Vlasenkod07a15b2017-07-30 16:51:05 +02005730 //if ((flags & REDIR_SAVEFD2) && copied_fd2 >= 0)
5731 // preverrout_fd = copied_fd2;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005732}
5733
Denys Vlasenko170f93e2017-07-29 18:54:53 +02005734static int
5735redirectsafe(union node *redir, int flags)
5736{
5737 int err;
5738 volatile int saveint;
5739 struct jmploc *volatile savehandler = exception_handler;
5740 struct jmploc jmploc;
5741
5742 SAVE_INT(saveint);
5743 /* "echo 9>/dev/null; echo >&9; echo result: $?" - result should be 1, not 2! */
Denys Vlasenko035486c2017-07-31 04:09:19 +02005744 err = setjmp(jmploc.loc); /* was = setjmp(jmploc.loc) * 2; */
Denys Vlasenko170f93e2017-07-29 18:54:53 +02005745 if (!err) {
5746 exception_handler = &jmploc;
5747 redirect(redir, flags);
5748 }
5749 exception_handler = savehandler;
5750 if (err && exception_type != EXERROR)
5751 longjmp(exception_handler->loc, 1);
5752 RESTORE_INT(saveint);
5753 return err;
5754}
5755
Denys Vlasenko1c79aeb2017-07-29 22:51:52 +02005756static struct redirtab*
5757pushredir(union node *redir)
5758{
5759 struct redirtab *sv;
5760 int i;
5761
5762 if (!redir)
5763 return redirlist;
5764
5765 i = 0;
5766 do {
5767 i++;
5768#if BASH_REDIR_OUTPUT
5769 if (redir->nfile.type == NTO2)
5770 i++;
5771#endif
5772 redir = redir->nfile.next;
5773 } while (redir);
5774
5775 sv = ckzalloc(sizeof(*sv) + i * sizeof(sv->two_fd[0]));
5776 sv->pair_count = i;
5777 while (--i >= 0)
Denys Vlasenko035486c2017-07-31 04:09:19 +02005778 sv->two_fd[i].orig_fd = sv->two_fd[i].moved_to = EMPTY;
Denys Vlasenko1c79aeb2017-07-29 22:51:52 +02005779 sv->next = redirlist;
5780 redirlist = sv;
5781 return sv->next;
5782}
5783
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005784/*
5785 * Undo the effects of the last redirection.
5786 */
5787static void
Denys Vlasenko035486c2017-07-31 04:09:19 +02005788popredir(int drop)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005789{
5790 struct redirtab *rp;
5791 int i;
5792
Denys Vlasenkoeaf94362016-10-25 21:46:03 +02005793 if (redirlist == NULL)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005794 return;
5795 INT_OFF;
5796 rp = redirlist;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005797 for (i = 0; i < rp->pair_count; i++) {
Denys Vlasenko035486c2017-07-31 04:09:19 +02005798 int fd = rp->two_fd[i].orig_fd;
5799 int copy = rp->two_fd[i].moved_to;
Denis Vlasenko22f74142008-07-24 22:34:43 +00005800 if (copy == CLOSED) {
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005801 if (!drop)
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005802 close(fd);
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005803 continue;
5804 }
Denis Vlasenko22f74142008-07-24 22:34:43 +00005805 if (copy != EMPTY) {
Denys Vlasenko035486c2017-07-31 04:09:19 +02005806 if (!drop) {
Denis Vlasenko5a867312008-07-24 19:46:38 +00005807 /*close(fd);*/
Denys Vlasenko64774602016-10-26 15:24:30 +02005808 dup2_or_raise(copy, fd);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005809 }
Denys Vlasenko035486c2017-07-31 04:09:19 +02005810 close(copy);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005811 }
5812 }
5813 redirlist = rp->next;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005814 free(rp);
5815 INT_ON;
5816}
5817
Denys Vlasenko1c79aeb2017-07-29 22:51:52 +02005818static void
5819unwindredir(struct redirtab *stop)
5820{
5821 while (redirlist != stop)
Denys Vlasenko035486c2017-07-31 04:09:19 +02005822 popredir(/*drop:*/ 0);
Denys Vlasenko1c79aeb2017-07-29 22:51:52 +02005823}
5824
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005825
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005826/* ============ Routines to expand arguments to commands
5827 *
5828 * We have to deal with backquotes, shell variables, and file metacharacters.
5829 */
5830
Denys Vlasenko0b883582016-12-23 16:49:07 +01005831#if ENABLE_FEATURE_SH_MATH
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005832static arith_t
5833ash_arith(const char *s)
5834{
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005835 arith_state_t math_state;
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005836 arith_t result;
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005837
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005838 math_state.lookupvar = lookupvar;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02005839 math_state.setvar = setvar0;
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005840 //math_state.endofname = endofname;
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005841
5842 INT_OFF;
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005843 result = arith(&math_state, s);
Denys Vlasenko063847d2010-09-15 13:33:02 +02005844 if (math_state.errmsg)
5845 ash_msg_and_raise_error(math_state.errmsg);
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005846 INT_ON;
5847
5848 return result;
5849}
Denis Vlasenko448d30e2008-06-27 00:24:11 +00005850#endif
Denys Vlasenkobaa41c72018-01-10 13:22:25 +01005851#if BASH_SUBSTR
5852# if ENABLE_FEATURE_SH_MATH
5853static int substr_atoi(const char *s)
5854{
5855 arith_t t = ash_arith(s);
5856 if (sizeof(t) > sizeof(int)) {
5857 /* clamp very large or very large negative nums for ${v:N:M}:
5858 * else "${v:0:0x100000001}" would work as "${v:0:1}"
5859 */
5860 if (t > INT_MAX)
5861 t = INT_MAX;
5862 if (t < INT_MIN)
5863 t = INT_MIN;
5864 }
5865 return t;
5866}
5867# else
5868# define substr_atoi(s) number(s)
5869# endif
5870#endif
Denis Vlasenko448d30e2008-06-27 00:24:11 +00005871
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005872/*
5873 * expandarg flags
5874 */
5875#define EXP_FULL 0x1 /* perform word splitting & file globbing */
5876#define EXP_TILDE 0x2 /* do normal tilde expansion */
5877#define EXP_VARTILDE 0x4 /* expand tildes in an assignment */
5878#define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */
Denys Vlasenkodb74c6c2016-10-24 21:12:33 +02005879/* ^^^^^^^^^^^^^^ this is meant to support constructs such as "cmd >file*.txt"
5880 * POSIX says for this case:
5881 * Pathname expansion shall not be performed on the word by a
5882 * non-interactive shell; an interactive shell may perform it, but shall
5883 * do so only when the expansion would result in one word.
5884 * Currently, our code complies to the above rule by never globbing
5885 * redirection filenames.
5886 * Bash performs globbing, unless it is non-interactive and in POSIX mode.
5887 * (this means that on a typical Linux distro, bash almost always
5888 * performs globbing, and thus diverges from what we do).
5889 */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005890#define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */
Denys Vlasenko216913c2018-04-02 12:35:04 +02005891#define EXP_VARTILDE2 0x20 /* expand tildes after colons only */
5892#define EXP_WORD 0x40 /* expand word in parameter expansion */
5893#define EXP_QUOTED 0x80 /* expand word in double quotes */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005894/*
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005895 * rmescape() flags
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005896 */
5897#define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
5898#define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005899#define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */
5900#define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */
5901
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005902/* Add CTLESC when necessary. */
Denys Vlasenko216913c2018-04-02 12:35:04 +02005903#define QUOTES_ESC (EXP_FULL | EXP_CASE)
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005904/* Do not skip NUL characters. */
5905#define QUOTES_KEEPNUL EXP_TILDE
5906
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005907/*
5908 * Structure specifying which parts of the string should be searched
5909 * for IFS characters.
5910 */
5911struct ifsregion {
5912 struct ifsregion *next; /* next region in list */
5913 int begoff; /* offset of start of region */
5914 int endoff; /* offset of end of region */
5915 int nulonly; /* search for nul bytes only */
5916};
5917
5918struct arglist {
5919 struct strlist *list;
5920 struct strlist **lastp;
5921};
5922
5923/* output of current string */
5924static char *expdest;
5925/* list of back quote expressions */
5926static struct nodelist *argbackq;
5927/* first struct in list of ifs regions */
5928static struct ifsregion ifsfirst;
5929/* last struct in list */
5930static struct ifsregion *ifslastp;
5931/* holds expanded arg list */
5932static struct arglist exparg;
5933
5934/*
5935 * Our own itoa().
Denys Vlasenkocf3a7962017-07-26 14:38:19 +02005936 * cvtnum() is used even if math support is off (to prepare $? values and such).
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005937 */
5938static int
5939cvtnum(arith_t num)
5940{
5941 int len;
5942
Denys Vlasenkocf3a7962017-07-26 14:38:19 +02005943 /* 32-bit and wider ints require buffer size of bytes*3 (or less) */
5944 len = sizeof(arith_t) * 3;
5945 /* If narrower: worst case, 1-byte ints: need 5 bytes: "-127<NUL>" */
5946 if (sizeof(arith_t) < 4) len += 2;
5947
5948 expdest = makestrspace(len, expdest);
5949 len = fmtstr(expdest, len, ARITH_FMT, num);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005950 STADJUST(len, expdest);
5951 return len;
5952}
5953
Denys Vlasenko455e4222016-10-27 14:45:13 +02005954/*
5955 * Break the argument string into pieces based upon IFS and add the
5956 * strings to the argument list. The regions of the string to be
5957 * searched for IFS characters have been stored by recordregion.
5958 */
5959static void
5960ifsbreakup(char *string, struct arglist *arglist)
5961{
5962 struct ifsregion *ifsp;
5963 struct strlist *sp;
5964 char *start;
5965 char *p;
5966 char *q;
5967 const char *ifs, *realifs;
5968 int ifsspc;
5969 int nulonly;
5970
5971 start = string;
5972 if (ifslastp != NULL) {
5973 ifsspc = 0;
5974 nulonly = 0;
5975 realifs = ifsset() ? ifsval() : defifs;
5976 ifsp = &ifsfirst;
5977 do {
Denys Vlasenko9a95df92018-04-02 14:27:50 +02005978 int afternul;
5979
Denys Vlasenko455e4222016-10-27 14:45:13 +02005980 p = string + ifsp->begoff;
Denys Vlasenko9a95df92018-04-02 14:27:50 +02005981 afternul = nulonly;
Denys Vlasenko455e4222016-10-27 14:45:13 +02005982 nulonly = ifsp->nulonly;
5983 ifs = nulonly ? nullstr : realifs;
5984 ifsspc = 0;
5985 while (p < string + ifsp->endoff) {
5986 q = p;
5987 if ((unsigned char)*p == CTLESC)
5988 p++;
5989 if (!strchr(ifs, *p)) {
5990 p++;
5991 continue;
5992 }
Denys Vlasenko9a95df92018-04-02 14:27:50 +02005993 if (!(afternul || nulonly))
Denys Vlasenko455e4222016-10-27 14:45:13 +02005994 ifsspc = (strchr(defifs, *p) != NULL);
5995 /* Ignore IFS whitespace at start */
5996 if (q == start && ifsspc) {
5997 p++;
5998 start = p;
5999 continue;
6000 }
6001 *q = '\0';
6002 sp = stzalloc(sizeof(*sp));
6003 sp->text = start;
6004 *arglist->lastp = sp;
6005 arglist->lastp = &sp->next;
6006 p++;
6007 if (!nulonly) {
6008 for (;;) {
6009 if (p >= string + ifsp->endoff) {
6010 break;
6011 }
6012 q = p;
6013 if ((unsigned char)*p == CTLESC)
6014 p++;
6015 if (strchr(ifs, *p) == NULL) {
6016 p = q;
6017 break;
6018 }
6019 if (strchr(defifs, *p) == NULL) {
6020 if (ifsspc) {
6021 p++;
6022 ifsspc = 0;
6023 } else {
6024 p = q;
6025 break;
6026 }
6027 } else
6028 p++;
6029 }
6030 }
6031 start = p;
6032 } /* while */
6033 ifsp = ifsp->next;
6034 } while (ifsp != NULL);
6035 if (nulonly)
6036 goto add;
6037 }
6038
6039 if (!*start)
6040 return;
6041
6042 add:
6043 sp = stzalloc(sizeof(*sp));
6044 sp->text = start;
6045 *arglist->lastp = sp;
6046 arglist->lastp = &sp->next;
6047}
6048
6049static void
6050ifsfree(void)
6051{
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02006052 struct ifsregion *p = ifsfirst.next;
6053
6054 if (!p)
6055 goto out;
Denys Vlasenko455e4222016-10-27 14:45:13 +02006056
6057 INT_OFF;
Denys Vlasenko455e4222016-10-27 14:45:13 +02006058 do {
6059 struct ifsregion *ifsp;
6060 ifsp = p->next;
6061 free(p);
6062 p = ifsp;
6063 } while (p);
Denys Vlasenko455e4222016-10-27 14:45:13 +02006064 ifsfirst.next = NULL;
6065 INT_ON;
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02006066 out:
6067 ifslastp = NULL;
Denys Vlasenko455e4222016-10-27 14:45:13 +02006068}
6069
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006070static size_t
6071esclen(const char *start, const char *p)
6072{
6073 size_t esc = 0;
6074
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006075 while (p > start && (unsigned char)*--p == CTLESC) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006076 esc++;
6077 }
6078 return esc;
6079}
6080
6081/*
6082 * Remove any CTLESC characters from a string.
6083 */
Denys Vlasenko740058b2018-01-09 17:01:00 +01006084#if !BASH_PATTERN_SUBST
6085#define rmescapes(str, flag, slash_position) \
6086 rmescapes(str, flag)
6087#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006088static char *
Denys Vlasenko740058b2018-01-09 17:01:00 +01006089rmescapes(char *str, int flag, int *slash_position)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006090{
Ron Yorston417622c2015-05-18 09:59:14 +02006091 static const char qchars[] ALIGN1 = {
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006092 IF_BASH_PATTERN_SUBST('/',) CTLESC, CTLQUOTEMARK, '\0' };
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00006093
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006094 char *p, *q, *r;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006095 unsigned protect_against_glob;
6096 unsigned globbing;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006097
Denys Vlasenko740058b2018-01-09 17:01:00 +01006098 p = strpbrk(str, qchars IF_BASH_PATTERN_SUBST(+ !slash_position));
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006099 if (!p)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006100 return str;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006101
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006102 q = p;
6103 r = str;
6104 if (flag & RMESCAPE_ALLOC) {
6105 size_t len = p - str;
6106 size_t fulllen = len + strlen(p) + 1;
6107
6108 if (flag & RMESCAPE_GROW) {
Colin Watson3963d942010-04-26 14:21:27 +02006109 int strloc = str - (char *)stackblock();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006110 r = makestrspace(fulllen, expdest);
Colin Watson3963d942010-04-26 14:21:27 +02006111 /* p and str may be invalidated by makestrspace */
6112 str = (char *)stackblock() + strloc;
6113 p = str + len;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006114 } else if (flag & RMESCAPE_HEAP) {
6115 r = ckmalloc(fulllen);
6116 } else {
6117 r = stalloc(fulllen);
6118 }
6119 q = r;
6120 if (len > 0) {
Denys Vlasenko5ace96a2017-07-23 21:46:02 +02006121 q = (char *)mempcpy(q, str, len);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006122 }
6123 }
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006124
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006125 globbing = flag & RMESCAPE_GLOB;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006126 protect_against_glob = globbing;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006127 while (*p) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006128 if ((unsigned char)*p == CTLQUOTEMARK) {
Denys Vlasenko216913c2018-04-02 12:35:04 +02006129// Note: protect_against_glob only affect whether
Denys Vlasenkofda9faf2017-07-05 19:10:21 +02006130// CTLESC,<ch> gets converted to <ch> or to \<ch>
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006131 p++;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006132 protect_against_glob = globbing;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006133 continue;
6134 }
Denys Vlasenko216913c2018-04-02 12:35:04 +02006135 if (*p == '\\') {
6136 /* naked back slash */
6137 protect_against_glob = 0;
6138 goto copy;
6139 }
Ron Yorston549deab2015-05-18 09:57:51 +02006140 if ((unsigned char)*p == CTLESC) {
6141 p++;
Denys Vlasenko13f20912016-09-25 20:54:25 +02006142#if DEBUG
6143 if (*p == '\0')
6144 ash_msg_and_raise_error("CTLESC at EOL (shouldn't happen)");
6145#endif
Ron Yorston549deab2015-05-18 09:57:51 +02006146 if (protect_against_glob) {
Denys Vlasenkofda9faf2017-07-05 19:10:21 +02006147 /*
6148 * We used to trust glob() and fnmatch() to eat
6149 * superfluous escapes (\z where z has no
6150 * special meaning anyway). But this causes
6151 * bugs such as string of one greek letter rho
Denys Vlasenkoed79a632017-07-05 19:20:43 +02006152 * (unicode-encoded as two bytes "cf,81")
Denys Vlasenkofda9faf2017-07-05 19:10:21 +02006153 * getting encoded as "cf,CTLESC,81"
6154 * and here, converted to "cf,\,81" -
6155 * which does not go well with some flavors
Denys Vlasenko92b8d9c2017-07-05 19:13:44 +02006156 * of fnmatch() in unicode locales
6157 * (for example, glibc <= 2.22).
Denys Vlasenkofda9faf2017-07-05 19:10:21 +02006158 *
6159 * Lets add "\" only on the chars which need it.
Denys Vlasenko4142f012017-07-05 22:19:28 +02006160 * Testcases for less obvious chars are shown.
Denys Vlasenkofda9faf2017-07-05 19:10:21 +02006161 */
6162 if (*p == '*'
6163 || *p == '?'
6164 || *p == '['
Denys Vlasenko8de5b9f2018-02-13 14:43:29 +01006165 || *p == '\\' /* case '\' in \\ ) echo ok;; *) echo WRONG;; esac */
6166 || *p == ']' /* case ']' in [a\]] ) echo ok;; *) echo WRONG;; esac */
6167 || *p == '-' /* case '-' in [a\-c]) echo ok;; *) echo WRONG;; esac */
6168 || *p == '!' /* case '!' in [\!] ) echo ok;; *) echo WRONG;; esac */
Denys Vlasenko4142f012017-07-05 22:19:28 +02006169 /* Some libc support [^negate], that's why "^" also needs love */
Denys Vlasenko8de5b9f2018-02-13 14:43:29 +01006170 || *p == '^' /* case '^' in [\^] ) echo ok;; *) echo WRONG;; esac */
Denys Vlasenkofda9faf2017-07-05 19:10:21 +02006171 ) {
6172 *q++ = '\\';
6173 }
Ron Yorston549deab2015-05-18 09:57:51 +02006174 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006175 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006176#if BASH_PATTERN_SUBST
Denys Vlasenko740058b2018-01-09 17:01:00 +01006177 else if (slash_position && p == str + *slash_position) {
6178 /* stop handling globbing */
6179 globbing = 0;
6180 *slash_position = q - r;
6181 slash_position = NULL;
Ron Yorston417622c2015-05-18 09:59:14 +02006182 }
6183#endif
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006184 protect_against_glob = globbing;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006185 copy:
6186 *q++ = *p++;
6187 }
6188 *q = '\0';
6189 if (flag & RMESCAPE_GROW) {
6190 expdest = r;
6191 STADJUST(q - r + 1, expdest);
6192 }
6193 return r;
6194}
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006195#define pmatch(a, b) !fnmatch((a), (b), 0)
6196
6197/*
6198 * Prepare a pattern for a expmeta (internal glob(3)) call.
6199 *
6200 * Returns an stalloced string.
6201 */
6202static char *
Ron Yorston549deab2015-05-18 09:57:51 +02006203preglob(const char *pattern, int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006204{
Denys Vlasenko740058b2018-01-09 17:01:00 +01006205 return rmescapes((char *)pattern, flag | RMESCAPE_GLOB, NULL);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006206}
6207
6208/*
6209 * Put a string on the stack.
6210 */
6211static void
6212memtodest(const char *p, size_t len, int syntax, int quotes)
6213{
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006214 char *q;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006215
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006216 if (!len)
6217 return;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006218
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006219 q = makestrspace((quotes & QUOTES_ESC) ? len * 2 : len, expdest);
6220
6221 do {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006222 unsigned char c = *p++;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006223 if (c) {
Denys Vlasenko2fe66b12016-12-12 17:39:12 +01006224 if (quotes & QUOTES_ESC) {
6225 int n = SIT(c, syntax);
6226 if (n == CCTL
6227 || (((quotes & EXP_FULL) || syntax != BASESYNTAX)
6228 && n == CBACK
6229 )
6230 ) {
6231 USTPUTC(CTLESC, q);
6232 }
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02006233 }
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006234 } else if (!(quotes & QUOTES_KEEPNUL))
6235 continue;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006236 USTPUTC(c, q);
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006237 } while (--len);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006238
6239 expdest = q;
6240}
6241
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006242static size_t
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006243strtodest(const char *p, int syntax, int quotes)
6244{
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006245 size_t len = strlen(p);
6246 memtodest(p, len, syntax, quotes);
6247 return len;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006248}
6249
6250/*
6251 * Record the fact that we have to scan this region of the
6252 * string for IFS characters.
6253 */
6254static void
6255recordregion(int start, int end, int nulonly)
6256{
6257 struct ifsregion *ifsp;
6258
6259 if (ifslastp == NULL) {
6260 ifsp = &ifsfirst;
6261 } else {
6262 INT_OFF;
Denis Vlasenko597906c2008-02-20 16:38:54 +00006263 ifsp = ckzalloc(sizeof(*ifsp));
6264 /*ifsp->next = NULL; - ckzalloc did it */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006265 ifslastp->next = ifsp;
6266 INT_ON;
6267 }
6268 ifslastp = ifsp;
6269 ifslastp->begoff = start;
6270 ifslastp->endoff = end;
6271 ifslastp->nulonly = nulonly;
6272}
6273
6274static void
6275removerecordregions(int endoff)
6276{
6277 if (ifslastp == NULL)
6278 return;
6279
6280 if (ifsfirst.endoff > endoff) {
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006281 while (ifsfirst.next) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006282 struct ifsregion *ifsp;
6283 INT_OFF;
6284 ifsp = ifsfirst.next->next;
6285 free(ifsfirst.next);
6286 ifsfirst.next = ifsp;
6287 INT_ON;
6288 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006289 if (ifsfirst.begoff > endoff) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006290 ifslastp = NULL;
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006291 } else {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006292 ifslastp = &ifsfirst;
6293 ifsfirst.endoff = endoff;
6294 }
6295 return;
6296 }
6297
6298 ifslastp = &ifsfirst;
6299 while (ifslastp->next && ifslastp->next->begoff < endoff)
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006300 ifslastp = ifslastp->next;
6301 while (ifslastp->next) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006302 struct ifsregion *ifsp;
6303 INT_OFF;
6304 ifsp = ifslastp->next->next;
6305 free(ifslastp->next);
6306 ifslastp->next = ifsp;
6307 INT_ON;
6308 }
6309 if (ifslastp->endoff > endoff)
6310 ifslastp->endoff = endoff;
6311}
6312
6313static char *
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006314exptilde(char *startp, char *p, int flags)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006315{
Denys Vlasenkocd716832009-11-28 22:14:02 +01006316 unsigned char c;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006317 char *name;
6318 struct passwd *pw;
6319 const char *home;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006320 int quotes = flags & QUOTES_ESC;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006321
6322 name = p + 1;
6323
6324 while ((c = *++p) != '\0') {
6325 switch (c) {
6326 case CTLESC:
6327 return startp;
6328 case CTLQUOTEMARK:
6329 return startp;
6330 case ':':
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006331 if (flags & EXP_VARTILDE)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006332 goto done;
6333 break;
6334 case '/':
6335 case CTLENDVAR:
6336 goto done;
6337 }
6338 }
6339 done:
6340 *p = '\0';
6341 if (*name == '\0') {
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02006342 home = lookupvar("HOME");
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006343 } else {
6344 pw = getpwnam(name);
6345 if (pw == NULL)
6346 goto lose;
6347 home = pw->pw_dir;
6348 }
6349 if (!home || !*home)
6350 goto lose;
6351 *p = c;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006352 strtodest(home, SQSYNTAX, quotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006353 return p;
6354 lose:
6355 *p = c;
6356 return startp;
6357}
6358
6359/*
6360 * Execute a command inside back quotes. If it's a builtin command, we
6361 * want to save its output in a block obtained from malloc. Otherwise
6362 * we fork off a subprocess and get the output of the command via a pipe.
6363 * Should be called with interrupts off.
6364 */
6365struct backcmd { /* result of evalbackcmd */
6366 int fd; /* file descriptor to read from */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006367 int nleft; /* number of chars in buffer */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00006368 char *buf; /* buffer */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006369 struct job *jp; /* job structure for command */
6370};
6371
6372/* These forward decls are needed to use "eval" code for backticks handling: */
Denys Vlasenko1e3e2cc2017-07-25 20:31:14 +02006373/* flags in argument to evaltree */
6374#define EV_EXIT 01 /* exit after evaluating tree */
6375#define EV_TESTED 02 /* exit status is checked; ignore -e flag */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02006376static int evaltree(union node *, int);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006377
Denys Vlasenko619d9b52017-07-28 15:28:33 +02006378/* An evaltree() which is known to never return.
6379 * Used to use an alias:
6380 * static int evaltreenr(union node *, int) __attribute__((alias("evaltree"),__noreturn__));
6381 * but clang was reported to "transfer" noreturn-ness to evaltree() as well.
6382 */
6383static ALWAYS_INLINE NORETURN void
6384evaltreenr(union node *n, int flags)
6385{
6386 evaltree(n, flags);
6387 bb_unreachable(abort());
6388 /* NOTREACHED */
6389}
6390
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02006391static void FAST_FUNC
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006392evalbackcmd(union node *n, struct backcmd *result)
6393{
Denys Vlasenko579ad102016-10-25 21:10:20 +02006394 int pip[2];
6395 struct job *jp;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006396
6397 result->fd = -1;
6398 result->buf = NULL;
6399 result->nleft = 0;
6400 result->jp = NULL;
Denys Vlasenko579ad102016-10-25 21:10:20 +02006401 if (n == NULL) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006402 goto out;
Denys Vlasenko579ad102016-10-25 21:10:20 +02006403 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006404
Denys Vlasenko579ad102016-10-25 21:10:20 +02006405 if (pipe(pip) < 0)
Denys Vlasenko12ffefb2017-08-23 14:52:56 +02006406 ash_msg_and_raise_perror("can't create pipe");
Denys Vlasenko579ad102016-10-25 21:10:20 +02006407 jp = makejob(/*n,*/ 1);
6408 if (forkshell(jp, n, FORK_NOJOB) == 0) {
Denys Vlasenko70392332016-10-27 02:31:55 +02006409 /* child */
Denys Vlasenko579ad102016-10-25 21:10:20 +02006410 FORCE_INT_ON;
6411 close(pip[0]);
6412 if (pip[1] != 1) {
6413 /*close(1);*/
Denys Vlasenko64774602016-10-26 15:24:30 +02006414 dup2_or_raise(pip[1], 1);
Denys Vlasenko579ad102016-10-25 21:10:20 +02006415 close(pip[1]);
6416 }
Denys Vlasenko960ca382016-10-25 18:12:15 +02006417/* TODO: eflag clearing makes the following not abort:
6418 * ash -c 'set -e; z=$(false;echo foo); echo $z'
6419 * which is what bash does (unless it is in POSIX mode).
6420 * dash deleted "eflag = 0" line in the commit
6421 * Date: Mon, 28 Jun 2010 17:11:58 +1000
6422 * [EVAL] Don't clear eflag in evalbackcmd
6423 * For now, preserve bash-like behavior, it seems to be somewhat more useful:
6424 */
Denys Vlasenko579ad102016-10-25 21:10:20 +02006425 eflag = 0;
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02006426 ifsfree();
Denys Vlasenko619d9b52017-07-28 15:28:33 +02006427 evaltreenr(n, EV_EXIT);
Denys Vlasenko579ad102016-10-25 21:10:20 +02006428 /* NOTREACHED */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006429 }
Denys Vlasenko70392332016-10-27 02:31:55 +02006430 /* parent */
Denys Vlasenko579ad102016-10-25 21:10:20 +02006431 close(pip[1]);
6432 result->fd = pip[0];
6433 result->jp = jp;
6434
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006435 out:
6436 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
6437 result->fd, result->buf, result->nleft, result->jp));
6438}
6439
6440/*
6441 * Expand stuff in backwards quotes.
6442 */
6443static void
Ron Yorston549deab2015-05-18 09:57:51 +02006444expbackq(union node *cmd, int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006445{
6446 struct backcmd in;
6447 int i;
6448 char buf[128];
6449 char *p;
6450 char *dest;
6451 int startloc;
Ron Yorston549deab2015-05-18 09:57:51 +02006452 int syntax = flag & EXP_QUOTED ? DQSYNTAX : BASESYNTAX;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006453 struct stackmark smark;
6454
6455 INT_OFF;
Denys Vlasenko60ca8342016-09-30 11:21:21 +02006456 startloc = expdest - (char *)stackblock();
6457 pushstackmark(&smark, startloc);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006458 evalbackcmd(cmd, &in);
6459 popstackmark(&smark);
6460
6461 p = in.buf;
6462 i = in.nleft;
6463 if (i == 0)
6464 goto read;
6465 for (;;) {
Ron Yorston549deab2015-05-18 09:57:51 +02006466 memtodest(p, i, syntax, flag & QUOTES_ESC);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006467 read:
6468 if (in.fd < 0)
6469 break;
Ron Yorston61d6ae22015-04-19 10:50:25 +01006470 i = nonblock_immune_read(in.fd, buf, sizeof(buf));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006471 TRACE(("expbackq: read returns %d\n", i));
6472 if (i <= 0)
6473 break;
6474 p = buf;
6475 }
6476
Denis Vlasenko60818682007-09-28 22:07:23 +00006477 free(in.buf);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006478 if (in.fd >= 0) {
6479 close(in.fd);
6480 back_exitstatus = waitforjob(in.jp);
6481 }
6482 INT_ON;
6483
6484 /* Eat all trailing newlines */
6485 dest = expdest;
6486 for (; dest > (char *)stackblock() && dest[-1] == '\n';)
6487 STUNPUTC(dest);
6488 expdest = dest;
6489
Ron Yorston549deab2015-05-18 09:57:51 +02006490 if (!(flag & EXP_QUOTED))
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006491 recordregion(startloc, dest - (char *)stackblock(), 0);
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006492 TRACE(("evalbackq: size:%d:'%.*s'\n",
6493 (int)((dest - (char *)stackblock()) - startloc),
6494 (int)((dest - (char *)stackblock()) - startloc),
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006495 stackblock() + startloc));
6496}
6497
Denys Vlasenko0b883582016-12-23 16:49:07 +01006498#if ENABLE_FEATURE_SH_MATH
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006499/*
6500 * Expand arithmetic expression. Backup to start of expression,
6501 * evaluate, place result in (backed up) result, adjust string position.
6502 */
6503static void
Ron Yorston549deab2015-05-18 09:57:51 +02006504expari(int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006505{
6506 char *p, *start;
6507 int begoff;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006508 int len;
6509
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006510 /* ifsfree(); */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006511
6512 /*
6513 * This routine is slightly over-complicated for
6514 * efficiency. Next we scan backwards looking for the
6515 * start of arithmetic.
6516 */
6517 start = stackblock();
6518 p = expdest - 1;
6519 *p = '\0';
6520 p--;
Denys Vlasenko940c7202011-03-02 04:07:14 +01006521 while (1) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006522 int esc;
6523
Denys Vlasenkocd716832009-11-28 22:14:02 +01006524 while ((unsigned char)*p != CTLARI) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006525 p--;
6526#if DEBUG
6527 if (p < start) {
6528 ash_msg_and_raise_error("missing CTLARI (shouldn't happen)");
6529 }
6530#endif
6531 }
6532
6533 esc = esclen(start, p);
6534 if (!(esc % 2)) {
6535 break;
6536 }
6537
6538 p -= esc + 1;
Denys Vlasenko940c7202011-03-02 04:07:14 +01006539 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006540
6541 begoff = p - start;
6542
6543 removerecordregions(begoff);
6544
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006545 expdest = p;
6546
Ron Yorston549deab2015-05-18 09:57:51 +02006547 if (flag & QUOTES_ESC)
Denys Vlasenko740058b2018-01-09 17:01:00 +01006548 rmescapes(p + 1, 0, NULL);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006549
Ron Yorston549deab2015-05-18 09:57:51 +02006550 len = cvtnum(ash_arith(p + 1));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006551
Ron Yorston549deab2015-05-18 09:57:51 +02006552 if (!(flag & EXP_QUOTED))
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006553 recordregion(begoff, begoff + len, 0);
6554}
6555#endif
6556
6557/* argstr needs it */
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02006558static char *evalvar(char *p, int flags);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006559
6560/*
6561 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
6562 * characters to allow for further processing. Otherwise treat
6563 * $@ like $* since no splitting will be performed.
6564 */
6565static void
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02006566argstr(char *p, int flags)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006567{
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00006568 static const char spclchars[] ALIGN1 = {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006569 '=',
6570 ':',
6571 CTLQUOTEMARK,
6572 CTLENDVAR,
6573 CTLESC,
6574 CTLVAR,
6575 CTLBACKQ,
Denys Vlasenko0b883582016-12-23 16:49:07 +01006576#if ENABLE_FEATURE_SH_MATH
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006577 CTLENDARI,
6578#endif
Denys Vlasenkocd716832009-11-28 22:14:02 +01006579 '\0'
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006580 };
6581 const char *reject = spclchars;
Ron Yorston3df47f92015-05-18 09:53:26 +02006582 int breakall = (flags & (EXP_WORD | EXP_QUOTED)) == EXP_WORD;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006583 int inquotes;
6584 size_t length;
6585 int startloc;
6586
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006587 if (!(flags & EXP_VARTILDE)) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006588 reject += 2;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006589 } else if (flags & EXP_VARTILDE2) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006590 reject++;
6591 }
6592 inquotes = 0;
6593 length = 0;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006594 if (flags & EXP_TILDE) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006595 char *q;
6596
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006597 flags &= ~EXP_TILDE;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006598 tilde:
6599 q = p;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006600 if (*q == '~')
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006601 p = exptilde(p, q, flags);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006602 }
6603 start:
6604 startloc = expdest - (char *)stackblock();
6605 for (;;) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006606 unsigned char c;
6607
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006608 length += strcspn(p + length, reject);
Denys Vlasenkocd716832009-11-28 22:14:02 +01006609 c = p[length];
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006610 if (c) {
6611 if (!(c & 0x80)
Denys Vlasenko0b883582016-12-23 16:49:07 +01006612 IF_FEATURE_SH_MATH(|| c == CTLENDARI)
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006613 ) {
6614 /* c == '=' || c == ':' || c == CTLENDARI */
6615 length++;
6616 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006617 }
6618 if (length > 0) {
6619 int newloc;
6620 expdest = stack_nputstr(p, length, expdest);
6621 newloc = expdest - (char *)stackblock();
6622 if (breakall && !inquotes && newloc > startloc) {
6623 recordregion(startloc, newloc, 0);
6624 }
6625 startloc = newloc;
6626 }
6627 p += length + 1;
6628 length = 0;
6629
6630 switch (c) {
6631 case '\0':
6632 goto breakloop;
6633 case '=':
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006634 if (flags & EXP_VARTILDE2) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006635 p--;
6636 continue;
6637 }
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006638 flags |= EXP_VARTILDE2;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006639 reject++;
6640 /* fall through */
6641 case ':':
6642 /*
6643 * sort of a hack - expand tildes in variable
6644 * assignments (after the first '=' and after ':'s).
6645 */
6646 if (*--p == '~') {
6647 goto tilde;
6648 }
6649 continue;
6650 }
6651
6652 switch (c) {
6653 case CTLENDVAR: /* ??? */
6654 goto breakloop;
6655 case CTLQUOTEMARK:
6656 /* "$@" syntax adherence hack */
Denys Vlasenko9a95df92018-04-02 14:27:50 +02006657 if (!inquotes && !memcmp(p, dolatstr + 1, DOLATSTRLEN - 1)) {
6658 p = evalvar(p + 1, flags | EXP_QUOTED) + 1;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006659 goto start;
6660 }
Denys Vlasenko9a95df92018-04-02 14:27:50 +02006661 inquotes ^= EXP_QUOTED;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006662 addquote:
Ron Yorston549deab2015-05-18 09:57:51 +02006663 if (flags & QUOTES_ESC) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006664 p--;
6665 length++;
6666 startloc++;
6667 }
6668 break;
6669 case CTLESC:
6670 startloc++;
6671 length++;
6672 goto addquote;
6673 case CTLVAR:
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02006674 TRACE(("argstr: evalvar('%s')\n", p));
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02006675 p = evalvar(p, flags | inquotes);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02006676 TRACE(("argstr: evalvar:'%s'\n", (char *)stackblock()));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006677 goto start;
6678 case CTLBACKQ:
Ron Yorston549deab2015-05-18 09:57:51 +02006679 expbackq(argbackq->n, flags | inquotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006680 argbackq = argbackq->next;
6681 goto start;
Denys Vlasenko0b883582016-12-23 16:49:07 +01006682#if ENABLE_FEATURE_SH_MATH
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006683 case CTLENDARI:
6684 p--;
Ron Yorston549deab2015-05-18 09:57:51 +02006685 expari(flags | inquotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006686 goto start;
6687#endif
6688 }
6689 }
Denys Vlasenko958581a2010-09-12 15:04:27 +02006690 breakloop: ;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006691}
6692
6693static char *
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006694scanleft(char *startp, char *rmesc, char *rmescend UNUSED_PARAM,
6695 char *pattern, int quotes, int zero)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006696{
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006697 char *loc, *loc2;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006698 char c;
6699
6700 loc = startp;
6701 loc2 = rmesc;
6702 do {
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006703 int match;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006704 const char *s = loc2;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006705
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006706 c = *loc2;
6707 if (zero) {
6708 *loc2 = '\0';
6709 s = rmesc;
6710 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006711 match = pmatch(pattern, s);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006712
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006713 *loc2 = c;
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006714 if (match)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006715 return loc;
Denys Vlasenkocd716832009-11-28 22:14:02 +01006716 if (quotes && (unsigned char)*loc == CTLESC)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006717 loc++;
6718 loc++;
6719 loc2++;
6720 } while (c);
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006721 return NULL;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006722}
6723
6724static char *
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006725scanright(char *startp, char *rmesc, char *rmescend,
6726 char *pattern, int quotes, int match_at_start)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006727{
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006728#if !ENABLE_ASH_OPTIMIZE_FOR_SIZE
6729 int try2optimize = match_at_start;
6730#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006731 int esc = 0;
6732 char *loc;
6733 char *loc2;
6734
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006735 /* If we called by "${v/pattern/repl}" or "${v//pattern/repl}":
6736 * startp="escaped_value_of_v" rmesc="raw_value_of_v"
6737 * rmescend=""(ptr to NUL in rmesc) pattern="pattern" quotes=match_at_start=1
6738 * Logic:
6739 * loc starts at NUL at the end of startp, loc2 starts at the end of rmesc,
6740 * and on each iteration they go back two/one char until they reach the beginning.
6741 * We try to find a match in "raw_value_of_v", "raw_value_of_", "raw_value_of" etc.
6742 */
6743 /* TODO: document in what other circumstances we are called. */
6744
6745 for (loc = pattern - 1, loc2 = rmescend; loc >= startp; loc2--) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006746 int match;
6747 char c = *loc2;
6748 const char *s = loc2;
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006749 if (match_at_start) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006750 *loc2 = '\0';
6751 s = rmesc;
6752 }
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006753 match = pmatch(pattern, s);
6754 //bb_error_msg("pmatch(pattern:'%s',s:'%s'):%d", pattern, s, match);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006755 *loc2 = c;
6756 if (match)
6757 return loc;
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006758#if !ENABLE_ASH_OPTIMIZE_FOR_SIZE
6759 if (try2optimize) {
6760 /* Maybe we can optimize this:
6761 * if pattern ends with unescaped *, we can avoid checking
Denys Vlasenko10ad6222017-04-17 16:13:32 +02006762 * shorter strings: if "foo*" doesn't match "raw_value_of_v",
6763 * it won't match truncated "raw_value_of_" strings too.
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006764 */
6765 unsigned plen = strlen(pattern);
6766 /* Does it end with "*"? */
6767 if (plen != 0 && pattern[--plen] == '*') {
6768 /* "xxxx*" is not escaped */
6769 /* "xxx\*" is escaped */
6770 /* "xx\\*" is not escaped */
6771 /* "x\\\*" is escaped */
6772 int slashes = 0;
6773 while (plen != 0 && pattern[--plen] == '\\')
6774 slashes++;
6775 if (!(slashes & 1))
6776 break; /* ends with unescaped "*" */
6777 }
6778 try2optimize = 0;
6779 }
6780#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006781 loc--;
6782 if (quotes) {
6783 if (--esc < 0) {
6784 esc = esclen(startp, loc);
6785 }
6786 if (esc % 2) {
6787 esc--;
6788 loc--;
6789 }
6790 }
6791 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006792 return NULL;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006793}
6794
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00006795static void varunset(const char *, const char *, const char *, int) NORETURN;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006796static void
6797varunset(const char *end, const char *var, const char *umsg, int varflags)
6798{
6799 const char *msg;
6800 const char *tail;
6801
6802 tail = nullstr;
6803 msg = "parameter not set";
6804 if (umsg) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006805 if ((unsigned char)*end == CTLENDVAR) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006806 if (varflags & VSNUL)
6807 tail = " or null";
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006808 } else {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006809 msg = umsg;
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006810 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006811 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006812 ash_msg_and_raise_error("%.*s: %s%s", (int)(end - var - 1), var, msg, tail);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006813}
6814
6815static const char *
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006816subevalvar(char *p, char *varname, int strloc, int subtype,
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02006817 int startloc, int varflags, int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006818{
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006819 struct nodelist *saveargbackq = argbackq;
Ron Yorston549deab2015-05-18 09:57:51 +02006820 int quotes = flag & QUOTES_ESC;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006821 char *startp;
6822 char *loc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006823 char *rmesc, *rmescend;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006824 char *str;
Denys Vlasenko0b4980c2012-09-25 12:49:29 +02006825 int amount, resetloc;
Denys Vlasenko740058b2018-01-09 17:01:00 +01006826 int argstr_flags;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006827 IF_BASH_PATTERN_SUBST(int workloc;)
Denys Vlasenko740058b2018-01-09 17:01:00 +01006828 IF_BASH_PATTERN_SUBST(int slash_pos;)
6829 IF_BASH_PATTERN_SUBST(char *repl;)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006830 int zero;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006831 char *(*scan)(char*, char*, char*, char*, int, int);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006832
Denys Vlasenko6040fe82010-09-12 15:03:16 +02006833 //bb_error_msg("subevalvar(p:'%s',varname:'%s',strloc:%d,subtype:%d,startloc:%d,varflags:%x,quotes:%d)",
6834 // p, varname, strloc, subtype, startloc, varflags, quotes);
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006835
Denys Vlasenko740058b2018-01-09 17:01:00 +01006836#if BASH_PATTERN_SUBST
Denys Vlasenkod1df1a72018-01-09 17:25:58 +01006837 /* For "${v/pattern/repl}", we must find the delimiter _before_
6838 * argstr() call expands possible variable references in pattern:
6839 * think about "v=a; a=a/; echo ${v/$a/r}" case.
6840 */
Denys Vlasenko740058b2018-01-09 17:01:00 +01006841 repl = NULL;
6842 if (subtype == VSREPLACE || subtype == VSREPLACEALL) {
6843 /* Find '/' and replace with NUL */
6844 repl = p;
6845 for (;;) {
6846 /* Handle escaped slashes, e.g. "${v/\//_}" (they are CTLESC'ed by this point) */
6847 if (*repl == '\0') {
6848 repl = NULL;
6849 break;
6850 }
6851 if (*repl == '/') {
6852 *repl = '\0';
6853 break;
6854 }
Denys Vlasenkod1df1a72018-01-09 17:25:58 +01006855 if ((unsigned char)*repl == CTLESC && repl[1])
Denys Vlasenko740058b2018-01-09 17:01:00 +01006856 repl++;
Denys Vlasenko740058b2018-01-09 17:01:00 +01006857 repl++;
6858 }
6859 }
6860#endif
6861 argstr_flags = EXP_TILDE;
Denys Vlasenko216913c2018-04-02 12:35:04 +02006862 if (subtype != VSASSIGN
6863 && subtype != VSQUESTION
6864#if BASH_SUBSTR
6865 && subtype != VSSUBSTR
6866#endif
6867 ) {
6868 /* EXP_CASE keeps CTLESC's */
6869 argstr_flags = EXP_TILDE | EXP_CASE;
6870 }
Denys Vlasenko740058b2018-01-09 17:01:00 +01006871 argstr(p, argstr_flags);
Denys Vlasenko216913c2018-04-02 12:35:04 +02006872 //bb_error_msg("str0:'%s'", (char *)stackblock() + strloc);
Denys Vlasenko740058b2018-01-09 17:01:00 +01006873#if BASH_PATTERN_SUBST
6874 slash_pos = -1;
6875 if (repl) {
6876 slash_pos = expdest - ((char *)stackblock() + strloc);
6877 STPUTC('/', expdest);
Denys Vlasenko216913c2018-04-02 12:35:04 +02006878 //bb_error_msg("repl+1:'%s'", repl + 1);
6879 argstr(repl + 1, EXP_TILDE); /* EXP_TILDE: echo "${v/x/~}" expands ~ ! */
Denys Vlasenko740058b2018-01-09 17:01:00 +01006880 *repl = '/';
6881 }
6882#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006883 STPUTC('\0', expdest);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006884 argbackq = saveargbackq;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006885 startp = (char *)stackblock() + startloc;
Denys Vlasenko740058b2018-01-09 17:01:00 +01006886 //bb_error_msg("str1:'%s'", (char *)stackblock() + strloc);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006887
6888 switch (subtype) {
6889 case VSASSIGN:
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02006890 setvar0(varname, startp);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006891 amount = startp - expdest;
6892 STADJUST(amount, expdest);
6893 return startp;
6894
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006895 case VSQUESTION:
6896 varunset(p, varname, startp, varflags);
6897 /* NOTREACHED */
6898
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006899#if BASH_SUBSTR
Denys Vlasenko826360f2017-07-17 17:49:11 +02006900 case VSSUBSTR: {
6901 int pos, len, orig_len;
6902 char *colon;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006903
Denys Vlasenko826360f2017-07-17 17:49:11 +02006904 loc = str = stackblock() + strloc;
6905
Denys Vlasenko826360f2017-07-17 17:49:11 +02006906 /* Read POS in ${var:POS:LEN} */
6907 colon = strchr(loc, ':');
6908 if (colon) *colon = '\0';
Denys Vlasenkobaa41c72018-01-10 13:22:25 +01006909 pos = substr_atoi(loc);
Denys Vlasenko826360f2017-07-17 17:49:11 +02006910 if (colon) *colon = ':';
6911
6912 /* Read LEN in ${var:POS:LEN} */
6913 len = str - startp - 1;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006914 /* *loc != '\0', guaranteed by parser */
6915 if (quotes) {
6916 char *ptr;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006917 /* Adjust the length by the number of escapes */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006918 for (ptr = startp; ptr < (str - 1); ptr++) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006919 if ((unsigned char)*ptr == CTLESC) {
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006920 len--;
6921 ptr++;
6922 }
6923 }
6924 }
6925 orig_len = len;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006926 if (*loc++ == ':') {
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006927 /* ${var::LEN} */
Denys Vlasenkobaa41c72018-01-10 13:22:25 +01006928 len = substr_atoi(loc);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006929 } else {
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006930 /* Skip POS in ${var:POS:LEN} */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006931 len = orig_len;
Denys Vlasenkobaa41c72018-01-10 13:22:25 +01006932 while (*loc && *loc != ':')
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006933 loc++;
Denys Vlasenkobaa41c72018-01-10 13:22:25 +01006934 if (*loc++ == ':')
6935 len = substr_atoi(loc);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006936 }
Denys Vlasenko08a5dab2014-11-17 20:27:18 +01006937 if (pos < 0) {
6938 /* ${VAR:$((-n)):l} starts n chars from the end */
6939 pos = orig_len + pos;
6940 }
6941 if ((unsigned)pos >= orig_len) {
6942 /* apart from obvious ${VAR:999999:l},
6943 * covers ${VAR:$((-9999999)):l} - result is ""
Denys Vlasenko826360f2017-07-17 17:49:11 +02006944 * (bash compat)
Denys Vlasenko08a5dab2014-11-17 20:27:18 +01006945 */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006946 pos = 0;
6947 len = 0;
6948 }
Denys Vlasenko826360f2017-07-17 17:49:11 +02006949 if (len < 0) {
6950 /* ${VAR:N:-M} sets LEN to strlen()-M */
6951 len = (orig_len - pos) + len;
6952 }
6953 if ((unsigned)len > (orig_len - pos))
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006954 len = orig_len - pos;
6955
6956 for (str = startp; pos; str++, pos--) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006957 if (quotes && (unsigned char)*str == CTLESC)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006958 str++;
6959 }
6960 for (loc = startp; len; len--) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006961 if (quotes && (unsigned char)*str == CTLESC)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006962 *loc++ = *str++;
6963 *loc++ = *str++;
6964 }
6965 *loc = '\0';
6966 amount = loc - expdest;
6967 STADJUST(amount, expdest);
6968 return loc;
Denys Vlasenko826360f2017-07-17 17:49:11 +02006969 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006970#endif /* BASH_SUBSTR */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006971 }
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006972
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006973 resetloc = expdest - (char *)stackblock();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006974
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006975#if BASH_PATTERN_SUBST
Denys Vlasenko740058b2018-01-09 17:01:00 +01006976 repl = NULL;
6977
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006978 /* We'll comeback here if we grow the stack while handling
6979 * a VSREPLACE or VSREPLACEALL, since our pointers into the
6980 * stack will need rebasing, and we'll need to remove our work
6981 * areas each time
6982 */
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006983 restart:
6984#endif
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006985
6986 amount = expdest - ((char *)stackblock() + resetloc);
6987 STADJUST(-amount, expdest);
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006988 startp = (char *)stackblock() + startloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006989
6990 rmesc = startp;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006991 rmescend = (char *)stackblock() + strloc;
Denys Vlasenko740058b2018-01-09 17:01:00 +01006992 //bb_error_msg("str7:'%s'", rmescend);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006993 if (quotes) {
Denys Vlasenko740058b2018-01-09 17:01:00 +01006994//TODO: how to handle slash_pos here if string changes (shortens?)
6995 rmesc = rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW, NULL);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006996 if (rmesc != startp) {
6997 rmescend = expdest;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006998 startp = (char *)stackblock() + startloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006999 }
7000 }
7001 rmescend--;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00007002 str = (char *)stackblock() + strloc;
Ron Yorston417622c2015-05-18 09:59:14 +02007003 /*
7004 * Example: v='a\bc'; echo ${v/\\b/_\\_\z_}
7005 * The result is a_\_z_c (not a\_\_z_c)!
7006 *
7007 * The search pattern and replace string treat backslashes differently!
Denys Vlasenko740058b2018-01-09 17:01:00 +01007008 * "&slash_pos" causes rmescapes() to work differently on the pattern
Ron Yorston417622c2015-05-18 09:59:14 +02007009 * and string. It's only used on the first call.
7010 */
Denys Vlasenko740058b2018-01-09 17:01:00 +01007011 //bb_error_msg("str8:'%s' slash_pos:%d", str, slash_pos);
7012 rmescapes(str, RMESCAPE_GLOB,
7013 repl ? NULL : (slash_pos < 0 ? NULL : &slash_pos)
7014 );
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007015
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01007016#if BASH_PATTERN_SUBST
Denys Vlasenko0b4980c2012-09-25 12:49:29 +02007017 workloc = expdest - (char *)stackblock();
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007018 if (subtype == VSREPLACE || subtype == VSREPLACEALL) {
Denys Vlasenko826360f2017-07-17 17:49:11 +02007019 int len;
Denys Vlasenkob76356b2010-03-13 16:19:04 +01007020 char *idx, *end;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007021
Denis Vlasenkod6855d12008-09-27 14:03:25 +00007022 if (!repl) {
Denys Vlasenko740058b2018-01-09 17:01:00 +01007023 //bb_error_msg("str9:'%s' slash_pos:%d", str, slash_pos);
Denys Vlasenkod1df1a72018-01-09 17:25:58 +01007024 repl = nullstr;
Denys Vlasenko740058b2018-01-09 17:01:00 +01007025 if (slash_pos >= 0) {
7026 repl = str + slash_pos;
Ron Yorston417622c2015-05-18 09:59:14 +02007027 *repl++ = '\0';
Denys Vlasenko740058b2018-01-09 17:01:00 +01007028 }
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007029 }
Ron Yorston417622c2015-05-18 09:59:14 +02007030 //bb_error_msg("str:'%s' repl:'%s'", str, repl);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007031
7032 /* If there's no pattern to match, return the expansion unmolested */
Denys Vlasenkob76356b2010-03-13 16:19:04 +01007033 if (str[0] == '\0')
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02007034 return NULL;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007035
7036 len = 0;
7037 idx = startp;
7038 end = str - 1;
7039 while (idx < end) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01007040 try_to_match:
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007041 loc = scanright(idx, rmesc, rmescend, str, quotes, 1);
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02007042 //bb_error_msg("scanright('%s'):'%s'", str, loc);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007043 if (!loc) {
7044 /* No match, advance */
Denys Vlasenkob76356b2010-03-13 16:19:04 +01007045 char *restart_detect = stackblock();
7046 skip_matching:
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007047 STPUTC(*idx, expdest);
Denys Vlasenkocd716832009-11-28 22:14:02 +01007048 if (quotes && (unsigned char)*idx == CTLESC) {
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007049 idx++;
7050 len++;
7051 STPUTC(*idx, expdest);
7052 }
7053 if (stackblock() != restart_detect)
7054 goto restart;
7055 idx++;
7056 len++;
7057 rmesc++;
Denys Vlasenkob76356b2010-03-13 16:19:04 +01007058 /* continue; - prone to quadratic behavior, smarter code: */
7059 if (idx >= end)
7060 break;
7061 if (str[0] == '*') {
7062 /* Pattern is "*foo". If "*foo" does not match "long_string",
7063 * it would never match "ong_string" etc, no point in trying.
7064 */
7065 goto skip_matching;
7066 }
7067 goto try_to_match;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007068 }
7069
7070 if (subtype == VSREPLACEALL) {
7071 while (idx < loc) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01007072 if (quotes && (unsigned char)*idx == CTLESC)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007073 idx++;
7074 idx++;
7075 rmesc++;
7076 }
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00007077 } else {
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007078 idx = loc;
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00007079 }
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007080
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02007081 //bb_error_msg("repl:'%s'", repl);
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007082 for (loc = (char*)repl; *loc; loc++) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01007083 char *restart_detect = stackblock();
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007084 if (quotes && *loc == '\\') {
7085 STPUTC(CTLESC, expdest);
7086 len++;
7087 }
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007088 STPUTC(*loc, expdest);
7089 if (stackblock() != restart_detect)
7090 goto restart;
7091 len++;
7092 }
7093
7094 if (subtype == VSREPLACE) {
Denys Vlasenkof02c82f2010-08-06 19:14:47 +02007095 //bb_error_msg("tail:'%s', quotes:%x", idx, quotes);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007096 while (*idx) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01007097 char *restart_detect = stackblock();
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007098 STPUTC(*idx, expdest);
7099 if (stackblock() != restart_detect)
7100 goto restart;
7101 len++;
7102 idx++;
7103 }
7104 break;
7105 }
7106 }
7107
7108 /* We've put the replaced text into a buffer at workloc, now
7109 * move it to the right place and adjust the stack.
7110 */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007111 STPUTC('\0', expdest);
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007112 startp = (char *)stackblock() + startloc;
7113 memmove(startp, (char *)stackblock() + workloc, len + 1);
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02007114 //bb_error_msg("startp:'%s'", startp);
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007115 amount = expdest - (startp + len);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007116 STADJUST(-amount, expdest);
7117 return startp;
7118 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01007119#endif /* BASH_PATTERN_SUBST */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007120
7121 subtype -= VSTRIMRIGHT;
7122#if DEBUG
7123 if (subtype < 0 || subtype > 7)
7124 abort();
7125#endif
Denys Vlasenkob76356b2010-03-13 16:19:04 +01007126 /* zero = (subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX) */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007127 zero = subtype >> 1;
7128 /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */
7129 scan = (subtype & 1) ^ zero ? scanleft : scanright;
7130
7131 loc = scan(startp, rmesc, rmescend, str, quotes, zero);
7132 if (loc) {
7133 if (zero) {
7134 memmove(startp, loc, str - loc);
7135 loc = startp + (str - loc) - 1;
7136 }
7137 *loc = '\0';
7138 amount = loc - expdest;
7139 STADJUST(amount, expdest);
7140 }
7141 return loc;
7142}
7143
7144/*
7145 * Add the value of a specialized variable to the stack string.
Denys Vlasenko4d8873f2009-10-04 03:14:41 +02007146 * name parameter (examples):
7147 * ash -c 'echo $1' name:'1='
7148 * ash -c 'echo $qwe' name:'qwe='
7149 * ash -c 'echo $$' name:'$='
7150 * ash -c 'echo ${$}' name:'$='
7151 * ash -c 'echo ${$##q}' name:'$=q'
7152 * ash -c 'echo ${#$}' name:'$='
7153 * note: examples with bad shell syntax:
7154 * ash -c 'echo ${#$1}' name:'$=1'
7155 * ash -c 'echo ${#1#}' name:'1=#'
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007156 */
Denys Vlasenkoadf922e2009-10-08 14:35:37 +02007157static NOINLINE ssize_t
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02007158varvalue(char *name, int varflags, int flags, int *quotedp)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007159{
Mike Frysinger98c52642009-04-02 10:02:37 +00007160 const char *p;
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01007161 int num;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007162 int i;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007163 ssize_t len = 0;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007164 int sep;
Denys Vlasenko0dd8e452016-10-01 21:02:06 +02007165 int quoted = *quotedp;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007166 int subtype = varflags & VSTYPE;
7167 int discard = subtype == VSPLUS || subtype == VSLENGTH;
7168 int quotes = (discard ? 0 : (flags & QUOTES_ESC)) | QUOTES_KEEPNUL;
Denys Vlasenko0aaaa502016-10-02 02:46:56 +02007169 int syntax;
7170
7171 sep = (flags & EXP_FULL) << CHAR_BIT;
7172 syntax = quoted ? DQSYNTAX : BASESYNTAX;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007173
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007174 switch (*name) {
7175 case '$':
7176 num = rootpid;
7177 goto numvar;
7178 case '?':
7179 num = exitstatus;
7180 goto numvar;
7181 case '#':
7182 num = shellparam.nparam;
7183 goto numvar;
7184 case '!':
7185 num = backgndpid;
7186 if (num == 0)
7187 return -1;
7188 numvar:
7189 len = cvtnum(num);
Denys Vlasenko4d8873f2009-10-04 03:14:41 +02007190 goto check_1char_name;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007191 case '-':
Mike Frysinger98c52642009-04-02 10:02:37 +00007192 expdest = makestrspace(NOPTS, expdest);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007193 for (i = NOPTS - 1; i >= 0; i--) {
Martijn Dekkerad4e9612018-03-31 18:15:59 +02007194 if (optlist[i] && optletters(i)) {
Mike Frysinger98c52642009-04-02 10:02:37 +00007195 USTPUTC(optletters(i), expdest);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007196 len++;
7197 }
7198 }
Denys Vlasenko4d8873f2009-10-04 03:14:41 +02007199 check_1char_name:
7200#if 0
7201 /* handles cases similar to ${#$1} */
7202 if (name[2] != '\0')
7203 raise_error_syntax("bad substitution");
7204#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007205 break;
Denys Vlasenko0aaaa502016-10-02 02:46:56 +02007206 case '@':
7207 if (quoted && sep)
7208 goto param;
7209 /* fall through */
7210 case '*': {
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01007211 char **ap;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007212 char sepc;
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01007213
Denys Vlasenko0aaaa502016-10-02 02:46:56 +02007214 if (quoted)
7215 sep = 0;
7216 sep |= ifsset() ? ifsval()[0] : ' ';
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007217 param:
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007218 sepc = sep;
Denys Vlasenko0dd8e452016-10-01 21:02:06 +02007219 *quotedp = !sepc;
7220 ap = shellparam.p;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007221 if (!ap)
7222 return -1;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02007223 while ((p = *ap++) != NULL) {
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007224 len += strtodest(p, syntax, quotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007225
7226 if (*ap && sep) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007227 len++;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007228 memtodest(&sepc, 1, syntax, quotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007229 }
7230 }
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007231 break;
Denys Vlasenko0aaaa502016-10-02 02:46:56 +02007232 } /* case '*' */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007233 case '0':
7234 case '1':
7235 case '2':
7236 case '3':
7237 case '4':
7238 case '5':
7239 case '6':
7240 case '7':
7241 case '8':
7242 case '9':
Denys Vlasenkoa00329c2009-08-30 20:05:10 +02007243 num = atoi(name); /* number(name) fails on ${N#str} etc */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007244 if (num < 0 || num > shellparam.nparam)
7245 return -1;
7246 p = num ? shellparam.p[num - 1] : arg0;
7247 goto value;
7248 default:
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00007249 /* NB: name has form "VAR=..." */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007250 p = lookupvar(name);
7251 value:
7252 if (!p)
7253 return -1;
7254
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007255 len = strtodest(p, syntax, quotes);
Denys Vlasenkoc76236f2014-12-29 00:04:18 +01007256#if ENABLE_UNICODE_SUPPORT
7257 if (subtype == VSLENGTH && len > 0) {
7258 reinit_unicode_for_ash();
7259 if (unicode_status == UNICODE_ON) {
Ron Yorston3e3bfb82016-03-18 11:29:19 +00007260 STADJUST(-len, expdest);
7261 discard = 0;
Denys Vlasenkoc76236f2014-12-29 00:04:18 +01007262 len = unicode_strlen(p);
7263 }
7264 }
7265#endif
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007266 break;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007267 }
7268
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007269 if (discard)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007270 STADJUST(-len, expdest);
7271 return len;
7272}
7273
7274/*
7275 * Expand a variable, and return a pointer to the next character in the
7276 * input string.
7277 */
7278static char *
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02007279evalvar(char *p, int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007280{
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00007281 char varflags;
7282 char subtype;
Ron Yorston549deab2015-05-18 09:57:51 +02007283 int quoted;
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00007284 char easy;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007285 char *var;
7286 int patloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007287 int startloc;
7288 ssize_t varlen;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007289
Denys Vlasenkob0d63382009-09-16 16:18:32 +02007290 varflags = (unsigned char) *p++;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007291 subtype = varflags & VSTYPE;
Denys Vlasenko88e15702016-10-26 01:55:56 +02007292
7293 if (!subtype)
7294 raise_error_syntax("bad substitution");
7295
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007296 quoted = flag & EXP_QUOTED;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007297 var = p;
7298 easy = (!quoted || (*var == '@' && shellparam.nparam));
7299 startloc = expdest - (char *)stackblock();
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02007300 p = strchr(p, '=') + 1; //TODO: use var_end(p)?
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007301
7302 again:
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02007303 varlen = varvalue(var, varflags, flag, &quoted);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007304 if (varflags & VSNUL)
7305 varlen--;
7306
7307 if (subtype == VSPLUS) {
7308 varlen = -1 - varlen;
7309 goto vsplus;
7310 }
7311
7312 if (subtype == VSMINUS) {
7313 vsplus:
7314 if (varlen < 0) {
7315 argstr(
Denys Vlasenko6040fe82010-09-12 15:03:16 +02007316 p,
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02007317 flag | EXP_TILDE | EXP_WORD
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007318 );
7319 goto end;
7320 }
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007321 goto record;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007322 }
7323
7324 if (subtype == VSASSIGN || subtype == VSQUESTION) {
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007325 if (varlen >= 0)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007326 goto record;
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007327
7328 subevalvar(p, var, 0, subtype, startloc, varflags,
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02007329 flag & ~QUOTES_ESC);
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007330 varflags &= ~VSNUL;
7331 /*
7332 * Remove any recorded regions beyond
7333 * start of variable
7334 */
7335 removerecordregions(startloc);
7336 goto again;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007337 }
7338
7339 if (varlen < 0 && uflag)
7340 varunset(p, var, 0, 0);
7341
7342 if (subtype == VSLENGTH) {
Denys Vlasenkoc76236f2014-12-29 00:04:18 +01007343 cvtnum(varlen > 0 ? varlen : 0);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007344 goto record;
7345 }
7346
7347 if (subtype == VSNORMAL) {
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007348 record:
7349 if (!easy)
7350 goto end;
Denys Vlasenko0dd8e452016-10-01 21:02:06 +02007351 recordregion(startloc, expdest - (char *)stackblock(), quoted);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007352 goto end;
7353 }
7354
7355#if DEBUG
7356 switch (subtype) {
7357 case VSTRIMLEFT:
7358 case VSTRIMLEFTMAX:
7359 case VSTRIMRIGHT:
7360 case VSTRIMRIGHTMAX:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01007361#if BASH_SUBSTR
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007362 case VSSUBSTR:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01007363#endif
7364#if BASH_PATTERN_SUBST
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007365 case VSREPLACE:
7366 case VSREPLACEALL:
7367#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007368 break;
7369 default:
7370 abort();
7371 }
7372#endif
7373
7374 if (varlen >= 0) {
7375 /*
7376 * Terminate the string and start recording the pattern
7377 * right after it
7378 */
7379 STPUTC('\0', expdest);
7380 patloc = expdest - (char *)stackblock();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02007381 if (NULL == subevalvar(p, /* varname: */ NULL, patloc, subtype,
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02007382 startloc, varflags, flag)) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007383 int amount = expdest - (
7384 (char *)stackblock() + patloc - 1
7385 );
7386 STADJUST(-amount, expdest);
7387 }
7388 /* Remove any recorded regions beyond start of variable */
7389 removerecordregions(startloc);
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007390 goto record;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007391 }
7392
7393 end:
7394 if (subtype != VSNORMAL) { /* skip to end of alternative */
7395 int nesting = 1;
7396 for (;;) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01007397 unsigned char c = *p++;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007398 if (c == CTLESC)
7399 p++;
Ron Yorston549deab2015-05-18 09:57:51 +02007400 else if (c == CTLBACKQ) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007401 if (varlen >= 0)
7402 argbackq = argbackq->next;
7403 } else if (c == CTLVAR) {
7404 if ((*p++ & VSTYPE) != VSNORMAL)
7405 nesting++;
7406 } else if (c == CTLENDVAR) {
7407 if (--nesting == 0)
7408 break;
7409 }
7410 }
7411 }
7412 return p;
7413}
7414
7415/*
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007416 * Add a file name to the list.
7417 */
7418static void
7419addfname(const char *name)
7420{
7421 struct strlist *sp;
7422
Denis Vlasenko597906c2008-02-20 16:38:54 +00007423 sp = stzalloc(sizeof(*sp));
Denys Vlasenko8e2bc472016-09-28 23:02:57 +02007424 sp->text = sstrdup(name);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007425 *exparg.lastp = sp;
7426 exparg.lastp = &sp->next;
7427}
7428
Felix Fietkaub5b21122017-01-31 21:58:55 +01007429/* Avoid glob() (and thus, stat() et al) for words like "echo" */
7430static int
7431hasmeta(const char *p)
7432{
7433 static const char chars[] ALIGN1 = {
7434 '*', '?', '[', '\\', CTLQUOTEMARK, CTLESC, 0
7435 };
7436
7437 for (;;) {
7438 p = strpbrk(p, chars);
7439 if (!p)
7440 break;
Denys Vlasenkoac61f442018-03-30 23:03:29 +02007441 switch ((unsigned char)*p) {
Felix Fietkaub5b21122017-01-31 21:58:55 +01007442 case CTLQUOTEMARK:
7443 for (;;) {
7444 p++;
Denys Vlasenkoac61f442018-03-30 23:03:29 +02007445 if ((unsigned char)*p == CTLQUOTEMARK)
Felix Fietkaub5b21122017-01-31 21:58:55 +01007446 break;
Denys Vlasenkoac61f442018-03-30 23:03:29 +02007447 if ((unsigned char)*p == CTLESC)
Felix Fietkaub5b21122017-01-31 21:58:55 +01007448 p++;
7449 if (*p == '\0') /* huh? */
7450 return 0;
7451 }
7452 break;
7453 case '\\':
7454 case CTLESC:
7455 p++;
7456 if (*p == '\0')
7457 return 0;
7458 break;
7459 case '[':
7460 if (!strchr(p + 1, ']')) {
7461 /* It's not a properly closed [] pattern,
7462 * but other metas may follow. Continue checking.
7463 * my[file* _is_ globbed by bash
7464 * and matches filenames like "my[file1".
7465 */
7466 break;
7467 }
7468 /* fallthrough */
7469 default:
7470 /* case '*': */
7471 /* case '?': */
7472 return 1;
7473 }
7474 p++;
7475 }
7476
7477 return 0;
7478}
7479
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007480/* If we want to use glob() from libc... */
Denys Vlasenko514b51d2016-10-01 14:33:08 +02007481#if !ENABLE_ASH_INTERNAL_GLOB
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007482
7483/* Add the result of glob() to the list */
7484static void
7485addglob(const glob_t *pglob)
7486{
7487 char **p = pglob->gl_pathv;
7488
7489 do {
7490 addfname(*p);
7491 } while (*++p);
7492}
7493static void
7494expandmeta(struct strlist *str /*, int flag*/)
7495{
7496 /* TODO - EXP_REDIR */
7497
7498 while (str) {
7499 char *p;
7500 glob_t pglob;
7501 int i;
7502
7503 if (fflag)
7504 goto nometa;
Denys Vlasenkod4f3db92016-10-30 18:41:01 +01007505
Felix Fietkaub5b21122017-01-31 21:58:55 +01007506 if (!hasmeta(str->text))
7507 goto nometa;
Denys Vlasenkod4f3db92016-10-30 18:41:01 +01007508
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007509 INT_OFF;
7510 p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP);
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007511// GLOB_NOMAGIC (GNU): if no *?[ chars in pattern, return it even if no match
7512// GLOB_NOCHECK: if no match, return unchanged pattern (sans \* escapes?)
7513//
7514// glibc 2.24.90 glob(GLOB_NOMAGIC) does not remove backslashes used for escaping:
7515// if you pass it "file\?", it returns "file\?", not "file?", if no match.
7516// Which means you need to unescape the string, right? Not so fast:
7517// if there _is_ a file named "file\?" (with backslash), it is returned
7518// as "file\?" too (whichever pattern you used to find it, say, "file*").
Denys Vlasenko10ad6222017-04-17 16:13:32 +02007519// You DON'T KNOW by looking at the result whether you need to unescape it.
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007520//
7521// Worse, globbing of "file\?" in a directory with two files, "file?" and "file\?",
7522// returns "file\?" - which is WRONG: "file\?" pattern matches "file?" file.
7523// Without GLOB_NOMAGIC, this works correctly ("file?" is returned as a match).
7524// With GLOB_NOMAGIC | GLOB_NOCHECK, this also works correctly.
7525// i = glob(p, GLOB_NOMAGIC | GLOB_NOCHECK, NULL, &pglob);
7526// i = glob(p, GLOB_NOMAGIC, NULL, &pglob);
7527 i = glob(p, 0, NULL, &pglob);
7528 //bb_error_msg("glob('%s'):%d '%s'...", p, i, pglob.gl_pathv ? pglob.gl_pathv[0] : "-");
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007529 if (p != str->text)
7530 free(p);
7531 switch (i) {
7532 case 0:
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007533#if 0 // glibc 2.24.90 bug? Patterns like "*/file", when match, don't set GLOB_MAGCHAR
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007534 /* GLOB_MAGCHAR is set if *?[ chars were seen (GNU) */
7535 if (!(pglob.gl_flags & GLOB_MAGCHAR))
7536 goto nometa2;
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007537#endif
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007538 addglob(&pglob);
7539 globfree(&pglob);
7540 INT_ON;
7541 break;
7542 case GLOB_NOMATCH:
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007543 //nometa2:
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007544 globfree(&pglob);
7545 INT_ON;
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007546 nometa:
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007547 *exparg.lastp = str;
Denys Vlasenko740058b2018-01-09 17:01:00 +01007548 rmescapes(str->text, 0, NULL);
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007549 exparg.lastp = &str->next;
7550 break;
7551 default: /* GLOB_NOSPACE */
7552 globfree(&pglob);
7553 INT_ON;
7554 ash_msg_and_raise_error(bb_msg_memory_exhausted);
7555 }
7556 str = str->next;
7557 }
7558}
7559
7560#else
Denys Vlasenko514b51d2016-10-01 14:33:08 +02007561/* ENABLE_ASH_INTERNAL_GLOB: Homegrown globbing code. (dash also has both, uses homegrown one.) */
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007562
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007563/*
7564 * Do metacharacter (i.e. *, ?, [...]) expansion.
7565 */
7566static void
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007567expmeta(char *expdir, char *enddir, char *name)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007568{
7569 char *p;
7570 const char *cp;
7571 char *start;
7572 char *endname;
7573 int metaflag;
7574 struct stat statb;
7575 DIR *dirp;
7576 struct dirent *dp;
7577 int atend;
7578 int matchdot;
Ron Yorstonca25af92015-09-04 10:32:41 +01007579 int esc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007580
7581 metaflag = 0;
7582 start = name;
Ron Yorstonca25af92015-09-04 10:32:41 +01007583 for (p = name; esc = 0, *p; p += esc + 1) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007584 if (*p == '*' || *p == '?')
7585 metaflag = 1;
7586 else if (*p == '[') {
7587 char *q = p + 1;
7588 if (*q == '!')
7589 q++;
7590 for (;;) {
7591 if (*q == '\\')
7592 q++;
7593 if (*q == '/' || *q == '\0')
7594 break;
7595 if (*++q == ']') {
7596 metaflag = 1;
7597 break;
7598 }
7599 }
Ron Yorstonca25af92015-09-04 10:32:41 +01007600 } else {
7601 if (*p == '\\')
7602 esc++;
7603 if (p[esc] == '/') {
7604 if (metaflag)
7605 break;
7606 start = p + esc + 1;
7607 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007608 }
7609 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007610 if (metaflag == 0) { /* we've reached the end of the file name */
7611 if (enddir != expdir)
7612 metaflag++;
7613 p = name;
7614 do {
7615 if (*p == '\\')
7616 p++;
7617 *enddir++ = *p;
7618 } while (*p++);
7619 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
7620 addfname(expdir);
7621 return;
7622 }
7623 endname = p;
7624 if (name < start) {
7625 p = name;
7626 do {
7627 if (*p == '\\')
7628 p++;
7629 *enddir++ = *p++;
7630 } while (p < start);
7631 }
7632 if (enddir == expdir) {
7633 cp = ".";
7634 } else if (enddir == expdir + 1 && *expdir == '/') {
7635 cp = "/";
7636 } else {
7637 cp = expdir;
7638 enddir[-1] = '\0';
7639 }
7640 dirp = opendir(cp);
7641 if (dirp == NULL)
7642 return;
7643 if (enddir != expdir)
7644 enddir[-1] = '/';
7645 if (*endname == 0) {
7646 atend = 1;
7647 } else {
7648 atend = 0;
Ron Yorstonca25af92015-09-04 10:32:41 +01007649 *endname = '\0';
7650 endname += esc + 1;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007651 }
7652 matchdot = 0;
7653 p = start;
7654 if (*p == '\\')
7655 p++;
7656 if (*p == '.')
7657 matchdot++;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02007658 while (!pending_int && (dp = readdir(dirp)) != NULL) {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00007659 if (dp->d_name[0] == '.' && !matchdot)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007660 continue;
7661 if (pmatch(start, dp->d_name)) {
7662 if (atend) {
7663 strcpy(enddir, dp->d_name);
7664 addfname(expdir);
7665 } else {
7666 for (p = enddir, cp = dp->d_name; (*p++ = *cp++) != '\0';)
7667 continue;
7668 p[-1] = '/';
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007669 expmeta(expdir, p, endname);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007670 }
7671 }
7672 }
7673 closedir(dirp);
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00007674 if (!atend)
Ron Yorstonca25af92015-09-04 10:32:41 +01007675 endname[-esc - 1] = esc ? '\\' : '/';
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007676}
7677
7678static struct strlist *
7679msort(struct strlist *list, int len)
7680{
7681 struct strlist *p, *q = NULL;
7682 struct strlist **lpp;
7683 int half;
7684 int n;
7685
7686 if (len <= 1)
7687 return list;
7688 half = len >> 1;
7689 p = list;
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +00007690 for (n = half; --n >= 0;) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007691 q = p;
7692 p = p->next;
7693 }
7694 q->next = NULL; /* terminate first half of list */
7695 q = msort(list, half); /* sort first half of list */
7696 p = msort(p, len - half); /* sort second half */
7697 lpp = &list;
7698 for (;;) {
7699#if ENABLE_LOCALE_SUPPORT
7700 if (strcoll(p->text, q->text) < 0)
7701#else
7702 if (strcmp(p->text, q->text) < 0)
7703#endif
7704 {
7705 *lpp = p;
7706 lpp = &p->next;
7707 p = *lpp;
7708 if (p == NULL) {
7709 *lpp = q;
7710 break;
7711 }
7712 } else {
7713 *lpp = q;
7714 lpp = &q->next;
7715 q = *lpp;
7716 if (q == NULL) {
7717 *lpp = p;
7718 break;
7719 }
7720 }
7721 }
7722 return list;
7723}
7724
7725/*
7726 * Sort the results of file name expansion. It calculates the number of
7727 * strings to sort and then calls msort (short for merge sort) to do the
7728 * work.
7729 */
7730static struct strlist *
7731expsort(struct strlist *str)
7732{
7733 int len;
7734 struct strlist *sp;
7735
7736 len = 0;
7737 for (sp = str; sp; sp = sp->next)
7738 len++;
7739 return msort(str, len);
7740}
7741
7742static void
Denis Vlasenko68404f12008-03-17 09:00:54 +00007743expandmeta(struct strlist *str /*, int flag*/)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007744{
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007745 /* TODO - EXP_REDIR */
7746
7747 while (str) {
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007748 char *expdir;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007749 struct strlist **savelastp;
7750 struct strlist *sp;
7751 char *p;
7752
7753 if (fflag)
7754 goto nometa;
Felix Fietkaub5b21122017-01-31 21:58:55 +01007755 if (!hasmeta(str->text))
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007756 goto nometa;
7757 savelastp = exparg.lastp;
7758
7759 INT_OFF;
Ron Yorston549deab2015-05-18 09:57:51 +02007760 p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007761 {
7762 int i = strlen(str->text);
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007763//BUGGY estimation of how long expanded name can be
7764 expdir = ckmalloc(i < 2048 ? 2048 : i+1);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007765 }
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007766 expmeta(expdir, expdir, p);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007767 free(expdir);
7768 if (p != str->text)
7769 free(p);
7770 INT_ON;
7771 if (exparg.lastp == savelastp) {
7772 /*
7773 * no matches
7774 */
7775 nometa:
7776 *exparg.lastp = str;
Denys Vlasenko740058b2018-01-09 17:01:00 +01007777 rmescapes(str->text, 0, NULL);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007778 exparg.lastp = &str->next;
7779 } else {
7780 *exparg.lastp = NULL;
7781 *savelastp = sp = expsort(*savelastp);
7782 while (sp->next != NULL)
7783 sp = sp->next;
7784 exparg.lastp = &sp->next;
7785 }
7786 str = str->next;
7787 }
7788}
Denys Vlasenko514b51d2016-10-01 14:33:08 +02007789#endif /* ENABLE_ASH_INTERNAL_GLOB */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007790
7791/*
7792 * Perform variable substitution and command substitution on an argument,
7793 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
7794 * perform splitting and file name expansion. When arglist is NULL, perform
7795 * here document expansion.
7796 */
7797static void
7798expandarg(union node *arg, struct arglist *arglist, int flag)
7799{
7800 struct strlist *sp;
7801 char *p;
7802
7803 argbackq = arg->narg.backquote;
7804 STARTSTACKSTR(expdest);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02007805 TRACE(("expandarg: argstr('%s',flags:%x)\n", arg->narg.text, flag));
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02007806 argstr(arg->narg.text, flag);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007807 p = _STPUTC('\0', expdest);
7808 expdest = p - 1;
7809 if (arglist == NULL) {
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02007810 /* here document expanded */
7811 goto out;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007812 }
7813 p = grabstackstr(p);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02007814 TRACE(("expandarg: p:'%s'\n", p));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007815 exparg.lastp = &exparg.list;
7816 /*
7817 * TODO - EXP_REDIR
7818 */
7819 if (flag & EXP_FULL) {
7820 ifsbreakup(p, &exparg);
7821 *exparg.lastp = NULL;
7822 exparg.lastp = &exparg.list;
Denis Vlasenko68404f12008-03-17 09:00:54 +00007823 expandmeta(exparg.list /*, flag*/);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007824 } else {
Denis Vlasenko597906c2008-02-20 16:38:54 +00007825 sp = stzalloc(sizeof(*sp));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007826 sp->text = p;
7827 *exparg.lastp = sp;
7828 exparg.lastp = &sp->next;
7829 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007830 *exparg.lastp = NULL;
7831 if (exparg.list) {
7832 *arglist->lastp = exparg.list;
7833 arglist->lastp = exparg.lastp;
7834 }
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02007835
7836 out:
7837 ifsfree();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007838}
7839
7840/*
7841 * Expand shell variables and backquotes inside a here document.
7842 */
7843static void
7844expandhere(union node *arg, int fd)
7845{
Ron Yorston549deab2015-05-18 09:57:51 +02007846 expandarg(arg, (struct arglist *)NULL, EXP_QUOTED);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007847 full_write(fd, stackblock(), expdest - (char *)stackblock());
7848}
7849
7850/*
7851 * Returns true if the pattern matches the string.
7852 */
7853static int
7854patmatch(char *pattern, const char *string)
7855{
Denys Vlasenkobd43c672017-07-05 23:12:15 +02007856 char *p = preglob(pattern, 0);
Denys Vlasenko4476c702017-08-15 15:27:41 +02007857 int r = pmatch(p, string);
7858 //bb_error_msg("!fnmatch(pattern:'%s',str:'%s',0):%d", p, string, r);
7859 return r;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007860}
7861
7862/*
7863 * See if a pattern matches in a case statement.
7864 */
7865static int
7866casematch(union node *pattern, char *val)
7867{
7868 struct stackmark smark;
7869 int result;
7870
7871 setstackmark(&smark);
7872 argbackq = pattern->narg.backquote;
7873 STARTSTACKSTR(expdest);
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02007874 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007875 STACKSTRNUL(expdest);
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02007876 ifsfree();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007877 result = patmatch(stackblock(), val);
7878 popstackmark(&smark);
7879 return result;
7880}
7881
7882
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007883/* ============ find_command */
7884
7885struct builtincmd {
7886 const char *name;
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02007887 int (*builtin)(int, char **) FAST_FUNC;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007888 /* unsigned flags; */
7889};
7890#define IS_BUILTIN_SPECIAL(b) ((b)->name[0] & 1)
Denis Vlasenkoe26b2782008-02-12 07:40:29 +00007891/* "regular" builtins always take precedence over commands,
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007892 * regardless of PATH=....%builtin... position */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007893#define IS_BUILTIN_REGULAR(b) ((b)->name[0] & 2)
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007894#define IS_BUILTIN_ASSIGN(b) ((b)->name[0] & 4)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007895
7896struct cmdentry {
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00007897 smallint cmdtype; /* CMDxxx */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007898 union param {
7899 int index;
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00007900 /* index >= 0 for commands without path (slashes) */
7901 /* (TODO: what exactly does the value mean? PATH position?) */
7902 /* index == -1 for commands with slashes */
7903 /* index == (-2 - applet_no) for NOFORK applets */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007904 const struct builtincmd *cmd;
7905 struct funcnode *func;
7906 } u;
7907};
7908/* values of cmdtype */
7909#define CMDUNKNOWN -1 /* no entry in table for command */
7910#define CMDNORMAL 0 /* command is an executable program */
7911#define CMDFUNCTION 1 /* command is a shell function */
7912#define CMDBUILTIN 2 /* command is a shell builtin */
7913
7914/* action to find_command() */
7915#define DO_ERR 0x01 /* prints errors */
7916#define DO_ABS 0x02 /* checks absolute paths */
7917#define DO_NOFUNC 0x04 /* don't return shell functions, for command */
7918#define DO_ALTPATH 0x08 /* using alternate path */
7919#define DO_ALTBLTIN 0x20 /* %builtin in alt. path */
7920
7921static void find_command(char *, struct cmdentry *, int, const char *);
7922
7923
7924/* ============ Hashing commands */
7925
7926/*
7927 * When commands are first encountered, they are entered in a hash table.
7928 * This ensures that a full path search will not have to be done for them
7929 * on each invocation.
7930 *
7931 * We should investigate converting to a linear search, even though that
7932 * would make the command name "hash" a misnomer.
7933 */
7934
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007935struct tblentry {
7936 struct tblentry *next; /* next entry in hash chain */
7937 union param param; /* definition of builtin function */
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00007938 smallint cmdtype; /* CMDxxx */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007939 char rehash; /* if set, cd done since entry created */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00007940 char cmdname[1]; /* name of command */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007941};
7942
Denis Vlasenko01631112007-12-16 17:20:38 +00007943static struct tblentry **cmdtable;
7944#define INIT_G_cmdtable() do { \
7945 cmdtable = xzalloc(CMDTABLESIZE * sizeof(cmdtable[0])); \
7946} while (0)
7947
7948static int builtinloc = -1; /* index in path of %builtin, or -1 */
7949
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007950
7951static void
Denys Vlasenko00a1dbd2017-07-29 01:20:53 +02007952tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) const char *cmd, char **argv, char **envp)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007953{
Denis Vlasenko80d14be2007-04-10 23:03:30 +00007954#if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007955 if (applet_no >= 0) {
Denis Vlasenkob7304742008-10-20 08:15:51 +00007956 if (APPLET_IS_NOEXEC(applet_no)) {
Denys Vlasenko7df28bb2010-06-18 14:23:47 +02007957 clearenv();
Denis Vlasenkob7304742008-10-20 08:15:51 +00007958 while (*envp)
7959 putenv(*envp++);
Denys Vlasenko035486c2017-07-31 04:09:19 +02007960 popredir(/*drop:*/ 1);
Denys Vlasenko80e8e3c2017-08-07 19:24:57 +02007961 run_noexec_applet_and_exit(applet_no, cmd, argv);
Denis Vlasenkob7304742008-10-20 08:15:51 +00007962 }
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007963 /* re-exec ourselves with the new arguments */
7964 execve(bb_busybox_exec_path, argv, envp);
7965 /* If they called chroot or otherwise made the binary no longer
7966 * executable, fall through */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007967 }
7968#endif
7969
7970 repeat:
7971#ifdef SYSV
7972 do {
7973 execve(cmd, argv, envp);
7974 } while (errno == EINTR);
7975#else
7976 execve(cmd, argv, envp);
7977#endif
Denys Vlasenko00a1dbd2017-07-29 01:20:53 +02007978 if (cmd != bb_busybox_exec_path && errno == ENOEXEC) {
Denys Vlasenkoaefe1c22011-03-07 12:02:40 +01007979 /* Run "cmd" as a shell script:
7980 * http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html
7981 * "If the execve() function fails with ENOEXEC, the shell
7982 * shall execute a command equivalent to having a shell invoked
7983 * with the command name as its first operand,
7984 * with any remaining arguments passed to the new shell"
7985 *
7986 * That is, do not use $SHELL, user's shell, or /bin/sh;
7987 * just call ourselves.
Denys Vlasenko2bef5262011-12-16 00:25:17 +01007988 *
7989 * Note that bash reads ~80 chars of the file, and if it sees
7990 * a zero byte before it sees newline, it doesn't try to
7991 * interpret it, but fails with "cannot execute binary file"
Denys Vlasenkocda6ea92011-12-16 00:44:36 +01007992 * message and exit code 126. For one, this prevents attempts
7993 * to interpret foreign ELF binaries as shell scripts.
Denys Vlasenkoaefe1c22011-03-07 12:02:40 +01007994 */
Denys Vlasenko00a1dbd2017-07-29 01:20:53 +02007995 argv[0] = (char*) cmd;
7996 cmd = bb_busybox_exec_path;
Denys Vlasenko65a8b852016-10-26 22:29:11 +02007997 /* NB: this is only possible because all callers of shellexec()
7998 * ensure that the argv[-1] slot exists!
7999 */
8000 argv--;
8001 argv[0] = (char*) "ash";
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008002 goto repeat;
8003 }
8004}
8005
8006/*
8007 * Exec a program. Never returns. If you change this routine, you may
8008 * have to change the find_command routine as well.
Denys Vlasenko65a8b852016-10-26 22:29:11 +02008009 * argv[-1] must exist and be writable! See tryexec() for why.
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008010 */
Denys Vlasenkoe139ae32017-04-12 21:02:33 +02008011static void shellexec(char *prog, char **argv, const char *path, int idx) NORETURN;
8012static void shellexec(char *prog, char **argv, const char *path, int idx)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008013{
8014 char *cmdname;
8015 int e;
8016 char **envp;
8017 int exerrno;
Denys Vlasenko83f103b2011-12-20 06:10:35 +01008018 int applet_no = -1; /* used only by FEATURE_SH_STANDALONE */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008019
Denys Vlasenkoa5060b82017-11-03 14:16:25 +01008020 envp = listvars(VEXPORT, VUNSET, /*strlist:*/ NULL, /*end:*/ NULL);
Denys Vlasenkoe139ae32017-04-12 21:02:33 +02008021 if (strchr(prog, '/') != NULL
Denis Vlasenko80d14be2007-04-10 23:03:30 +00008022#if ENABLE_FEATURE_SH_STANDALONE
Denys Vlasenkoe139ae32017-04-12 21:02:33 +02008023 || (applet_no = find_applet_by_name(prog)) >= 0
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008024#endif
8025 ) {
Denys Vlasenkoe139ae32017-04-12 21:02:33 +02008026 tryexec(IF_FEATURE_SH_STANDALONE(applet_no,) prog, argv, envp);
Denys Vlasenko83f103b2011-12-20 06:10:35 +01008027 if (applet_no >= 0) {
8028 /* We tried execing ourself, but it didn't work.
8029 * Maybe /proc/self/exe doesn't exist?
8030 * Try $PATH search.
8031 */
8032 goto try_PATH;
8033 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008034 e = errno;
8035 } else {
Denys Vlasenko83f103b2011-12-20 06:10:35 +01008036 try_PATH:
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008037 e = ENOENT;
Denys Vlasenkoe139ae32017-04-12 21:02:33 +02008038 while ((cmdname = path_advance(&path, prog)) != NULL) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008039 if (--idx < 0 && pathopt == NULL) {
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00008040 tryexec(IF_FEATURE_SH_STANDALONE(-1,) cmdname, argv, envp);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008041 if (errno != ENOENT && errno != ENOTDIR)
8042 e = errno;
8043 }
8044 stunalloc(cmdname);
8045 }
8046 }
8047
8048 /* Map to POSIX errors */
8049 switch (e) {
8050 case EACCES:
8051 exerrno = 126;
8052 break;
8053 case ENOENT:
8054 exerrno = 127;
8055 break;
8056 default:
8057 exerrno = 2;
8058 break;
8059 }
8060 exitstatus = exerrno;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02008061 TRACE(("shellexec failed for %s, errno %d, suppress_int %d\n",
Denys Vlasenkoe139ae32017-04-12 21:02:33 +02008062 prog, e, suppress_int));
8063 ash_msg_and_raise(EXEXIT, "%s: %s", prog, errmsg(e, "not found"));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008064 /* NOTREACHED */
8065}
8066
8067static void
8068printentry(struct tblentry *cmdp)
8069{
8070 int idx;
8071 const char *path;
8072 char *name;
8073
8074 idx = cmdp->param.index;
8075 path = pathval();
8076 do {
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02008077 name = path_advance(&path, cmdp->cmdname);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008078 stunalloc(name);
8079 } while (--idx >= 0);
8080 out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr));
8081}
8082
8083/*
8084 * Clear out command entries. The argument specifies the first entry in
8085 * PATH which has changed.
8086 */
8087static void
8088clearcmdentry(int firstchange)
8089{
8090 struct tblentry **tblp;
8091 struct tblentry **pp;
8092 struct tblentry *cmdp;
8093
8094 INT_OFF;
8095 for (tblp = cmdtable; tblp < &cmdtable[CMDTABLESIZE]; tblp++) {
8096 pp = tblp;
8097 while ((cmdp = *pp) != NULL) {
8098 if ((cmdp->cmdtype == CMDNORMAL &&
8099 cmdp->param.index >= firstchange)
8100 || (cmdp->cmdtype == CMDBUILTIN &&
8101 builtinloc >= firstchange)
8102 ) {
8103 *pp = cmdp->next;
8104 free(cmdp);
8105 } else {
8106 pp = &cmdp->next;
8107 }
8108 }
8109 }
8110 INT_ON;
8111}
8112
8113/*
8114 * Locate a command in the command hash table. If "add" is nonzero,
8115 * add the command to the table if it is not already present. The
8116 * variable "lastcmdentry" is set to point to the address of the link
8117 * pointing to the entry, so that delete_cmd_entry can delete the
8118 * entry.
8119 *
8120 * Interrupts must be off if called with add != 0.
8121 */
8122static struct tblentry **lastcmdentry;
8123
8124static struct tblentry *
8125cmdlookup(const char *name, int add)
8126{
8127 unsigned int hashval;
8128 const char *p;
8129 struct tblentry *cmdp;
8130 struct tblentry **pp;
8131
8132 p = name;
8133 hashval = (unsigned char)*p << 4;
8134 while (*p)
8135 hashval += (unsigned char)*p++;
8136 hashval &= 0x7FFF;
8137 pp = &cmdtable[hashval % CMDTABLESIZE];
8138 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
8139 if (strcmp(cmdp->cmdname, name) == 0)
8140 break;
8141 pp = &cmdp->next;
8142 }
8143 if (add && cmdp == NULL) {
Denis Vlasenkob07a4962008-06-22 13:16:23 +00008144 cmdp = *pp = ckzalloc(sizeof(struct tblentry)
8145 + strlen(name)
8146 /* + 1 - already done because
8147 * tblentry::cmdname is char[1] */);
Denis Vlasenko597906c2008-02-20 16:38:54 +00008148 /*cmdp->next = NULL; - ckzalloc did it */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008149 cmdp->cmdtype = CMDUNKNOWN;
8150 strcpy(cmdp->cmdname, name);
8151 }
8152 lastcmdentry = pp;
8153 return cmdp;
8154}
8155
8156/*
8157 * Delete the command entry returned on the last lookup.
8158 */
8159static void
8160delete_cmd_entry(void)
8161{
8162 struct tblentry *cmdp;
8163
8164 INT_OFF;
8165 cmdp = *lastcmdentry;
8166 *lastcmdentry = cmdp->next;
8167 if (cmdp->cmdtype == CMDFUNCTION)
8168 freefunc(cmdp->param.func);
8169 free(cmdp);
8170 INT_ON;
8171}
8172
8173/*
8174 * Add a new command entry, replacing any existing command entry for
8175 * the same name - except special builtins.
8176 */
8177static void
8178addcmdentry(char *name, struct cmdentry *entry)
8179{
8180 struct tblentry *cmdp;
8181
8182 cmdp = cmdlookup(name, 1);
8183 if (cmdp->cmdtype == CMDFUNCTION) {
8184 freefunc(cmdp->param.func);
8185 }
8186 cmdp->cmdtype = entry->cmdtype;
8187 cmdp->param = entry->u;
8188 cmdp->rehash = 0;
8189}
8190
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02008191static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00008192hashcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008193{
8194 struct tblentry **pp;
8195 struct tblentry *cmdp;
8196 int c;
8197 struct cmdentry entry;
8198 char *name;
8199
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008200 if (nextopt("r") != '\0') {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008201 clearcmdentry(0);
8202 return 0;
8203 }
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008204
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008205 if (*argptr == NULL) {
8206 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
8207 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
8208 if (cmdp->cmdtype == CMDNORMAL)
8209 printentry(cmdp);
8210 }
8211 }
8212 return 0;
8213 }
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008214
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008215 c = 0;
8216 while ((name = *argptr) != NULL) {
8217 cmdp = cmdlookup(name, 0);
8218 if (cmdp != NULL
8219 && (cmdp->cmdtype == CMDNORMAL
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008220 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))
8221 ) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008222 delete_cmd_entry();
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008223 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008224 find_command(name, &entry, DO_ERR, pathval());
8225 if (entry.cmdtype == CMDUNKNOWN)
8226 c = 1;
8227 argptr++;
8228 }
8229 return c;
8230}
8231
8232/*
8233 * Called when a cd is done. Marks all commands so the next time they
8234 * are executed they will be rehashed.
8235 */
8236static void
8237hashcd(void)
8238{
8239 struct tblentry **pp;
8240 struct tblentry *cmdp;
8241
8242 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
8243 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008244 if (cmdp->cmdtype == CMDNORMAL
8245 || (cmdp->cmdtype == CMDBUILTIN
Denys Vlasenkoe4dcba12010-10-28 18:57:19 +02008246 && !IS_BUILTIN_REGULAR(cmdp->param.cmd)
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008247 && builtinloc > 0)
8248 ) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008249 cmdp->rehash = 1;
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008250 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008251 }
8252 }
8253}
8254
8255/*
8256 * Fix command hash table when PATH changed.
8257 * Called before PATH is changed. The argument is the new value of PATH;
8258 * pathval() still returns the old value at this point.
8259 * Called with interrupts off.
8260 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02008261static void FAST_FUNC
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008262changepath(const char *new)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008263{
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008264 const char *old;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008265 int firstchange;
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008266 int idx;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008267 int idx_bltin;
8268
8269 old = pathval();
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008270 firstchange = 9999; /* assume no change */
8271 idx = 0;
8272 idx_bltin = -1;
8273 for (;;) {
8274 if (*old != *new) {
8275 firstchange = idx;
8276 if ((*old == '\0' && *new == ':')
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +02008277 || (*old == ':' && *new == '\0')
8278 ) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008279 firstchange++;
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +02008280 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008281 old = new; /* ignore subsequent differences */
8282 }
8283 if (*new == '\0')
8284 break;
8285 if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin"))
8286 idx_bltin = idx;
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008287 if (*new == ':')
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008288 idx++;
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +02008289 new++;
8290 old++;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008291 }
8292 if (builtinloc < 0 && idx_bltin >= 0)
8293 builtinloc = idx_bltin; /* zap builtins */
8294 if (builtinloc >= 0 && idx_bltin < 0)
8295 firstchange = 0;
8296 clearcmdentry(firstchange);
8297 builtinloc = idx_bltin;
8298}
Ron Yorston95ebcf72015-11-03 09:42:23 +00008299enum {
8300 TEOF,
8301 TNL,
8302 TREDIR,
8303 TWORD,
8304 TSEMI,
8305 TBACKGND,
8306 TAND,
8307 TOR,
8308 TPIPE,
8309 TLP,
8310 TRP,
8311 TENDCASE,
8312 TENDBQUOTE,
8313 TNOT,
8314 TCASE,
8315 TDO,
8316 TDONE,
8317 TELIF,
8318 TELSE,
8319 TESAC,
8320 TFI,
8321 TFOR,
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01008322#if BASH_FUNCTION
Ron Yorston95ebcf72015-11-03 09:42:23 +00008323 TFUNCTION,
8324#endif
8325 TIF,
8326 TIN,
8327 TTHEN,
8328 TUNTIL,
8329 TWHILE,
8330 TBEGIN,
8331 TEND
8332};
Denis Vlasenkob07a4962008-06-22 13:16:23 +00008333typedef smallint token_id_t;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008334
Denys Vlasenko888527c2016-10-02 16:54:17 +02008335/* Nth bit indicates if token marks the end of a list */
8336enum {
8337 tokendlist = 0
8338 /* 0 */ | (1u << TEOF)
8339 /* 1 */ | (0u << TNL)
8340 /* 2 */ | (0u << TREDIR)
8341 /* 3 */ | (0u << TWORD)
8342 /* 4 */ | (0u << TSEMI)
8343 /* 5 */ | (0u << TBACKGND)
8344 /* 6 */ | (0u << TAND)
8345 /* 7 */ | (0u << TOR)
8346 /* 8 */ | (0u << TPIPE)
8347 /* 9 */ | (0u << TLP)
8348 /* 10 */ | (1u << TRP)
8349 /* 11 */ | (1u << TENDCASE)
8350 /* 12 */ | (1u << TENDBQUOTE)
8351 /* 13 */ | (0u << TNOT)
8352 /* 14 */ | (0u << TCASE)
8353 /* 15 */ | (1u << TDO)
8354 /* 16 */ | (1u << TDONE)
8355 /* 17 */ | (1u << TELIF)
8356 /* 18 */ | (1u << TELSE)
8357 /* 19 */ | (1u << TESAC)
8358 /* 20 */ | (1u << TFI)
8359 /* 21 */ | (0u << TFOR)
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01008360#if BASH_FUNCTION
Denys Vlasenko888527c2016-10-02 16:54:17 +02008361 /* 22 */ | (0u << TFUNCTION)
Denys Vlasenko80729a42016-10-02 22:33:15 +02008362#endif
Denys Vlasenko888527c2016-10-02 16:54:17 +02008363 /* 23 */ | (0u << TIF)
8364 /* 24 */ | (0u << TIN)
8365 /* 25 */ | (1u << TTHEN)
8366 /* 26 */ | (0u << TUNTIL)
8367 /* 27 */ | (0u << TWHILE)
8368 /* 28 */ | (0u << TBEGIN)
8369 /* 29 */ | (1u << TEND)
8370 , /* thus far 29 bits used */
8371};
8372
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008373static const char *const tokname_array[] = {
Denys Vlasenko888527c2016-10-02 16:54:17 +02008374 "end of file",
8375 "newline",
8376 "redirection",
8377 "word",
8378 ";",
8379 "&",
8380 "&&",
8381 "||",
8382 "|",
8383 "(",
8384 ")",
8385 ";;",
8386 "`",
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008387#define KWDOFFSET 13
8388 /* the following are keywords */
Denys Vlasenko888527c2016-10-02 16:54:17 +02008389 "!",
8390 "case",
8391 "do",
8392 "done",
8393 "elif",
8394 "else",
8395 "esac",
8396 "fi",
8397 "for",
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01008398#if BASH_FUNCTION
Denys Vlasenko888527c2016-10-02 16:54:17 +02008399 "function",
Ron Yorston95ebcf72015-11-03 09:42:23 +00008400#endif
Denys Vlasenko888527c2016-10-02 16:54:17 +02008401 "if",
8402 "in",
8403 "then",
8404 "until",
8405 "while",
8406 "{",
8407 "}",
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008408};
8409
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008410/* Wrapper around strcmp for qsort/bsearch/... */
8411static int
8412pstrcmp(const void *a, const void *b)
8413{
Denys Vlasenko888527c2016-10-02 16:54:17 +02008414 return strcmp((char*)a, *(char**)b);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008415}
8416
8417static const char *const *
8418findkwd(const char *s)
8419{
8420 return bsearch(s, tokname_array + KWDOFFSET,
Denis Vlasenko80b8b392007-06-25 10:55:35 +00008421 ARRAY_SIZE(tokname_array) - KWDOFFSET,
8422 sizeof(tokname_array[0]), pstrcmp);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008423}
8424
8425/*
8426 * Locate and print what a word is...
8427 */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008428static int
Ron Yorston3f221112015-08-03 13:47:33 +01008429describe_command(char *command, const char *path, int describe_command_verbose)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008430{
8431 struct cmdentry entry;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008432#if ENABLE_ASH_ALIAS
8433 const struct alias *ap;
8434#endif
Ron Yorston3f221112015-08-03 13:47:33 +01008435
8436 path = path ? path : pathval();
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008437
8438 if (describe_command_verbose) {
8439 out1str(command);
8440 }
8441
8442 /* First look at the keywords */
8443 if (findkwd(command)) {
8444 out1str(describe_command_verbose ? " is a shell keyword" : command);
8445 goto out;
8446 }
8447
8448#if ENABLE_ASH_ALIAS
8449 /* Then look at the aliases */
8450 ap = lookupalias(command, 0);
8451 if (ap != NULL) {
Denis Vlasenko46846e22007-05-20 13:08:31 +00008452 if (!describe_command_verbose) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008453 out1str("alias ");
8454 printalias(ap);
8455 return 0;
8456 }
Denis Vlasenko46846e22007-05-20 13:08:31 +00008457 out1fmt(" is an alias for %s", ap->val);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008458 goto out;
8459 }
8460#endif
Youfu Zhang6683d1c2017-05-26 15:31:29 +08008461 /* Brute force */
8462 find_command(command, &entry, DO_ABS, path);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008463
8464 switch (entry.cmdtype) {
8465 case CMDNORMAL: {
8466 int j = entry.u.index;
8467 char *p;
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00008468 if (j < 0) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008469 p = command;
8470 } else {
8471 do {
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02008472 p = path_advance(&path, command);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008473 stunalloc(p);
8474 } while (--j >= 0);
8475 }
8476 if (describe_command_verbose) {
Youfu Zhang6683d1c2017-05-26 15:31:29 +08008477 out1fmt(" is %s", p);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008478 } else {
8479 out1str(p);
8480 }
8481 break;
8482 }
8483
8484 case CMDFUNCTION:
8485 if (describe_command_verbose) {
8486 out1str(" is a shell function");
8487 } else {
8488 out1str(command);
8489 }
8490 break;
8491
8492 case CMDBUILTIN:
8493 if (describe_command_verbose) {
8494 out1fmt(" is a %sshell builtin",
8495 IS_BUILTIN_SPECIAL(entry.u.cmd) ?
8496 "special " : nullstr
8497 );
8498 } else {
8499 out1str(command);
8500 }
8501 break;
8502
8503 default:
8504 if (describe_command_verbose) {
8505 out1str(": not found\n");
8506 }
8507 return 127;
8508 }
8509 out:
Denys Vlasenko285ad152009-12-04 23:02:27 +01008510 out1str("\n");
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008511 return 0;
8512}
8513
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02008514static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00008515typecmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008516{
Denis Vlasenko46846e22007-05-20 13:08:31 +00008517 int i = 1;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008518 int err = 0;
Denis Vlasenko46846e22007-05-20 13:08:31 +00008519 int verbose = 1;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008520
Denis Vlasenko46846e22007-05-20 13:08:31 +00008521 /* type -p ... ? (we don't bother checking for 'p') */
Denis Vlasenko1fc62382007-06-25 22:55:34 +00008522 if (argv[1] && argv[1][0] == '-') {
Denis Vlasenko46846e22007-05-20 13:08:31 +00008523 i++;
8524 verbose = 0;
8525 }
Denis Vlasenko68404f12008-03-17 09:00:54 +00008526 while (argv[i]) {
Ron Yorston3f221112015-08-03 13:47:33 +01008527 err |= describe_command(argv[i++], NULL, verbose);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008528 }
8529 return err;
8530}
8531
8532#if ENABLE_ASH_CMDCMD
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008533/* Is it "command [-p] PROG ARGS" bltin, no other opts? Return ptr to "PROG" if yes */
8534static char **
8535parse_command_args(char **argv, const char **path)
8536{
8537 char *cp, c;
8538
8539 for (;;) {
8540 cp = *++argv;
8541 if (!cp)
8542 return NULL;
8543 if (*cp++ != '-')
8544 break;
8545 c = *cp++;
8546 if (!c)
8547 break;
8548 if (c == '-' && !*cp) {
8549 if (!*++argv)
8550 return NULL;
8551 break;
8552 }
8553 do {
8554 switch (c) {
8555 case 'p':
8556 *path = bb_default_path;
8557 break;
8558 default:
8559 /* run 'typecmd' for other options */
8560 return NULL;
8561 }
8562 c = *cp++;
8563 } while (c);
8564 }
8565 return argv;
8566}
8567
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02008568static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00008569commandcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008570{
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008571 char *cmd;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008572 int c;
8573 enum {
8574 VERIFY_BRIEF = 1,
8575 VERIFY_VERBOSE = 2,
8576 } verify = 0;
Ron Yorston3f221112015-08-03 13:47:33 +01008577 const char *path = NULL;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008578
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008579 /* "command [-p] PROG ARGS" (that is, without -V or -v)
8580 * never reaches this function.
8581 */
8582
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008583 while ((c = nextopt("pvV")) != '\0')
8584 if (c == 'V')
8585 verify |= VERIFY_VERBOSE;
8586 else if (c == 'v')
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008587 /*verify |= VERIFY_BRIEF*/;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008588#if DEBUG
8589 else if (c != 'p')
8590 abort();
8591#endif
Ron Yorston3f221112015-08-03 13:47:33 +01008592 else
8593 path = bb_default_path;
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008594
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00008595 /* Mimic bash: just "command -v" doesn't complain, it's a nop */
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008596 cmd = *argptr;
8597 if (/*verify && */ cmd)
8598 return describe_command(cmd, path, verify /* - VERIFY_BRIEF*/);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008599
8600 return 0;
8601}
8602#endif
8603
8604
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008605/*static int funcblocksize; // size of structures in function */
8606/*static int funcstringsize; // size of strings in node */
Denis Vlasenko340299a2008-11-21 10:36:36 +00008607static void *funcblock; /* block to allocate function from */
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008608static char *funcstring_end; /* end of block to allocate strings from */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008609
Denys Vlasenko3e134eb2016-04-22 18:09:21 +02008610static const uint8_t nodesize[N_NUMBER] ALIGN1 = {
Denis Vlasenko340299a2008-11-21 10:36:36 +00008611 [NCMD ] = SHELL_ALIGN(sizeof(struct ncmd)),
8612 [NPIPE ] = SHELL_ALIGN(sizeof(struct npipe)),
8613 [NREDIR ] = SHELL_ALIGN(sizeof(struct nredir)),
8614 [NBACKGND ] = SHELL_ALIGN(sizeof(struct nredir)),
8615 [NSUBSHELL] = SHELL_ALIGN(sizeof(struct nredir)),
8616 [NAND ] = SHELL_ALIGN(sizeof(struct nbinary)),
8617 [NOR ] = SHELL_ALIGN(sizeof(struct nbinary)),
8618 [NSEMI ] = SHELL_ALIGN(sizeof(struct nbinary)),
8619 [NIF ] = SHELL_ALIGN(sizeof(struct nif)),
8620 [NWHILE ] = SHELL_ALIGN(sizeof(struct nbinary)),
8621 [NUNTIL ] = SHELL_ALIGN(sizeof(struct nbinary)),
8622 [NFOR ] = SHELL_ALIGN(sizeof(struct nfor)),
8623 [NCASE ] = SHELL_ALIGN(sizeof(struct ncase)),
8624 [NCLIST ] = SHELL_ALIGN(sizeof(struct nclist)),
8625 [NDEFUN ] = SHELL_ALIGN(sizeof(struct narg)),
8626 [NARG ] = SHELL_ALIGN(sizeof(struct narg)),
8627 [NTO ] = SHELL_ALIGN(sizeof(struct nfile)),
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01008628#if BASH_REDIR_OUTPUT
Denis Vlasenko340299a2008-11-21 10:36:36 +00008629 [NTO2 ] = SHELL_ALIGN(sizeof(struct nfile)),
Denis Vlasenkocc5feab2008-11-22 01:32:40 +00008630#endif
Denis Vlasenko340299a2008-11-21 10:36:36 +00008631 [NCLOBBER ] = SHELL_ALIGN(sizeof(struct nfile)),
8632 [NFROM ] = SHELL_ALIGN(sizeof(struct nfile)),
8633 [NFROMTO ] = SHELL_ALIGN(sizeof(struct nfile)),
8634 [NAPPEND ] = SHELL_ALIGN(sizeof(struct nfile)),
8635 [NTOFD ] = SHELL_ALIGN(sizeof(struct ndup)),
8636 [NFROMFD ] = SHELL_ALIGN(sizeof(struct ndup)),
8637 [NHERE ] = SHELL_ALIGN(sizeof(struct nhere)),
8638 [NXHERE ] = SHELL_ALIGN(sizeof(struct nhere)),
8639 [NNOT ] = SHELL_ALIGN(sizeof(struct nnot)),
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008640};
8641
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008642static int calcsize(int funcblocksize, union node *n);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008643
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008644static int
8645sizenodelist(int funcblocksize, struct nodelist *lp)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008646{
8647 while (lp) {
8648 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008649 funcblocksize = calcsize(funcblocksize, lp->n);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008650 lp = lp->next;
8651 }
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008652 return funcblocksize;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008653}
8654
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008655static int
8656calcsize(int funcblocksize, union node *n)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008657{
8658 if (n == NULL)
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008659 return funcblocksize;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008660 funcblocksize += nodesize[n->type];
8661 switch (n->type) {
8662 case NCMD:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008663 funcblocksize = calcsize(funcblocksize, n->ncmd.redirect);
8664 funcblocksize = calcsize(funcblocksize, n->ncmd.args);
8665 funcblocksize = calcsize(funcblocksize, n->ncmd.assign);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008666 break;
8667 case NPIPE:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008668 funcblocksize = sizenodelist(funcblocksize, n->npipe.cmdlist);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008669 break;
8670 case NREDIR:
8671 case NBACKGND:
8672 case NSUBSHELL:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008673 funcblocksize = calcsize(funcblocksize, n->nredir.redirect);
8674 funcblocksize = calcsize(funcblocksize, n->nredir.n);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008675 break;
8676 case NAND:
8677 case NOR:
8678 case NSEMI:
8679 case NWHILE:
8680 case NUNTIL:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008681 funcblocksize = calcsize(funcblocksize, n->nbinary.ch2);
8682 funcblocksize = calcsize(funcblocksize, n->nbinary.ch1);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008683 break;
8684 case NIF:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008685 funcblocksize = calcsize(funcblocksize, n->nif.elsepart);
8686 funcblocksize = calcsize(funcblocksize, n->nif.ifpart);
8687 funcblocksize = calcsize(funcblocksize, n->nif.test);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008688 break;
8689 case NFOR:
Denys Vlasenko561639a2016-10-07 04:28:33 +02008690 funcblocksize += SHELL_ALIGN(strlen(n->nfor.var) + 1); /* was funcstringsize += ... */
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008691 funcblocksize = calcsize(funcblocksize, n->nfor.body);
8692 funcblocksize = calcsize(funcblocksize, n->nfor.args);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008693 break;
8694 case NCASE:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008695 funcblocksize = calcsize(funcblocksize, n->ncase.cases);
8696 funcblocksize = calcsize(funcblocksize, n->ncase.expr);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008697 break;
8698 case NCLIST:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008699 funcblocksize = calcsize(funcblocksize, n->nclist.body);
8700 funcblocksize = calcsize(funcblocksize, n->nclist.pattern);
8701 funcblocksize = calcsize(funcblocksize, n->nclist.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008702 break;
8703 case NDEFUN:
Denys Vlasenko675d24a2018-01-27 22:02:05 +01008704 funcblocksize = calcsize(funcblocksize, n->ndefun.body);
8705 funcblocksize += SHELL_ALIGN(strlen(n->ndefun.text) + 1);
8706 break;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008707 case NARG:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008708 funcblocksize = sizenodelist(funcblocksize, n->narg.backquote);
Denys Vlasenko561639a2016-10-07 04:28:33 +02008709 funcblocksize += SHELL_ALIGN(strlen(n->narg.text) + 1); /* was funcstringsize += ... */
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008710 funcblocksize = calcsize(funcblocksize, n->narg.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008711 break;
8712 case NTO:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01008713#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00008714 case NTO2:
8715#endif
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008716 case NCLOBBER:
8717 case NFROM:
8718 case NFROMTO:
8719 case NAPPEND:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008720 funcblocksize = calcsize(funcblocksize, n->nfile.fname);
8721 funcblocksize = calcsize(funcblocksize, n->nfile.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008722 break;
8723 case NTOFD:
8724 case NFROMFD:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008725 funcblocksize = calcsize(funcblocksize, n->ndup.vname);
8726 funcblocksize = calcsize(funcblocksize, n->ndup.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008727 break;
8728 case NHERE:
8729 case NXHERE:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008730 funcblocksize = calcsize(funcblocksize, n->nhere.doc);
8731 funcblocksize = calcsize(funcblocksize, n->nhere.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008732 break;
8733 case NNOT:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008734 funcblocksize = calcsize(funcblocksize, n->nnot.com);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008735 break;
8736 };
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008737 return funcblocksize;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008738}
8739
8740static char *
8741nodeckstrdup(char *s)
8742{
Denys Vlasenko561639a2016-10-07 04:28:33 +02008743 funcstring_end -= SHELL_ALIGN(strlen(s) + 1);
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008744 return strcpy(funcstring_end, s);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008745}
8746
8747static union node *copynode(union node *);
8748
8749static struct nodelist *
8750copynodelist(struct nodelist *lp)
8751{
8752 struct nodelist *start;
8753 struct nodelist **lpp;
8754
8755 lpp = &start;
8756 while (lp) {
8757 *lpp = funcblock;
8758 funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist));
8759 (*lpp)->n = copynode(lp->n);
8760 lp = lp->next;
8761 lpp = &(*lpp)->next;
8762 }
8763 *lpp = NULL;
8764 return start;
8765}
8766
8767static union node *
8768copynode(union node *n)
8769{
8770 union node *new;
8771
8772 if (n == NULL)
8773 return NULL;
8774 new = funcblock;
8775 funcblock = (char *) funcblock + nodesize[n->type];
8776
8777 switch (n->type) {
8778 case NCMD:
8779 new->ncmd.redirect = copynode(n->ncmd.redirect);
8780 new->ncmd.args = copynode(n->ncmd.args);
8781 new->ncmd.assign = copynode(n->ncmd.assign);
Denys Vlasenko675d24a2018-01-27 22:02:05 +01008782 new->ncmd.linno = n->ncmd.linno;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008783 break;
8784 case NPIPE:
8785 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00008786 new->npipe.pipe_backgnd = n->npipe.pipe_backgnd;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008787 break;
8788 case NREDIR:
8789 case NBACKGND:
8790 case NSUBSHELL:
8791 new->nredir.redirect = copynode(n->nredir.redirect);
8792 new->nredir.n = copynode(n->nredir.n);
Denys Vlasenko675d24a2018-01-27 22:02:05 +01008793 new->nredir.linno = n->nredir.linno;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008794 break;
8795 case NAND:
8796 case NOR:
8797 case NSEMI:
8798 case NWHILE:
8799 case NUNTIL:
8800 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8801 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8802 break;
8803 case NIF:
8804 new->nif.elsepart = copynode(n->nif.elsepart);
8805 new->nif.ifpart = copynode(n->nif.ifpart);
8806 new->nif.test = copynode(n->nif.test);
8807 break;
8808 case NFOR:
8809 new->nfor.var = nodeckstrdup(n->nfor.var);
8810 new->nfor.body = copynode(n->nfor.body);
8811 new->nfor.args = copynode(n->nfor.args);
Denys Vlasenko675d24a2018-01-27 22:02:05 +01008812 new->nfor.linno = n->nfor.linno;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008813 break;
8814 case NCASE:
8815 new->ncase.cases = copynode(n->ncase.cases);
8816 new->ncase.expr = copynode(n->ncase.expr);
Denys Vlasenko675d24a2018-01-27 22:02:05 +01008817 new->ncase.linno = n->ncase.linno;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008818 break;
8819 case NCLIST:
8820 new->nclist.body = copynode(n->nclist.body);
8821 new->nclist.pattern = copynode(n->nclist.pattern);
8822 new->nclist.next = copynode(n->nclist.next);
8823 break;
8824 case NDEFUN:
Denys Vlasenko675d24a2018-01-27 22:02:05 +01008825 new->ndefun.body = copynode(n->ndefun.body);
8826 new->ndefun.text = nodeckstrdup(n->ndefun.text);
8827 new->ndefun.linno = n->ndefun.linno;
8828 break;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008829 case NARG:
8830 new->narg.backquote = copynodelist(n->narg.backquote);
8831 new->narg.text = nodeckstrdup(n->narg.text);
8832 new->narg.next = copynode(n->narg.next);
8833 break;
8834 case NTO:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01008835#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00008836 case NTO2:
8837#endif
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008838 case NCLOBBER:
8839 case NFROM:
8840 case NFROMTO:
8841 case NAPPEND:
8842 new->nfile.fname = copynode(n->nfile.fname);
8843 new->nfile.fd = n->nfile.fd;
8844 new->nfile.next = copynode(n->nfile.next);
8845 break;
8846 case NTOFD:
8847 case NFROMFD:
8848 new->ndup.vname = copynode(n->ndup.vname);
8849 new->ndup.dupfd = n->ndup.dupfd;
8850 new->ndup.fd = n->ndup.fd;
8851 new->ndup.next = copynode(n->ndup.next);
8852 break;
8853 case NHERE:
8854 case NXHERE:
8855 new->nhere.doc = copynode(n->nhere.doc);
8856 new->nhere.fd = n->nhere.fd;
8857 new->nhere.next = copynode(n->nhere.next);
8858 break;
8859 case NNOT:
8860 new->nnot.com = copynode(n->nnot.com);
8861 break;
8862 };
8863 new->type = n->type;
8864 return new;
8865}
8866
8867/*
8868 * Make a copy of a parse tree.
8869 */
8870static struct funcnode *
8871copyfunc(union node *n)
8872{
8873 struct funcnode *f;
8874 size_t blocksize;
8875
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008876 /*funcstringsize = 0;*/
8877 blocksize = offsetof(struct funcnode, n) + calcsize(0, n);
8878 f = ckzalloc(blocksize /* + funcstringsize */);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008879 funcblock = (char *) f + offsetof(struct funcnode, n);
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008880 funcstring_end = (char *) f + blocksize;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008881 copynode(n);
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008882 /* f->count = 0; - ckzalloc did it */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008883 return f;
8884}
8885
8886/*
8887 * Define a shell function.
8888 */
8889static void
Denys Vlasenko7aec8682016-10-25 20:26:02 +02008890defun(union node *func)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008891{
8892 struct cmdentry entry;
8893
8894 INT_OFF;
8895 entry.cmdtype = CMDFUNCTION;
8896 entry.u.func = copyfunc(func);
Denys Vlasenko675d24a2018-01-27 22:02:05 +01008897 addcmdentry(func->ndefun.text, &entry);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008898 INT_ON;
8899}
8900
Denis Vlasenko4b875702009-03-19 13:30:04 +00008901/* Reasons for skipping commands (see comment on breakcmd routine) */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008902#define SKIPBREAK (1 << 0)
8903#define SKIPCONT (1 << 1)
8904#define SKIPFUNC (1 << 2)
Denis Vlasenko4b875702009-03-19 13:30:04 +00008905static smallint evalskip; /* set to SKIPxxx if we are skipping commands */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008906static int skipcount; /* number of levels to skip */
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +00008907static int loopnest; /* current loop nesting level */
Denys Vlasenko675d24a2018-01-27 22:02:05 +01008908static int funcline; /* starting line number of current function, or 0 if not in a function */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008909
Denis Vlasenko4b875702009-03-19 13:30:04 +00008910/* Forward decl way out to parsing code - dotrap needs it */
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02008911static int evalstring(char *s, int flags);
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008912
Denis Vlasenko4b875702009-03-19 13:30:04 +00008913/* Called to execute a trap.
8914 * Single callsite - at the end of evaltree().
Denys Vlasenkob563f622010-09-25 17:15:13 +02008915 * If we return non-zero, evaltree raises EXEXIT exception.
Denis Vlasenko4b875702009-03-19 13:30:04 +00008916 *
8917 * Perhaps we should avoid entering new trap handlers
8918 * while we are executing a trap handler. [is it a TODO?]
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008919 */
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008920static void
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008921dotrap(void)
8922{
Denis Vlasenko4b875702009-03-19 13:30:04 +00008923 uint8_t *g;
8924 int sig;
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008925 uint8_t last_status;
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008926
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008927 if (!pending_sig)
8928 return;
8929
8930 last_status = exitstatus;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02008931 pending_sig = 0;
Denys Vlasenkode892052016-10-02 01:49:13 +02008932 barrier();
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008933
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008934 TRACE(("dotrap entered\n"));
Denis Vlasenko4b875702009-03-19 13:30:04 +00008935 for (sig = 1, g = gotsig; sig < NSIG; sig++, g++) {
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008936 char *p;
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008937
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008938 if (!*g)
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008939 continue;
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008940
8941 if (evalskip) {
8942 pending_sig = sig;
8943 break;
8944 }
8945
8946 p = trap[sig];
Denis Vlasenko4b875702009-03-19 13:30:04 +00008947 /* non-trapped SIGINT is handled separately by raise_interrupt,
8948 * don't upset it by resetting gotsig[SIGINT-1] */
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008949 if (sig == SIGINT && !p)
Denis Vlasenko4b875702009-03-19 13:30:04 +00008950 continue;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008951
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008952 TRACE(("sig %d is active, will run handler '%s'\n", sig, p));
Denis Vlasenko4b875702009-03-19 13:30:04 +00008953 *g = 0;
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008954 if (!p)
Denis Vlasenko4b875702009-03-19 13:30:04 +00008955 continue;
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008956 evalstring(p, 0);
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008957 }
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008958 exitstatus = last_status;
8959 TRACE(("dotrap returns\n"));
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008960}
8961
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00008962/* forward declarations - evaluation is fairly recursive business... */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008963static int evalloop(union node *, int);
8964static int evalfor(union node *, int);
8965static int evalcase(union node *, int);
8966static int evalsubshell(union node *, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008967static void expredir(union node *);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008968static int evalpipe(union node *, int);
8969static int evalcommand(union node *, int);
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02008970static int evalbltin(const struct builtincmd *, int, char **, int);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008971static void prehash(union node *);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008972
Eric Andersen62483552001-07-10 06:09:16 +00008973/*
Eric Andersenc470f442003-07-28 09:56:35 +00008974 * Evaluate a parse tree. The value is left in the global variable
8975 * exitstatus.
Eric Andersen62483552001-07-10 06:09:16 +00008976 */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008977static int
Eric Andersenc470f442003-07-28 09:56:35 +00008978evaltree(union node *n, int flags)
Eric Andersen62483552001-07-10 06:09:16 +00008979{
Eric Andersenc470f442003-07-28 09:56:35 +00008980 int checkexit = 0;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008981 int (*evalfn)(union node *, int);
8982 int status = 0;
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008983
Eric Andersenc470f442003-07-28 09:56:35 +00008984 if (n == NULL) {
8985 TRACE(("evaltree(NULL) called\n"));
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02008986 goto out;
Eric Andersen62483552001-07-10 06:09:16 +00008987 }
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008988 TRACE(("evaltree(%p: %d, %d) called\n", n, n->type, flags));
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008989
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008990 dotrap();
8991
Eric Andersenc470f442003-07-28 09:56:35 +00008992 switch (n->type) {
8993 default:
Denis Vlasenkoa7189f02006-11-17 20:29:00 +00008994#if DEBUG
Eric Andersenc470f442003-07-28 09:56:35 +00008995 out1fmt("Node type = %d\n", n->type);
Denys Vlasenko8131eea2009-11-02 14:19:51 +01008996 fflush_all();
Eric Andersenc470f442003-07-28 09:56:35 +00008997 break;
8998#endif
8999 case NNOT:
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009000 status = !evaltree(n->nnot.com, EV_TESTED);
Eric Andersenc470f442003-07-28 09:56:35 +00009001 goto setstatus;
9002 case NREDIR:
Denys Vlasenko675d24a2018-01-27 22:02:05 +01009003 errlinno = lineno = n->nredir.linno;
9004 if (funcline)
9005 lineno -= funcline - 1;
Eric Andersenc470f442003-07-28 09:56:35 +00009006 expredir(n->nredir.redirect);
Denys Vlasenko1c79aeb2017-07-29 22:51:52 +02009007 pushredir(n->nredir.redirect);
Eric Andersenc470f442003-07-28 09:56:35 +00009008 status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
9009 if (!status) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009010 status = evaltree(n->nredir.n, flags & EV_TESTED);
Eric Andersenc470f442003-07-28 09:56:35 +00009011 }
Denys Vlasenkoeaf94362016-10-25 21:46:03 +02009012 if (n->nredir.redirect)
Denys Vlasenko035486c2017-07-31 04:09:19 +02009013 popredir(/*drop:*/ 0);
Eric Andersenc470f442003-07-28 09:56:35 +00009014 goto setstatus;
9015 case NCMD:
9016 evalfn = evalcommand;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009017 checkexit:
Eric Andersenc470f442003-07-28 09:56:35 +00009018 if (eflag && !(flags & EV_TESTED))
9019 checkexit = ~0;
9020 goto calleval;
9021 case NFOR:
9022 evalfn = evalfor;
9023 goto calleval;
9024 case NWHILE:
9025 case NUNTIL:
9026 evalfn = evalloop;
9027 goto calleval;
9028 case NSUBSHELL:
9029 case NBACKGND:
9030 evalfn = evalsubshell;
Denys Vlasenkocf98b0c2016-10-25 18:19:39 +02009031 goto checkexit;
Eric Andersenc470f442003-07-28 09:56:35 +00009032 case NPIPE:
9033 evalfn = evalpipe;
9034 goto checkexit;
9035 case NCASE:
9036 evalfn = evalcase;
9037 goto calleval;
9038 case NAND:
9039 case NOR:
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00009040 case NSEMI: {
9041
Eric Andersenc470f442003-07-28 09:56:35 +00009042#if NAND + 1 != NOR
9043#error NAND + 1 != NOR
9044#endif
9045#if NOR + 1 != NSEMI
9046#error NOR + 1 != NSEMI
9047#endif
Denis Vlasenko87d5fd92008-07-26 13:48:35 +00009048 unsigned is_or = n->type - NAND;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009049 status = evaltree(
Eric Andersenc470f442003-07-28 09:56:35 +00009050 n->nbinary.ch1,
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00009051 (flags | ((is_or >> 1) - 1)) & EV_TESTED
Eric Andersenc470f442003-07-28 09:56:35 +00009052 );
Denys Vlasenkobc1a0082016-10-02 15:31:33 +02009053 if ((!status) == is_or || evalskip)
Eric Andersenc470f442003-07-28 09:56:35 +00009054 break;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009055 n = n->nbinary.ch2;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009056 evaln:
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009057 evalfn = evaltree;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009058 calleval:
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009059 status = evalfn(n, flags);
9060 goto setstatus;
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00009061 }
Eric Andersenc470f442003-07-28 09:56:35 +00009062 case NIF:
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009063 status = evaltree(n->nif.test, EV_TESTED);
Eric Andersenc470f442003-07-28 09:56:35 +00009064 if (evalskip)
9065 break;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009066 if (!status) {
Eric Andersenc470f442003-07-28 09:56:35 +00009067 n = n->nif.ifpart;
9068 goto evaln;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00009069 }
9070 if (n->nif.elsepart) {
Eric Andersenc470f442003-07-28 09:56:35 +00009071 n = n->nif.elsepart;
9072 goto evaln;
9073 }
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009074 status = 0;
9075 goto setstatus;
Eric Andersenc470f442003-07-28 09:56:35 +00009076 case NDEFUN:
Denys Vlasenko7aec8682016-10-25 20:26:02 +02009077 defun(n);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009078 /* Not necessary. To test it:
9079 * "false; f() { qwerty; }; echo $?" should print 0.
9080 */
9081 /* status = 0; */
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009082 setstatus:
Eric Andersenc470f442003-07-28 09:56:35 +00009083 exitstatus = status;
9084 break;
9085 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009086 out:
Denys Vlasenkob563f622010-09-25 17:15:13 +02009087 /* Order of checks below is important:
9088 * signal handlers trigger before exit caused by "set -e".
9089 */
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02009090 dotrap();
9091
9092 if (checkexit & status)
Denis Vlasenkob012b102007-02-19 22:43:01 +00009093 raise_exception(EXEXIT);
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02009094 if (flags & EV_EXIT)
9095 raise_exception(EXEXIT);
Denis Vlasenko653d8e72009-03-19 21:59:35 +00009096
Denis Vlasenko653d8e72009-03-19 21:59:35 +00009097 TRACE(("leaving evaltree (no interrupts)\n"));
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009098 return exitstatus;
Eric Andersen62483552001-07-10 06:09:16 +00009099}
9100
Denys Vlasenko37dc08b2016-10-02 04:38:07 +02009101static int
9102skiploop(void)
Denys Vlasenko35ec8182016-10-01 19:56:52 +02009103{
9104 int skip = evalskip;
9105
9106 switch (skip) {
9107 case 0:
9108 break;
9109 case SKIPBREAK:
9110 case SKIPCONT:
9111 if (--skipcount <= 0) {
9112 evalskip = 0;
9113 break;
9114 }
9115 skip = SKIPBREAK;
9116 break;
9117 }
9118 return skip;
9119}
9120
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009121static int
Eric Andersenc470f442003-07-28 09:56:35 +00009122evalloop(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00009123{
Denys Vlasenko35ec8182016-10-01 19:56:52 +02009124 int skip;
Eric Andersencb57d552001-06-28 07:25:16 +00009125 int status;
9126
9127 loopnest++;
9128 status = 0;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009129 flags &= EV_TESTED;
Denys Vlasenko35ec8182016-10-01 19:56:52 +02009130 do {
Eric Andersenc470f442003-07-28 09:56:35 +00009131 int i;
9132
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009133 i = evaltree(n->nbinary.ch1, EV_TESTED);
Denys Vlasenko35ec8182016-10-01 19:56:52 +02009134 skip = skiploop();
9135 if (skip == SKIPFUNC)
9136 status = i;
9137 if (skip)
9138 continue;
Eric Andersenc470f442003-07-28 09:56:35 +00009139 if (n->type != NWHILE)
9140 i = !i;
9141 if (i != 0)
9142 break;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009143 status = evaltree(n->nbinary.ch2, flags);
Denys Vlasenko35ec8182016-10-01 19:56:52 +02009144 skip = skiploop();
9145 } while (!(skip & ~SKIPCONT));
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009146 loopnest--;
9147
9148 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00009149}
9150
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009151static int
Eric Andersenc470f442003-07-28 09:56:35 +00009152evalfor(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00009153{
9154 struct arglist arglist;
9155 union node *argp;
9156 struct strlist *sp;
9157 struct stackmark smark;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009158 int status = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00009159
Denys Vlasenko675d24a2018-01-27 22:02:05 +01009160 errlinno = lineno = n->ncase.linno;
9161 if (funcline)
9162 lineno -= funcline - 1;
9163
Eric Andersencb57d552001-06-28 07:25:16 +00009164 setstackmark(&smark);
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00009165 arglist.list = NULL;
Eric Andersencb57d552001-06-28 07:25:16 +00009166 arglist.lastp = &arglist.list;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009167 for (argp = n->nfor.args; argp; argp = argp->narg.next) {
Ron Yorston549deab2015-05-18 09:57:51 +02009168 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
Eric Andersencb57d552001-06-28 07:25:16 +00009169 }
9170 *arglist.lastp = NULL;
9171
Eric Andersencb57d552001-06-28 07:25:16 +00009172 loopnest++;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009173 flags &= EV_TESTED;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009174 for (sp = arglist.list; sp; sp = sp->next) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009175 setvar0(n->nfor.var, sp->text);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009176 status = evaltree(n->nfor.body, flags);
Denys Vlasenko35ec8182016-10-01 19:56:52 +02009177 if (skiploop() & ~SKIPCONT)
Eric Andersencb57d552001-06-28 07:25:16 +00009178 break;
Eric Andersencb57d552001-06-28 07:25:16 +00009179 }
9180 loopnest--;
Eric Andersencb57d552001-06-28 07:25:16 +00009181 popstackmark(&smark);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009182
9183 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00009184}
9185
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009186static int
Eric Andersenc470f442003-07-28 09:56:35 +00009187evalcase(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00009188{
9189 union node *cp;
9190 union node *patp;
9191 struct arglist arglist;
9192 struct stackmark smark;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009193 int status = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00009194
Denys Vlasenko675d24a2018-01-27 22:02:05 +01009195 errlinno = lineno = n->ncase.linno;
9196 if (funcline)
9197 lineno -= funcline - 1;
9198
Eric Andersencb57d552001-06-28 07:25:16 +00009199 setstackmark(&smark);
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00009200 arglist.list = NULL;
Eric Andersencb57d552001-06-28 07:25:16 +00009201 arglist.lastp = &arglist.list;
Eric Andersencb57d552001-06-28 07:25:16 +00009202 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009203 for (cp = n->ncase.cases; cp && evalskip == 0; cp = cp->nclist.next) {
9204 for (patp = cp->nclist.pattern; patp; patp = patp->narg.next) {
Eric Andersencb57d552001-06-28 07:25:16 +00009205 if (casematch(patp, arglist.list->text)) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009206 /* Ensure body is non-empty as otherwise
9207 * EV_EXIT may prevent us from setting the
9208 * exit status.
9209 */
9210 if (evalskip == 0 && cp->nclist.body) {
9211 status = evaltree(cp->nclist.body, flags);
Eric Andersencb57d552001-06-28 07:25:16 +00009212 }
9213 goto out;
9214 }
9215 }
9216 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009217 out:
Eric Andersencb57d552001-06-28 07:25:16 +00009218 popstackmark(&smark);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009219
9220 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00009221}
9222
Eric Andersenc470f442003-07-28 09:56:35 +00009223/*
9224 * Kick off a subshell to evaluate a tree.
9225 */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009226static int
Eric Andersenc470f442003-07-28 09:56:35 +00009227evalsubshell(union node *n, int flags)
9228{
9229 struct job *jp;
Denys Vlasenko098b7132017-01-11 19:59:03 +01009230 int backgnd = (n->type == NBACKGND); /* FORK_BG(1) if yes, else FORK_FG(0) */
Eric Andersenc470f442003-07-28 09:56:35 +00009231 int status;
9232
Denys Vlasenko675d24a2018-01-27 22:02:05 +01009233 errlinno = lineno = n->nredir.linno;
9234 if (funcline)
9235 lineno -= funcline - 1;
9236
Eric Andersenc470f442003-07-28 09:56:35 +00009237 expredir(n->nredir.redirect);
Denys Vlasenko238bf182010-05-18 15:49:07 +02009238 if (!backgnd && (flags & EV_EXIT) && !may_have_traps)
Eric Andersenc470f442003-07-28 09:56:35 +00009239 goto nofork;
Denis Vlasenkob012b102007-02-19 22:43:01 +00009240 INT_OFF;
Denys Vlasenko098b7132017-01-11 19:59:03 +01009241 if (backgnd == FORK_FG)
9242 get_tty_state();
Denis Vlasenko68404f12008-03-17 09:00:54 +00009243 jp = makejob(/*n,*/ 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009244 if (forkshell(jp, n, backgnd) == 0) {
Denys Vlasenko238bf182010-05-18 15:49:07 +02009245 /* child */
Denis Vlasenkob012b102007-02-19 22:43:01 +00009246 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +00009247 flags |= EV_EXIT;
9248 if (backgnd)
Denys Vlasenko238bf182010-05-18 15:49:07 +02009249 flags &= ~EV_TESTED;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00009250 nofork:
Eric Andersenc470f442003-07-28 09:56:35 +00009251 redirect(n->nredir.redirect, 0);
9252 evaltreenr(n->nredir.n, flags);
9253 /* never returns */
9254 }
Denys Vlasenko70392332016-10-27 02:31:55 +02009255 /* parent */
Eric Andersenc470f442003-07-28 09:56:35 +00009256 status = 0;
Denys Vlasenko098b7132017-01-11 19:59:03 +01009257 if (backgnd == FORK_FG)
Eric Andersenc470f442003-07-28 09:56:35 +00009258 status = waitforjob(jp);
Denis Vlasenkob012b102007-02-19 22:43:01 +00009259 INT_ON;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009260 return status;
Eric Andersenc470f442003-07-28 09:56:35 +00009261}
9262
Eric Andersenc470f442003-07-28 09:56:35 +00009263/*
9264 * Compute the names of the files in a redirection list.
9265 */
Denis Vlasenko99eb8502007-02-23 21:09:49 +00009266static void fixredir(union node *, const char *, int);
Eric Andersenc470f442003-07-28 09:56:35 +00009267static void
9268expredir(union node *n)
9269{
9270 union node *redir;
9271
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009272 for (redir = n; redir; redir = redir->nfile.next) {
Eric Andersenc470f442003-07-28 09:56:35 +00009273 struct arglist fn;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009274
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00009275 fn.list = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00009276 fn.lastp = &fn.list;
9277 switch (redir->type) {
9278 case NFROMTO:
9279 case NFROM:
9280 case NTO:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01009281#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00009282 case NTO2:
9283#endif
Eric Andersenc470f442003-07-28 09:56:35 +00009284 case NCLOBBER:
9285 case NAPPEND:
9286 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02009287 TRACE(("expredir expanded to '%s'\n", fn.list->text));
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01009288#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00009289 store_expfname:
9290#endif
Denys Vlasenko7c4b13e2013-01-17 13:02:27 +01009291#if 0
9292// By the design of stack allocator, the loop of this kind:
9293// while true; do while true; do break; done </dev/null; done
9294// will look like a memory leak: ash plans to free expfname's
9295// of "/dev/null" as soon as it finishes running the loop
9296// (in this case, never).
9297// This "fix" is wrong:
Jon Tollefson4ba6c5d2012-11-13 19:26:53 +01009298 if (redir->nfile.expfname)
9299 stunalloc(redir->nfile.expfname);
Denys Vlasenko7c4b13e2013-01-17 13:02:27 +01009300// It results in corrupted state of stacked allocations.
9301#endif
Eric Andersenc470f442003-07-28 09:56:35 +00009302 redir->nfile.expfname = fn.list->text;
9303 break;
9304 case NFROMFD:
Denis Vlasenko559691a2008-10-05 18:39:31 +00009305 case NTOFD: /* >& */
Eric Andersenc470f442003-07-28 09:56:35 +00009306 if (redir->ndup.vname) {
9307 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009308 if (fn.list == NULL)
Denis Vlasenkob012b102007-02-19 22:43:01 +00009309 ash_msg_and_raise_error("redir error");
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01009310#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00009311//FIXME: we used expandarg with different args!
9312 if (!isdigit_str9(fn.list->text)) {
9313 /* >&file, not >&fd */
9314 if (redir->nfile.fd != 1) /* 123>&file - BAD */
9315 ash_msg_and_raise_error("redir error");
9316 redir->type = NTO2;
9317 goto store_expfname;
9318 }
9319#endif
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009320 fixredir(redir, fn.list->text, 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009321 }
9322 break;
9323 }
9324 }
9325}
9326
Eric Andersencb57d552001-06-28 07:25:16 +00009327/*
Eric Andersencb57d552001-06-28 07:25:16 +00009328 * Evaluate a pipeline. All the processes in the pipeline are children
9329 * of the process creating the pipeline. (This differs from some versions
9330 * of the shell, which make the last process in a pipeline the parent
9331 * of all the rest.)
9332 */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009333static int
Eric Andersenc470f442003-07-28 09:56:35 +00009334evalpipe(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00009335{
9336 struct job *jp;
9337 struct nodelist *lp;
9338 int pipelen;
9339 int prevfd;
9340 int pip[2];
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009341 int status = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00009342
Eric Andersenc470f442003-07-28 09:56:35 +00009343 TRACE(("evalpipe(0x%lx) called\n", (long)n));
Eric Andersencb57d552001-06-28 07:25:16 +00009344 pipelen = 0;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009345 for (lp = n->npipe.cmdlist; lp; lp = lp->next)
Eric Andersencb57d552001-06-28 07:25:16 +00009346 pipelen++;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009347 flags |= EV_EXIT;
Denis Vlasenkob012b102007-02-19 22:43:01 +00009348 INT_OFF;
Denys Vlasenko098b7132017-01-11 19:59:03 +01009349 if (n->npipe.pipe_backgnd == 0)
9350 get_tty_state();
Denis Vlasenko68404f12008-03-17 09:00:54 +00009351 jp = makejob(/*n,*/ pipelen);
Eric Andersencb57d552001-06-28 07:25:16 +00009352 prevfd = -1;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009353 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009354 prehash(lp->n);
Eric Andersencb57d552001-06-28 07:25:16 +00009355 pip[1] = -1;
9356 if (lp->next) {
9357 if (pipe(pip) < 0) {
9358 close(prevfd);
Denys Vlasenko12ffefb2017-08-23 14:52:56 +02009359 ash_msg_and_raise_perror("can't create pipe");
Eric Andersencb57d552001-06-28 07:25:16 +00009360 }
9361 }
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00009362 if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) {
Denys Vlasenko70392332016-10-27 02:31:55 +02009363 /* child */
Denis Vlasenkob012b102007-02-19 22:43:01 +00009364 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +00009365 if (pip[1] >= 0) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009366 close(pip[0]);
Eric Andersencb57d552001-06-28 07:25:16 +00009367 }
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009368 if (prevfd > 0) {
9369 dup2(prevfd, 0);
9370 close(prevfd);
9371 }
9372 if (pip[1] > 1) {
9373 dup2(pip[1], 1);
9374 close(pip[1]);
9375 }
Eric Andersenc470f442003-07-28 09:56:35 +00009376 evaltreenr(lp->n, flags);
9377 /* never returns */
Eric Andersencb57d552001-06-28 07:25:16 +00009378 }
Denys Vlasenko70392332016-10-27 02:31:55 +02009379 /* parent */
Eric Andersencb57d552001-06-28 07:25:16 +00009380 if (prevfd >= 0)
9381 close(prevfd);
9382 prevfd = pip[0];
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +00009383 /* Don't want to trigger debugging */
9384 if (pip[1] != -1)
9385 close(pip[1]);
Eric Andersencb57d552001-06-28 07:25:16 +00009386 }
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00009387 if (n->npipe.pipe_backgnd == 0) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009388 status = waitforjob(jp);
9389 TRACE(("evalpipe: job done exit status %d\n", status));
Eric Andersencb57d552001-06-28 07:25:16 +00009390 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00009391 INT_ON;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009392
9393 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00009394}
9395
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009396/*
9397 * Controls whether the shell is interactive or not.
9398 */
9399static void
9400setinteractive(int on)
9401{
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009402 static smallint is_interactive;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009403
9404 if (++on == is_interactive)
9405 return;
9406 is_interactive = on;
9407 setsignal(SIGINT);
9408 setsignal(SIGQUIT);
9409 setsignal(SIGTERM);
9410#if !ENABLE_FEATURE_SH_EXTRA_QUIET
9411 if (is_interactive > 1) {
9412 /* Looks like they want an interactive shell */
Denis Vlasenkoca525b42007-06-13 12:27:17 +00009413 static smallint did_banner;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009414
Denis Vlasenkoca525b42007-06-13 12:27:17 +00009415 if (!did_banner) {
Denys Vlasenkoc34c0332009-09-29 12:25:30 +02009416 /* note: ash and hush share this string */
9417 out1fmt("\n\n%s %s\n"
Denys Vlasenko2ec34962014-09-08 16:52:39 +02009418 IF_ASH_HELP("Enter 'help' for a list of built-in commands.\n")
9419 "\n",
Denys Vlasenkoc34c0332009-09-29 12:25:30 +02009420 bb_banner,
9421 "built-in shell (ash)"
9422 );
Denis Vlasenkoca525b42007-06-13 12:27:17 +00009423 did_banner = 1;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009424 }
9425 }
9426#endif
9427}
9428
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009429static void
9430optschanged(void)
9431{
9432#if DEBUG
9433 opentrace();
9434#endif
9435 setinteractive(iflag);
9436 setjobctl(mflag);
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009437#if ENABLE_FEATURE_EDITING_VI
9438 if (viflag)
9439 line_input_state->flags |= VI_MODE;
9440 else
9441 line_input_state->flags &= ~VI_MODE;
9442#else
9443 viflag = 0; /* forcibly keep the option off */
9444#endif
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009445}
9446
Denys Vlasenkob8ab27b2017-07-26 19:22:34 +02009447struct localvar_list {
9448 struct localvar_list *next;
9449 struct localvar *lv;
9450};
9451
9452static struct localvar_list *localvar_stack;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009453
9454/*
9455 * Called after a function returns.
9456 * Interrupts must be off.
9457 */
9458static void
Denys Vlasenko981a0562017-07-26 19:53:11 +02009459poplocalvars(int keep)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009460{
Denys Vlasenkob8ab27b2017-07-26 19:22:34 +02009461 struct localvar_list *ll;
9462 struct localvar *lvp, *next;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009463 struct var *vp;
9464
Denys Vlasenkob8ab27b2017-07-26 19:22:34 +02009465 INT_OFF;
9466 ll = localvar_stack;
9467 localvar_stack = ll->next;
9468
9469 next = ll->lv;
9470 free(ll);
9471
9472 while ((lvp = next) != NULL) {
9473 next = lvp->next;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009474 vp = lvp->vp;
Denys Vlasenkob563f622010-09-25 17:15:13 +02009475 TRACE(("poplocalvar %s\n", vp ? vp->var_text : "-"));
Denys Vlasenko981a0562017-07-26 19:53:11 +02009476 if (keep) {
9477 int bits = VSTRFIXED;
9478
9479 if (lvp->flags != VUNSET) {
9480 if (vp->var_text == lvp->text)
9481 bits |= VTEXTFIXED;
9482 else if (!(lvp->flags & (VTEXTFIXED|VSTACK)))
9483 free((char*)lvp->text);
9484 }
9485
9486 vp->flags &= ~bits;
9487 vp->flags |= (lvp->flags & bits);
9488
9489 if ((vp->flags &
9490 (VEXPORT|VREADONLY|VSTRFIXED|VUNSET)) == VUNSET)
9491 unsetvar(vp->var_text);
9492 } else if (vp == NULL) { /* $- saved */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009493 memcpy(optlist, lvp->text, sizeof(optlist));
9494 free((char*)lvp->text);
9495 optschanged();
Denys Vlasenkod5b500c2017-07-26 19:25:40 +02009496 } else if (lvp->flags == VUNSET) {
9497 vp->flags &= ~(VSTRFIXED|VREADONLY);
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009498 unsetvar(vp->var_text);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009499 } else {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009500 if (vp->var_func)
9501 vp->var_func(var_end(lvp->text));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009502 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009503 free((char*)vp->var_text);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009504 vp->flags = lvp->flags;
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009505 vp->var_text = lvp->text;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009506 }
9507 free(lvp);
9508 }
Denys Vlasenkob8ab27b2017-07-26 19:22:34 +02009509 INT_ON;
9510}
9511
9512/*
9513 * Create a new localvar environment.
9514 */
Denys Vlasenko484fc202017-07-26 19:55:31 +02009515static struct localvar_list *
Denys Vlasenkob8ab27b2017-07-26 19:22:34 +02009516pushlocalvars(void)
9517{
9518 struct localvar_list *ll;
9519
9520 INT_OFF;
9521 ll = ckzalloc(sizeof(*ll));
9522 /*ll->lv = NULL; - zalloc did it */
9523 ll->next = localvar_stack;
9524 localvar_stack = ll;
9525 INT_ON;
Denys Vlasenko484fc202017-07-26 19:55:31 +02009526
9527 return ll->next;
9528}
9529
9530static void
9531unwindlocalvars(struct localvar_list *stop)
9532{
9533 while (localvar_stack != stop)
9534 poplocalvars(0);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009535}
9536
9537static int
9538evalfun(struct funcnode *func, int argc, char **argv, int flags)
9539{
9540 volatile struct shparam saveparam;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009541 struct jmploc *volatile savehandler;
9542 struct jmploc jmploc;
9543 int e;
Denys Vlasenko675d24a2018-01-27 22:02:05 +01009544 int savefuncline;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009545
9546 saveparam = shellparam;
Denys Vlasenko675d24a2018-01-27 22:02:05 +01009547 savefuncline = funcline;
Denys Vlasenkoa2d121c2016-09-30 11:30:11 +02009548 savehandler = exception_handler;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009549 e = setjmp(jmploc.loc);
9550 if (e) {
9551 goto funcdone;
9552 }
9553 INT_OFF;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009554 exception_handler = &jmploc;
Denis Vlasenko01631112007-12-16 17:20:38 +00009555 shellparam.malloced = 0;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009556 func->count++;
Denys Vlasenko675d24a2018-01-27 22:02:05 +01009557 funcline = func->n.ndefun.linno;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009558 INT_ON;
9559 shellparam.nparam = argc - 1;
9560 shellparam.p = argv + 1;
9561#if ENABLE_ASH_GETOPTS
9562 shellparam.optind = 1;
9563 shellparam.optoff = -1;
9564#endif
Denys Vlasenkob8ab27b2017-07-26 19:22:34 +02009565 pushlocalvars();
Denys Vlasenko675d24a2018-01-27 22:02:05 +01009566 evaltree(func->n.ndefun.body, flags & EV_TESTED);
Denys Vlasenko981a0562017-07-26 19:53:11 +02009567 poplocalvars(0);
Denis Vlasenko01631112007-12-16 17:20:38 +00009568 funcdone:
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009569 INT_OFF;
Denys Vlasenko675d24a2018-01-27 22:02:05 +01009570 funcline = savefuncline;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009571 freefunc(func);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009572 freeparam(&shellparam);
9573 shellparam = saveparam;
9574 exception_handler = savehandler;
9575 INT_ON;
9576 evalskip &= ~SKIPFUNC;
9577 return e;
9578}
9579
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009580/*
9581 * Make a variable a local variable. When a variable is made local, it's
9582 * value and flags are saved in a localvar structure. The saved values
9583 * will be restored when the shell function returns. We handle the name
Denys Vlasenkoe0a4e102015-05-13 02:20:14 +02009584 * "-" as a special case: it makes changes to "set +-options" local
9585 * (options will be restored on return from the function).
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009586 */
9587static void
9588mklocal(char *name)
9589{
9590 struct localvar *lvp;
9591 struct var **vpp;
9592 struct var *vp;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009593 char *eq = strchr(name, '=');
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009594
9595 INT_OFF;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009596 /* Cater for duplicate "local". Examples:
9597 * x=0; f() { local x=1; echo $x; local x; echo $x; }; f; echo $x
9598 * x=0; f() { local x=1; echo $x; local x=2; echo $x; }; f; echo $x
9599 */
Denys Vlasenkob8ab27b2017-07-26 19:22:34 +02009600 lvp = localvar_stack->lv;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009601 while (lvp) {
Eugene Rudoy1285aa62015-04-26 23:32:00 +02009602 if (lvp->vp && varcmp(lvp->vp->var_text, name) == 0) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009603 if (eq)
9604 setvareq(name, 0);
9605 /* else:
9606 * it's a duplicate "local VAR" declaration, do nothing
9607 */
Denys Vlasenko06b11492016-11-04 16:43:18 +01009608 goto ret;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009609 }
9610 lvp = lvp->next;
9611 }
9612
9613 lvp = ckzalloc(sizeof(*lvp));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009614 if (LONE_DASH(name)) {
9615 char *p;
9616 p = ckmalloc(sizeof(optlist));
9617 lvp->text = memcpy(p, optlist, sizeof(optlist));
9618 vp = NULL;
9619 } else {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009620 vpp = hashvar(name);
9621 vp = *findvar(vpp, name);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009622 if (vp == NULL) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009623 /* variable did not exist yet */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009624 if (eq)
Denys Vlasenkod04fc712017-07-26 20:06:48 +02009625 vp = setvareq(name, VSTRFIXED);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009626 else
Denys Vlasenkod04fc712017-07-26 20:06:48 +02009627 vp = setvar(name, NULL, VSTRFIXED);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009628 lvp->flags = VUNSET;
9629 } else {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009630 lvp->text = vp->var_text;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009631 lvp->flags = vp->flags;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009632 /* make sure neither "struct var" nor string gets freed
9633 * during (un)setting:
9634 */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009635 vp->flags |= VSTRFIXED|VTEXTFIXED;
9636 if (eq)
9637 setvareq(name, 0);
Denys Vlasenko109ee5d2014-03-16 18:41:11 +01009638 else
9639 /* "local VAR" unsets VAR: */
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009640 setvar0(name, NULL);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009641 }
9642 }
9643 lvp->vp = vp;
Denys Vlasenkob8ab27b2017-07-26 19:22:34 +02009644 lvp->next = localvar_stack->lv;
9645 localvar_stack->lv = lvp;
Denys Vlasenko06b11492016-11-04 16:43:18 +01009646 ret:
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009647 INT_ON;
9648}
9649
9650/*
9651 * The "local" command.
9652 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009653static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009654localcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009655{
9656 char *name;
9657
Denys Vlasenkob8ab27b2017-07-26 19:22:34 +02009658 if (!localvar_stack)
Ron Yorstonef2386b2015-10-29 16:19:14 +00009659 ash_msg_and_raise_error("not in a function");
9660
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009661 argv = argptr;
9662 while ((name = *argv++) != NULL) {
9663 mklocal(name);
9664 }
9665 return 0;
9666}
9667
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009668static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009669falsecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009670{
9671 return 1;
9672}
9673
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009674static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009675truecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009676{
9677 return 0;
9678}
9679
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009680static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009681execcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009682{
Denys Vlasenko6c149f42017-04-12 21:31:32 +02009683 optionarg = NULL;
9684 while (nextopt("a:") != '\0')
9685 /* nextopt() sets optionarg to "-a ARGV0" */;
9686
9687 argv = argptr;
9688 if (argv[0]) {
9689 char *prog;
9690
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009691 iflag = 0; /* exit on error */
9692 mflag = 0;
9693 optschanged();
Denys Vlasenkoe5814a52016-07-16 18:33:55 +02009694 /* We should set up signals for "exec CMD"
9695 * the same way as for "CMD" without "exec".
9696 * But optschanged->setinteractive->setsignal
9697 * still thought we are a root shell. Therefore, for example,
9698 * SIGQUIT is still set to IGN. Fix it:
9699 */
9700 shlvl++;
9701 setsignal(SIGQUIT);
9702 /*setsignal(SIGTERM); - unnecessary because of iflag=0 */
9703 /*setsignal(SIGTSTP); - unnecessary because of mflag=0 */
9704 /*setsignal(SIGTTOU); - unnecessary because of mflag=0 */
9705
Denys Vlasenko6c149f42017-04-12 21:31:32 +02009706 prog = argv[0];
9707 if (optionarg)
9708 argv[0] = optionarg;
9709 shellexec(prog, argv, pathval(), 0);
Denys Vlasenkoe5814a52016-07-16 18:33:55 +02009710 /* NOTREACHED */
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009711 }
9712 return 0;
9713}
9714
9715/*
9716 * The return command.
9717 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009718static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009719returncmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009720{
9721 /*
9722 * If called outside a function, do what ksh does;
9723 * skip the rest of the file.
9724 */
Denys Vlasenko6a0710e2016-09-30 14:18:34 +02009725 evalskip = SKIPFUNC;
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009726 return argv[1] ? number(argv[1]) : exitstatus;
9727}
9728
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009729/* Forward declarations for builtintab[] */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009730static int breakcmd(int, char **) FAST_FUNC;
9731static int dotcmd(int, char **) FAST_FUNC;
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009732static int evalcmd(int, char **, int) FAST_FUNC;
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009733static int exitcmd(int, char **) FAST_FUNC;
9734static int exportcmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009735#if ENABLE_ASH_GETOPTS
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009736static int getoptscmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009737#endif
Denys Vlasenko2ec34962014-09-08 16:52:39 +02009738#if ENABLE_ASH_HELP
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009739static int helpcmd(int, char **) FAST_FUNC;
Denis Vlasenko52764022007-02-24 13:42:56 +00009740#endif
Flemming Madsend96ffda2013-04-07 18:47:24 +02009741#if MAX_HISTORY
9742static int historycmd(int, char **) FAST_FUNC;
9743#endif
Denys Vlasenko0b883582016-12-23 16:49:07 +01009744#if ENABLE_FEATURE_SH_MATH
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009745static int letcmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009746#endif
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009747static int readcmd(int, char **) FAST_FUNC;
9748static int setcmd(int, char **) FAST_FUNC;
9749static int shiftcmd(int, char **) FAST_FUNC;
9750static int timescmd(int, char **) FAST_FUNC;
9751static int trapcmd(int, char **) FAST_FUNC;
9752static int umaskcmd(int, char **) FAST_FUNC;
9753static int unsetcmd(int, char **) FAST_FUNC;
9754static int ulimitcmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009755
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009756#define BUILTIN_NOSPEC "0"
9757#define BUILTIN_SPECIAL "1"
9758#define BUILTIN_REGULAR "2"
9759#define BUILTIN_SPEC_REG "3"
9760#define BUILTIN_ASSIGN "4"
9761#define BUILTIN_SPEC_ASSG "5"
9762#define BUILTIN_REG_ASSG "6"
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009763#define BUILTIN_SPEC_REG_ASSG "7"
9764
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009765/* Stubs for calling non-FAST_FUNC's */
Denys Vlasenko265062d2017-01-10 15:13:30 +01009766#if ENABLE_ASH_ECHO
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009767static int FAST_FUNC echocmd(int argc, char **argv) { return echo_main(argc, argv); }
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009768#endif
Denys Vlasenko265062d2017-01-10 15:13:30 +01009769#if ENABLE_ASH_PRINTF
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009770static int FAST_FUNC printfcmd(int argc, char **argv) { return printf_main(argc, argv); }
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009771#endif
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01009772#if ENABLE_ASH_TEST || BASH_TEST2
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009773static int FAST_FUNC testcmd(int argc, char **argv) { return test_main(argc, argv); }
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009774#endif
Denis Vlasenko468aea22008-04-01 14:47:57 +00009775
Denis Vlasenkof7d56652008-03-25 05:51:41 +00009776/* Keep these in proper order since it is searched via bsearch() */
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009777static const struct builtincmd builtintab[] = {
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009778 { BUILTIN_SPEC_REG "." , dotcmd },
9779 { BUILTIN_SPEC_REG ":" , truecmd },
Denys Vlasenko265062d2017-01-10 15:13:30 +01009780#if ENABLE_ASH_TEST
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009781 { BUILTIN_REGULAR "[" , testcmd },
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01009782#endif
9783#if BASH_TEST2
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009784 { BUILTIN_REGULAR "[[" , testcmd },
Denis Vlasenko80591b02008-03-25 07:49:43 +00009785#endif
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009786#if ENABLE_ASH_ALIAS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009787 { BUILTIN_REG_ASSG "alias" , aliascmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009788#endif
9789#if JOBS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009790 { BUILTIN_REGULAR "bg" , fg_bgcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009791#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009792 { BUILTIN_SPEC_REG "break" , breakcmd },
9793 { BUILTIN_REGULAR "cd" , cdcmd },
9794 { BUILTIN_NOSPEC "chdir" , cdcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009795#if ENABLE_ASH_CMDCMD
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009796 { BUILTIN_REGULAR "command" , commandcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009797#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009798 { BUILTIN_SPEC_REG "continue", breakcmd },
Denys Vlasenko265062d2017-01-10 15:13:30 +01009799#if ENABLE_ASH_ECHO
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009800 { BUILTIN_REGULAR "echo" , echocmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009801#endif
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009802 { BUILTIN_SPEC_REG "eval" , NULL }, /*evalcmd() has a differing prototype*/
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009803 { BUILTIN_SPEC_REG "exec" , execcmd },
9804 { BUILTIN_SPEC_REG "exit" , exitcmd },
9805 { BUILTIN_SPEC_REG_ASSG "export" , exportcmd },
9806 { BUILTIN_REGULAR "false" , falsecmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009807#if JOBS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009808 { BUILTIN_REGULAR "fg" , fg_bgcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009809#endif
9810#if ENABLE_ASH_GETOPTS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009811 { BUILTIN_REGULAR "getopts" , getoptscmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009812#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009813 { BUILTIN_NOSPEC "hash" , hashcmd },
Denys Vlasenko2ec34962014-09-08 16:52:39 +02009814#if ENABLE_ASH_HELP
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009815 { BUILTIN_NOSPEC "help" , helpcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009816#endif
Flemming Madsend96ffda2013-04-07 18:47:24 +02009817#if MAX_HISTORY
9818 { BUILTIN_NOSPEC "history" , historycmd },
9819#endif
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009820#if JOBS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009821 { BUILTIN_REGULAR "jobs" , jobscmd },
9822 { BUILTIN_REGULAR "kill" , killcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009823#endif
Denys Vlasenko0b883582016-12-23 16:49:07 +01009824#if ENABLE_FEATURE_SH_MATH
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009825 { BUILTIN_NOSPEC "let" , letcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009826#endif
Denys Vlasenko85241c72017-07-26 20:00:08 +02009827 { BUILTIN_SPEC_REG_ASSG "local" , localcmd },
Denys Vlasenko265062d2017-01-10 15:13:30 +01009828#if ENABLE_ASH_PRINTF
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009829 { BUILTIN_REGULAR "printf" , printfcmd },
Denis Vlasenkocd2663f2008-06-01 22:36:39 +00009830#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009831 { BUILTIN_NOSPEC "pwd" , pwdcmd },
9832 { BUILTIN_REGULAR "read" , readcmd },
9833 { BUILTIN_SPEC_REG_ASSG "readonly", exportcmd },
9834 { BUILTIN_SPEC_REG "return" , returncmd },
9835 { BUILTIN_SPEC_REG "set" , setcmd },
9836 { BUILTIN_SPEC_REG "shift" , shiftcmd },
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01009837#if BASH_SOURCE
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009838 { BUILTIN_SPEC_REG "source" , dotcmd },
Denys Vlasenko82731b42010-05-17 17:49:52 +02009839#endif
Denys Vlasenko265062d2017-01-10 15:13:30 +01009840#if ENABLE_ASH_TEST
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009841 { BUILTIN_REGULAR "test" , testcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009842#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009843 { BUILTIN_SPEC_REG "times" , timescmd },
9844 { BUILTIN_SPEC_REG "trap" , trapcmd },
9845 { BUILTIN_REGULAR "true" , truecmd },
9846 { BUILTIN_NOSPEC "type" , typecmd },
9847 { BUILTIN_NOSPEC "ulimit" , ulimitcmd },
9848 { BUILTIN_REGULAR "umask" , umaskcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009849#if ENABLE_ASH_ALIAS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009850 { BUILTIN_REGULAR "unalias" , unaliascmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009851#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009852 { BUILTIN_SPEC_REG "unset" , unsetcmd },
9853 { BUILTIN_REGULAR "wait" , waitcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009854};
9855
Denis Vlasenko80591b02008-03-25 07:49:43 +00009856/* Should match the above table! */
9857#define COMMANDCMD (builtintab + \
Denys Vlasenko928e2a72016-09-29 00:30:31 +02009858 /* . : */ 2 + \
Denys Vlasenko265062d2017-01-10 15:13:30 +01009859 /* [ */ 1 * ENABLE_ASH_TEST + \
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01009860 /* [[ */ 1 * BASH_TEST2 + \
Denys Vlasenko928e2a72016-09-29 00:30:31 +02009861 /* alias */ 1 * ENABLE_ASH_ALIAS + \
9862 /* bg */ 1 * ENABLE_ASH_JOB_CONTROL + \
9863 /* break cd cddir */ 3)
9864#define EVALCMD (COMMANDCMD + \
9865 /* command */ 1 * ENABLE_ASH_CMDCMD + \
9866 /* continue */ 1 + \
Denys Vlasenko265062d2017-01-10 15:13:30 +01009867 /* echo */ 1 * ENABLE_ASH_ECHO + \
Denys Vlasenko928e2a72016-09-29 00:30:31 +02009868 0)
9869#define EXECCMD (EVALCMD + \
9870 /* eval */ 1)
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009871
9872/*
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009873 * Search the table of builtin commands.
9874 */
Denys Vlasenko888527c2016-10-02 16:54:17 +02009875static int
9876pstrcmp1(const void *a, const void *b)
9877{
9878 return strcmp((char*)a, *(char**)b + 1);
9879}
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009880static struct builtincmd *
9881find_builtin(const char *name)
9882{
9883 struct builtincmd *bp;
9884
9885 bp = bsearch(
Denis Vlasenko80b8b392007-06-25 10:55:35 +00009886 name, builtintab, ARRAY_SIZE(builtintab), sizeof(builtintab[0]),
Denys Vlasenko888527c2016-10-02 16:54:17 +02009887 pstrcmp1
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009888 );
9889 return bp;
9890}
9891
9892/*
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009893 * Execute a simple command.
9894 */
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009895static int
9896isassignment(const char *p)
Paul Foxc3850c82005-07-20 18:23:39 +00009897{
9898 const char *q = endofname(p);
9899 if (p == q)
9900 return 0;
9901 return *q == '=';
9902}
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009903static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009904bltincmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009905{
9906 /* Preserve exitstatus of a previous possible redirection
9907 * as POSIX mandates */
9908 return back_exitstatus;
9909}
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009910static int
Eric Andersenc470f442003-07-28 09:56:35 +00009911evalcommand(union node *cmd, int flags)
9912{
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00009913 static const struct builtincmd null_bltin = {
9914 "\0\0", bltincmd /* why three NULs? */
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009915 };
Denys Vlasenko484fc202017-07-26 19:55:31 +02009916 struct localvar_list *localvar_stop;
Denys Vlasenko1c79aeb2017-07-29 22:51:52 +02009917 struct redirtab *redir_stop;
Eric Andersenc470f442003-07-28 09:56:35 +00009918 struct stackmark smark;
9919 union node *argp;
9920 struct arglist arglist;
9921 struct arglist varlist;
9922 char **argv;
9923 int argc;
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009924 const struct strlist *sp;
Eric Andersenc470f442003-07-28 09:56:35 +00009925 struct cmdentry cmdentry;
9926 struct job *jp;
9927 char *lastarg;
9928 const char *path;
9929 int spclbltin;
Eric Andersenc470f442003-07-28 09:56:35 +00009930 int status;
9931 char **nargv;
Denis Vlasenko34c73c42008-08-16 11:48:02 +00009932 smallint cmd_is_exec;
Eric Andersenc470f442003-07-28 09:56:35 +00009933
Denys Vlasenko675d24a2018-01-27 22:02:05 +01009934 errlinno = lineno = cmd->ncmd.linno;
9935 if (funcline)
9936 lineno -= funcline - 1;
9937
Eric Andersenc470f442003-07-28 09:56:35 +00009938 /* First expand the arguments. */
9939 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
9940 setstackmark(&smark);
Denys Vlasenko484fc202017-07-26 19:55:31 +02009941 localvar_stop = pushlocalvars();
Eric Andersenc470f442003-07-28 09:56:35 +00009942 back_exitstatus = 0;
9943
9944 cmdentry.cmdtype = CMDBUILTIN;
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00009945 cmdentry.u.cmd = &null_bltin;
Eric Andersenc470f442003-07-28 09:56:35 +00009946 varlist.lastp = &varlist.list;
9947 *varlist.lastp = NULL;
9948 arglist.lastp = &arglist.list;
9949 *arglist.lastp = NULL;
9950
9951 argc = 0;
Denis Vlasenkob012b102007-02-19 22:43:01 +00009952 if (cmd->ncmd.args) {
Denys Vlasenkod07a15b2017-07-30 16:51:05 +02009953 struct builtincmd *bcmd;
9954 smallint pseudovarflag;
9955
Paul Foxc3850c82005-07-20 18:23:39 +00009956 bcmd = find_builtin(cmd->ncmd.args->narg.text);
9957 pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd);
Paul Foxc3850c82005-07-20 18:23:39 +00009958
Denys Vlasenkod07a15b2017-07-30 16:51:05 +02009959 for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) {
9960 struct strlist **spp;
Eric Andersenc470f442003-07-28 09:56:35 +00009961
Denys Vlasenkod07a15b2017-07-30 16:51:05 +02009962 spp = arglist.lastp;
9963 if (pseudovarflag && isassignment(argp->narg.text))
9964 expandarg(argp, &arglist, EXP_VARTILDE);
9965 else
9966 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
Paul Foxc3850c82005-07-20 18:23:39 +00009967
Denys Vlasenkod07a15b2017-07-30 16:51:05 +02009968 for (sp = *spp; sp; sp = sp->next)
9969 argc++;
9970 }
Eric Andersenc470f442003-07-28 09:56:35 +00009971 }
9972
Denys Vlasenko65a8b852016-10-26 22:29:11 +02009973 /* Reserve one extra spot at the front for shellexec. */
9974 nargv = stalloc(sizeof(char *) * (argc + 2));
9975 argv = ++nargv;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009976 for (sp = arglist.list; sp; sp = sp->next) {
Eric Andersenc470f442003-07-28 09:56:35 +00009977 TRACE(("evalcommand arg: %s\n", sp->text));
9978 *nargv++ = sp->text;
9979 }
9980 *nargv = NULL;
9981
9982 lastarg = NULL;
Denys Vlasenko675d24a2018-01-27 22:02:05 +01009983 if (iflag && funcline == 0 && argc > 0)
Eric Andersenc470f442003-07-28 09:56:35 +00009984 lastarg = nargv[-1];
9985
9986 expredir(cmd->ncmd.redirect);
Denys Vlasenko1c79aeb2017-07-29 22:51:52 +02009987 redir_stop = pushredir(cmd->ncmd.redirect);
Denys Vlasenkod07a15b2017-07-30 16:51:05 +02009988 preverrout_fd = 2;
Denys Vlasenkof8cdc7a2017-08-04 15:24:49 +02009989 if (BASH_XTRACEFD && xflag) {
9990 /* NB: bash closes fd == $BASH_XTRACEFD when it is changed.
9991 * we do not emulate this. We only use its value.
9992 */
9993 const char *xtracefd = lookupvar("BASH_XTRACEFD");
9994 if (xtracefd && is_number(xtracefd))
9995 preverrout_fd = atoi(xtracefd);
9996
9997 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009998 status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH | REDIR_SAVEFD2);
Eric Andersenc470f442003-07-28 09:56:35 +00009999
Denys Vlasenko8837c5d2010-06-02 12:56:18 +020010000 path = vpath.var_text;
Eric Andersenc470f442003-07-28 09:56:35 +000010001 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
10002 struct strlist **spp;
10003 char *p;
10004
10005 spp = varlist.lastp;
10006 expandarg(argp, &varlist, EXP_VARTILDE);
10007
Denys Vlasenko981a0562017-07-26 19:53:11 +020010008 mklocal((*spp)->text);
10009
Eric Andersenc470f442003-07-28 09:56:35 +000010010 /*
10011 * Modify the command lookup path, if a PATH= assignment
10012 * is present
10013 */
10014 p = (*spp)->text;
Denys Vlasenko8837c5d2010-06-02 12:56:18 +020010015 if (varcmp(p, path) == 0)
Eric Andersenc470f442003-07-28 09:56:35 +000010016 path = p;
10017 }
10018
10019 /* Print the command if xflag is set. */
10020 if (xflag) {
Denys Vlasenko42ba7572017-07-21 13:20:14 +020010021 const char *pfx = "";
Eric Andersenc470f442003-07-28 09:56:35 +000010022
Denys Vlasenko46999802017-07-29 21:12:29 +020010023 fdprintf(preverrout_fd, "%s", expandstr(ps4val(), DQSYNTAX));
Denys Vlasenko42ba7572017-07-21 13:20:14 +020010024
Glenn L McGrath7b8765c2003-08-29 07:29:30 +000010025 sp = varlist.list;
Denys Vlasenko42ba7572017-07-21 13:20:14 +020010026 while (sp) {
10027 char *varval = sp->text;
10028 char *eq = strchrnul(varval, '=');
10029 if (*eq)
10030 eq++;
10031 fdprintf(preverrout_fd, "%s%.*s%s",
10032 pfx,
10033 (int)(eq - varval), varval,
10034 maybe_single_quote(eq)
10035 );
10036 sp = sp->next;
10037 pfx = " ";
10038 }
10039
10040 sp = arglist.list;
10041 while (sp) {
10042 fdprintf(preverrout_fd, "%s%s",
10043 pfx,
10044 /* always quote if matches reserved word: */
10045 findkwd(sp->text)
10046 ? single_quote(sp->text)
10047 : maybe_single_quote(sp->text)
10048 );
10049 sp = sp->next;
10050 pfx = " ";
Glenn L McGrath7b8765c2003-08-29 07:29:30 +000010051 }
Denis Vlasenko0e6f6612008-02-15 15:02:15 +000010052 safe_write(preverrout_fd, "\n", 1);
Eric Andersenc470f442003-07-28 09:56:35 +000010053 }
10054
10055 cmd_is_exec = 0;
10056 spclbltin = -1;
10057
10058 /* Now locate the command. */
10059 if (argc) {
Eric Andersenc470f442003-07-28 09:56:35 +000010060 int cmd_flag = DO_ERR;
Denys Vlasenko0b4980c2012-09-25 12:49:29 +020010061#if ENABLE_ASH_CMDCMD
10062 const char *oldpath = path + 5;
10063#endif
Eric Andersenc470f442003-07-28 09:56:35 +000010064 path += 5;
Eric Andersenc470f442003-07-28 09:56:35 +000010065 for (;;) {
10066 find_command(argv[0], &cmdentry, cmd_flag, path);
10067 if (cmdentry.cmdtype == CMDUNKNOWN) {
Denys Vlasenko8131eea2009-11-02 14:19:51 +010010068 flush_stdout_stderr();
Denis Vlasenko6514c5e2008-07-24 13:41:37 +000010069 status = 127;
Eric Andersenc470f442003-07-28 09:56:35 +000010070 goto bail;
10071 }
10072
10073 /* implement bltin and command here */
10074 if (cmdentry.cmdtype != CMDBUILTIN)
10075 break;
10076 if (spclbltin < 0)
10077 spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd);
10078 if (cmdentry.u.cmd == EXECCMD)
Denis Vlasenko34c73c42008-08-16 11:48:02 +000010079 cmd_is_exec = 1;
Denis Vlasenko131ae172007-02-18 13:00:19 +000010080#if ENABLE_ASH_CMDCMD
Eric Andersenc470f442003-07-28 09:56:35 +000010081 if (cmdentry.u.cmd == COMMANDCMD) {
Eric Andersenc470f442003-07-28 09:56:35 +000010082 path = oldpath;
10083 nargv = parse_command_args(argv, &path);
10084 if (!nargv)
10085 break;
Denys Vlasenkocac4d002016-10-01 03:02:25 +020010086 /* It's "command [-p] PROG ARGS" (that is, no -Vv).
10087 * nargv => "PROG". path is updated if -p.
10088 */
Eric Andersenc470f442003-07-28 09:56:35 +000010089 argc -= nargv - argv;
10090 argv = nargv;
10091 cmd_flag |= DO_NOFUNC;
10092 } else
10093#endif
10094 break;
10095 }
10096 }
10097
10098 if (status) {
Ron Yorstonea7d2f62017-01-03 11:18:23 +010010099 bail:
10100 exitstatus = status;
10101
Eric Andersenc470f442003-07-28 09:56:35 +000010102 /* We have a redirection error. */
10103 if (spclbltin > 0)
Denis Vlasenkob012b102007-02-19 22:43:01 +000010104 raise_exception(EXERROR);
Ron Yorstonea7d2f62017-01-03 11:18:23 +010010105
Eric Andersenc470f442003-07-28 09:56:35 +000010106 goto out;
10107 }
10108
10109 /* Execute the command. */
10110 switch (cmdentry.cmdtype) {
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +020010111 default: {
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +000010112
Denys Vlasenko1750d3a2018-01-15 00:41:04 +010010113#if ENABLE_FEATURE_SH_STANDALONE \
10114 && ENABLE_FEATURE_SH_NOFORK \
10115 && NUM_APPLETS > 1
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +020010116/* (1) BUG: if variables are set, we need to fork, or save/restore them
10117 * around run_nofork_applet() call.
10118 * (2) Should this check also be done in forkshell()?
10119 * (perhaps it should, so that "VAR=VAL nofork" at least avoids exec...)
10120 */
Denis Vlasenko7465dbc2008-04-13 02:25:53 +000010121 /* find_command() encodes applet_no as (-2 - applet_no) */
10122 int applet_no = (- cmdentry.u.index - 2);
Denis Vlasenko9bc80d72008-04-12 20:07:53 +000010123 if (applet_no >= 0 && APPLET_IS_NOFORK(applet_no)) {
Denys Vlasenkoa5060b82017-11-03 14:16:25 +010010124 char **sv_environ;
10125
10126 INT_OFF;
10127 sv_environ = environ;
10128 environ = listvars(VEXPORT, VUNSET, varlist.list, /*end:*/ NULL);
Denys Vlasenkod329e342017-08-04 14:50:03 +020010129 /*
10130 * Run <applet>_main().
10131 * Signals (^C) can't interrupt here.
10132 * Otherwise we can mangle stdio or malloc internal state.
10133 * This makes applets which can run for a long time
10134 * and/or wait for user input ineligible for NOFORK:
10135 * for example, "yes" or "rm" (rm -i waits for input).
10136 */
Ron Yorston5ccb0e92016-10-20 12:24:02 +010010137 status = run_nofork_applet(applet_no, argv);
Denys Vlasenkoa5060b82017-11-03 14:16:25 +010010138 environ = sv_environ;
Denys Vlasenkod329e342017-08-04 14:50:03 +020010139 /*
10140 * Try enabling NOFORK for "yes" applet.
10141 * ^C _will_ stop it (write returns EINTR),
10142 * but this causes stdout FILE to be stuck
10143 * and needing clearerr(). What if other applets
10144 * also can get EINTRs? Do we need to switch
10145 * our signals to SA_RESTART?
10146 */
10147 /*clearerr(stdout);*/
10148 INT_ON;
Denis Vlasenko9bc80d72008-04-12 20:07:53 +000010149 break;
10150 }
Denis Vlasenko9bc80d72008-04-12 20:07:53 +000010151#endif
Denys Vlasenkocfd392b2017-08-03 19:56:29 +020010152 /* Can we avoid forking? For example, very last command
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +020010153 * in a script or a subshell does not need forking,
10154 * we can just exec it.
10155 */
Denys Vlasenko238bf182010-05-18 15:49:07 +020010156 if (!(flags & EV_EXIT) || may_have_traps) {
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +020010157 /* No, forking off a child is necessary */
Denis Vlasenkob012b102007-02-19 22:43:01 +000010158 INT_OFF;
Denys Vlasenko098b7132017-01-11 19:59:03 +010010159 get_tty_state();
Denis Vlasenko68404f12008-03-17 09:00:54 +000010160 jp = makejob(/*cmd,*/ 1);
Eric Andersenc470f442003-07-28 09:56:35 +000010161 if (forkshell(jp, cmd, FORK_FG) != 0) {
Denys Vlasenko238bf182010-05-18 15:49:07 +020010162 /* parent */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020010163 status = waitforjob(jp);
Denis Vlasenkob012b102007-02-19 22:43:01 +000010164 INT_ON;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020010165 TRACE(("forked child exited with %d\n", status));
Eric Andersenc470f442003-07-28 09:56:35 +000010166 break;
10167 }
Denys Vlasenko238bf182010-05-18 15:49:07 +020010168 /* child */
Denis Vlasenkob012b102007-02-19 22:43:01 +000010169 FORCE_INT_ON;
Denys Vlasenkoc7f95d22010-05-18 15:52:23 +020010170 /* fall through to exec'ing external program */
Eric Andersenc470f442003-07-28 09:56:35 +000010171 }
10172 listsetvar(varlist.list, VEXPORT|VSTACK);
Denys Vlasenkoe139ae32017-04-12 21:02:33 +020010173 shellexec(argv[0], argv, path, cmdentry.u.index);
Eric Andersenc470f442003-07-28 09:56:35 +000010174 /* NOTREACHED */
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +020010175 } /* default */
Eric Andersenc470f442003-07-28 09:56:35 +000010176 case CMDBUILTIN:
Denys Vlasenko85241c72017-07-26 20:00:08 +020010177 if (spclbltin > 0 || argc == 0) {
10178 poplocalvars(1);
10179 if (cmd_is_exec && argc > 1)
10180 listsetvar(varlist.list, VEXPORT);
10181 }
Denys Vlasenko981a0562017-07-26 19:53:11 +020010182
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +000010183 /* Tight loop with builtins only:
10184 * "while kill -0 $child; do true; done"
10185 * will never exit even if $child died, unless we do this
10186 * to reap the zombie and make kill detect that it's gone: */
10187 dowait(DOWAIT_NONBLOCK, NULL);
10188
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020010189 if (evalbltin(cmdentry.u.cmd, argc, argv, flags)) {
Denys Vlasenkoc0663c72016-10-27 21:09:01 +020010190 if (exception_type == EXERROR && spclbltin <= 0) {
10191 FORCE_INT_ON;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020010192 goto readstatus;
Eric Andersenc470f442003-07-28 09:56:35 +000010193 }
Denys Vlasenkoc0663c72016-10-27 21:09:01 +020010194 raise:
10195 longjmp(exception_handler->loc, 1);
Eric Andersenc470f442003-07-28 09:56:35 +000010196 }
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020010197 goto readstatus;
Eric Andersenc470f442003-07-28 09:56:35 +000010198
10199 case CMDFUNCTION:
Denys Vlasenko981a0562017-07-26 19:53:11 +020010200 poplocalvars(1);
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +000010201 /* See above for the rationale */
10202 dowait(DOWAIT_NONBLOCK, NULL);
Eric Andersenc470f442003-07-28 09:56:35 +000010203 if (evalfun(cmdentry.u.func, argc, argv, flags))
10204 goto raise;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020010205 readstatus:
10206 status = exitstatus;
Eric Andersenc470f442003-07-28 09:56:35 +000010207 break;
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +020010208 } /* switch */
Eric Andersenc470f442003-07-28 09:56:35 +000010209
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010210 out:
Denys Vlasenkoeaf94362016-10-25 21:46:03 +020010211 if (cmd->ncmd.redirect)
Denys Vlasenko035486c2017-07-31 04:09:19 +020010212 popredir(/*drop:*/ cmd_is_exec);
Denys Vlasenko1c79aeb2017-07-29 22:51:52 +020010213 unwindredir(redir_stop);
Denys Vlasenko484fc202017-07-26 19:55:31 +020010214 unwindlocalvars(localvar_stop);
Denis Vlasenko6514c5e2008-07-24 13:41:37 +000010215 if (lastarg) {
Eric Andersenc470f442003-07-28 09:56:35 +000010216 /* dsl: I think this is intended to be used to support
10217 * '_' in 'vi' command mode during line editing...
10218 * However I implemented that within libedit itself.
10219 */
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020010220 setvar0("_", lastarg);
Denis Vlasenko6514c5e2008-07-24 13:41:37 +000010221 }
Eric Andersenc470f442003-07-28 09:56:35 +000010222 popstackmark(&smark);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020010223
10224 return status;
Eric Andersenc470f442003-07-28 09:56:35 +000010225}
10226
10227static int
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020010228evalbltin(const struct builtincmd *cmd, int argc, char **argv, int flags)
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010229{
Eric Andersenc470f442003-07-28 09:56:35 +000010230 char *volatile savecmdname;
10231 struct jmploc *volatile savehandler;
10232 struct jmploc jmploc;
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020010233 int status;
Eric Andersenc470f442003-07-28 09:56:35 +000010234 int i;
10235
10236 savecmdname = commandname;
Denys Vlasenkoa2d121c2016-09-30 11:30:11 +020010237 savehandler = exception_handler;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010238 i = setjmp(jmploc.loc);
10239 if (i)
Eric Andersenc470f442003-07-28 09:56:35 +000010240 goto cmddone;
Denis Vlasenko2da584f2007-02-19 22:44:05 +000010241 exception_handler = &jmploc;
Eric Andersenc470f442003-07-28 09:56:35 +000010242 commandname = argv[0];
10243 argptr = argv + 1;
10244 optptr = NULL; /* initialize nextopt */
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020010245 if (cmd == EVALCMD)
10246 status = evalcmd(argc, argv, flags);
10247 else
10248 status = (*cmd->builtin)(argc, argv);
Denis Vlasenkob012b102007-02-19 22:43:01 +000010249 flush_stdout_stderr();
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020010250 status |= ferror(stdout);
10251 exitstatus = status;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010252 cmddone:
Rob Landleyf296f0b2006-07-06 01:09:21 +000010253 clearerr(stdout);
Eric Andersenc470f442003-07-28 09:56:35 +000010254 commandname = savecmdname;
Denis Vlasenko2da584f2007-02-19 22:44:05 +000010255 exception_handler = savehandler;
Eric Andersenc470f442003-07-28 09:56:35 +000010256
10257 return i;
10258}
10259
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010260static int
10261goodname(const char *p)
Glenn L McGrath16e45d72004-02-04 08:24:39 +000010262{
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +020010263 return endofname(p)[0] == '\0';
Glenn L McGrath16e45d72004-02-04 08:24:39 +000010264}
10265
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010266
Glenn L McGrath50812ff2002-08-23 13:14:48 +000010267/*
10268 * Search for a command. This is called before we fork so that the
10269 * location of the command will be available in the parent as well as
Glenn L McGrath16e45d72004-02-04 08:24:39 +000010270 * the child. The check for "goodname" is an overly conservative
10271 * check that the name will not be subject to expansion.
Glenn L McGrath50812ff2002-08-23 13:14:48 +000010272 */
Eric Andersenc470f442003-07-28 09:56:35 +000010273static void
10274prehash(union node *n)
Glenn L McGrath50812ff2002-08-23 13:14:48 +000010275{
10276 struct cmdentry entry;
10277
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000010278 if (n->type == NCMD && n->ncmd.args && goodname(n->ncmd.args->narg.text))
10279 find_command(n->ncmd.args->narg.text, &entry, 0, pathval());
Glenn L McGrath50812ff2002-08-23 13:14:48 +000010280}
10281
Eric Andersencb57d552001-06-28 07:25:16 +000010282
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000010283/* ============ Builtin commands
10284 *
10285 * Builtin commands whose functions are closely tied to evaluation
10286 * are implemented here.
Eric Andersencb57d552001-06-28 07:25:16 +000010287 */
10288
10289/*
Eric Andersencb57d552001-06-28 07:25:16 +000010290 * Handle break and continue commands. Break, continue, and return are
10291 * all handled by setting the evalskip flag. The evaluation routines
10292 * above all check this flag, and if it is set they start skipping
10293 * commands rather than executing them. The variable skipcount is
10294 * the number of loops to break/continue, or the number of function
10295 * levels to return. (The latter is always 1.) It should probably
10296 * be an error to break out of more loops than exist, but it isn't
10297 * in the standard shell so we don't make it one here.
10298 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010299static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010300breakcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000010301{
Denis Vlasenko68404f12008-03-17 09:00:54 +000010302 int n = argv[1] ? number(argv[1]) : 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010303
Aaron Lehmann2aef3a62001-12-31 06:03:12 +000010304 if (n <= 0)
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +020010305 ash_msg_and_raise_error(msg_illnum, argv[1]);
Eric Andersencb57d552001-06-28 07:25:16 +000010306 if (n > loopnest)
10307 n = loopnest;
10308 if (n > 0) {
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000010309 evalskip = (**argv == 'c') ? SKIPCONT : SKIPBREAK;
Eric Andersencb57d552001-06-28 07:25:16 +000010310 skipcount = n;
10311 }
10312 return 0;
10313}
10314
Eric Andersenc470f442003-07-28 09:56:35 +000010315
Denys Vlasenko70392332016-10-27 02:31:55 +020010316/*
Eric Andersen90898442003-08-06 11:20:52 +000010317 * This implements the input routines used by the parser.
Eric Andersencb57d552001-06-28 07:25:16 +000010318 */
Denis Vlasenko99eb8502007-02-23 21:09:49 +000010319
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010320enum {
10321 INPUT_PUSH_FILE = 1,
10322 INPUT_NOFILE_OK = 2,
10323};
Eric Andersencb57d552001-06-28 07:25:16 +000010324
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010325static smallint checkkwd;
Denis Vlasenko99eb8502007-02-23 21:09:49 +000010326/* values of checkkwd variable */
10327#define CHKALIAS 0x1
10328#define CHKKWD 0x2
10329#define CHKNL 0x4
Denys Vlasenkoa7328982017-07-29 19:57:28 +020010330#define CHKEOFMARK 0x8
Denis Vlasenko99eb8502007-02-23 21:09:49 +000010331
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010332/*
10333 * Push a string back onto the input at this current parsefile level.
10334 * We handle aliases this way.
10335 */
10336#if !ENABLE_ASH_ALIAS
10337#define pushstring(s, ap) pushstring(s)
10338#endif
10339static void
10340pushstring(char *s, struct alias *ap)
10341{
10342 struct strpush *sp;
10343 int len;
10344
10345 len = strlen(s);
10346 INT_OFF;
10347 if (g_parsefile->strpush) {
10348 sp = ckzalloc(sizeof(*sp));
10349 sp->prev = g_parsefile->strpush;
10350 } else {
10351 sp = &(g_parsefile->basestrpush);
10352 }
10353 g_parsefile->strpush = sp;
10354 sp->prev_string = g_parsefile->next_to_pgetc;
10355 sp->prev_left_in_line = g_parsefile->left_in_line;
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010356 sp->unget = g_parsefile->unget;
10357 memcpy(sp->lastc, g_parsefile->lastc, sizeof(sp->lastc));
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010358#if ENABLE_ASH_ALIAS
10359 sp->ap = ap;
10360 if (ap) {
10361 ap->flag |= ALIASINUSE;
10362 sp->string = s;
10363 }
10364#endif
10365 g_parsefile->next_to_pgetc = s;
10366 g_parsefile->left_in_line = len;
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010367 g_parsefile->unget = 0;
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010368 INT_ON;
10369}
10370
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010371static void
10372popstring(void)
Eric Andersenc470f442003-07-28 09:56:35 +000010373{
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010374 struct strpush *sp = g_parsefile->strpush;
Eric Andersenc470f442003-07-28 09:56:35 +000010375
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010376 INT_OFF;
Denis Vlasenko131ae172007-02-18 13:00:19 +000010377#if ENABLE_ASH_ALIAS
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010378 if (sp->ap) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010379 if (g_parsefile->next_to_pgetc[-1] == ' '
10380 || g_parsefile->next_to_pgetc[-1] == '\t'
10381 ) {
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010382 checkkwd |= CHKALIAS;
Glenn L McGrath28939ad2004-07-21 10:20:19 +000010383 }
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010384 if (sp->string != sp->ap->val) {
10385 free(sp->string);
10386 }
10387 sp->ap->flag &= ~ALIASINUSE;
10388 if (sp->ap->flag & ALIASDEAD) {
10389 unalias(sp->ap->name);
10390 }
Glenn L McGrath28939ad2004-07-21 10:20:19 +000010391 }
Denis Vlasenko8e1c7152007-01-22 07:21:38 +000010392#endif
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010393 g_parsefile->next_to_pgetc = sp->prev_string;
10394 g_parsefile->left_in_line = sp->prev_left_in_line;
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010395 g_parsefile->unget = sp->unget;
10396 memcpy(g_parsefile->lastc, sp->lastc, sizeof(sp->lastc));
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010397 g_parsefile->strpush = sp->prev;
10398 if (sp != &(g_parsefile->basestrpush))
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010399 free(sp);
10400 INT_ON;
10401}
Denis Vlasenko8e1c7152007-01-22 07:21:38 +000010402
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010403static int
10404preadfd(void)
Eric Andersencb57d552001-06-28 07:25:16 +000010405{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010406 int nr;
Denis Vlasenko6a0ad252008-07-25 13:34:05 +000010407 char *buf = g_parsefile->buf;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010408
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010409 g_parsefile->next_to_pgetc = buf;
Denis Vlasenko38f63192007-01-22 09:03:07 +000010410#if ENABLE_FEATURE_EDITING
Denis Vlasenko85c24712008-03-17 09:04:04 +000010411 retry:
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010412 if (!iflag || g_parsefile->pf_fd != STDIN_FILENO)
Ron Yorston61d6ae22015-04-19 10:50:25 +010010413 nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1);
Eric Andersenc470f442003-07-28 09:56:35 +000010414 else {
Denys Vlasenko66c5b122011-02-08 05:07:02 +010010415# if ENABLE_ASH_IDLE_TIMEOUT
Denys Vlasenko84ea60e2017-08-02 17:27:28 +020010416 int timeout = -1;
Denys Vlasenko66c5b122011-02-08 05:07:02 +010010417 if (iflag) {
10418 const char *tmout_var = lookupvar("TMOUT");
10419 if (tmout_var) {
10420 timeout = atoi(tmout_var) * 1000;
10421 if (timeout <= 0)
10422 timeout = -1;
10423 }
10424 }
Denys Vlasenko84ea60e2017-08-02 17:27:28 +020010425 line_input_state->timeout = timeout;
Denys Vlasenko66c5b122011-02-08 05:07:02 +010010426# endif
Denys Vlasenko8c52f802011-02-04 17:36:21 +010010427# if ENABLE_FEATURE_TAB_COMPLETION
Denis Vlasenko8e1c7152007-01-22 07:21:38 +000010428 line_input_state->path_lookup = pathval();
Denys Vlasenko8c52f802011-02-04 17:36:21 +010010429# endif
Denys Vlasenkoe9ab07c2014-08-13 18:00:08 +020010430 reinit_unicode_for_ash();
Denys Vlasenko84ea60e2017-08-02 17:27:28 +020010431 nr = read_line_input(line_input_state, cmdedit_prompt, buf, IBUFSIZ);
Denis Vlasenko8e1c7152007-01-22 07:21:38 +000010432 if (nr == 0) {
Denys Vlasenko4b89d512016-11-25 03:41:03 +010010433 /* ^C pressed, "convert" to SIGINT */
10434 write(STDOUT_FILENO, "^C", 2);
Denis Vlasenko8e1c7152007-01-22 07:21:38 +000010435 if (trap[SIGINT]) {
Glenn L McGrath16e45d72004-02-04 08:24:39 +000010436 buf[0] = '\n';
Denis Vlasenko8e1c7152007-01-22 07:21:38 +000010437 buf[1] = '\0';
Glenn L McGrath16e45d72004-02-04 08:24:39 +000010438 raise(SIGINT);
10439 return 1;
10440 }
Denys Vlasenko8660aeb2016-11-24 17:44:02 +010010441 exitstatus = 128 + SIGINT;
Denys Vlasenko4b89d512016-11-25 03:41:03 +010010442 bb_putchar('\n');
Eric Andersenc470f442003-07-28 09:56:35 +000010443 goto retry;
10444 }
Denys Vlasenko66c5b122011-02-08 05:07:02 +010010445 if (nr < 0) {
10446 if (errno == 0) {
10447 /* Ctrl+D pressed */
10448 nr = 0;
10449 }
10450# if ENABLE_ASH_IDLE_TIMEOUT
10451 else if (errno == EAGAIN && timeout > 0) {
Denys Vlasenkod60752f2015-10-07 22:42:45 +020010452 puts("\007timed out waiting for input: auto-logout");
Denys Vlasenko66c5b122011-02-08 05:07:02 +010010453 exitshell();
10454 }
10455# endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010456 }
Eric Andersencb57d552001-06-28 07:25:16 +000010457 }
10458#else
Ron Yorston61d6ae22015-04-19 10:50:25 +010010459 nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1);
Eric Andersencb57d552001-06-28 07:25:16 +000010460#endif
10461
Denys Vlasenko80c5b682011-05-08 21:21:10 +020010462#if 0 /* disabled: nonblock_immune_read() handles this problem */
Eric Andersencb57d552001-06-28 07:25:16 +000010463 if (nr < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +000010464 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
Denis Vlasenkod37f2222007-08-19 13:42:08 +000010465 int flags = fcntl(0, F_GETFL);
Denis Vlasenko9cb220b2007-12-09 10:03:28 +000010466 if (flags >= 0 && (flags & O_NONBLOCK)) {
10467 flags &= ~O_NONBLOCK;
Eric Andersencb57d552001-06-28 07:25:16 +000010468 if (fcntl(0, F_SETFL, flags) >= 0) {
10469 out2str("sh: turning off NDELAY mode\n");
10470 goto retry;
10471 }
10472 }
10473 }
10474 }
Denis Vlasenkoe376d452008-02-20 22:23:24 +000010475#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010476 return nr;
10477}
10478
10479/*
10480 * Refill the input buffer and return the next input character:
10481 *
10482 * 1) If a string was pushed back on the input, pop it;
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010483 * 2) If an EOF was pushed back (g_parsefile->left_in_line < -BIGNUM)
10484 * or we are reading from a string so we can't refill the buffer,
10485 * return EOF.
Denys Vlasenko883cea42009-07-11 15:31:59 +020010486 * 3) If there is more stuff in this buffer, use it else call read to fill it.
Eric Andersencb57d552001-06-28 07:25:16 +000010487 * 4) Process input up to the next newline, deleting nul characters.
10488 */
Denis Vlasenko727752d2008-11-28 03:41:47 +000010489//#define pgetc_debug(...) bb_error_msg(__VA_ARGS__)
10490#define pgetc_debug(...) ((void)0)
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010491static int pgetc(void);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010492static int
Eric Andersenc470f442003-07-28 09:56:35 +000010493preadbuffer(void)
Eric Andersencb57d552001-06-28 07:25:16 +000010494{
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010495 char *q;
Eric Andersencb57d552001-06-28 07:25:16 +000010496 int more;
Eric Andersencb57d552001-06-28 07:25:16 +000010497
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010498 if (g_parsefile->strpush) {
Denis Vlasenko131ae172007-02-18 13:00:19 +000010499#if ENABLE_ASH_ALIAS
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010500 if (g_parsefile->left_in_line == -1
10501 && g_parsefile->strpush->ap
10502 && g_parsefile->next_to_pgetc[-1] != ' '
10503 && g_parsefile->next_to_pgetc[-1] != '\t'
Denis Vlasenko16898402008-11-25 01:34:52 +000010504 ) {
Denis Vlasenko727752d2008-11-28 03:41:47 +000010505 pgetc_debug("preadbuffer PEOA");
Eric Andersencb57d552001-06-28 07:25:16 +000010506 return PEOA;
10507 }
Eric Andersen2870d962001-07-02 17:27:21 +000010508#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010509 popstring();
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010510 return pgetc();
Eric Andersencb57d552001-06-28 07:25:16 +000010511 }
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010512 /* on both branches above g_parsefile->left_in_line < 0.
Denis Vlasenko727752d2008-11-28 03:41:47 +000010513 * "pgetc" needs refilling.
10514 */
10515
Denis Vlasenkoe27dafd2008-11-28 04:01:03 +000010516 /* -90 is our -BIGNUM. Below we use -99 to mark "EOF on read",
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010517 * pungetc() may increment it a few times.
Denis Vlasenkoe27dafd2008-11-28 04:01:03 +000010518 * Assuming it won't increment it to less than -90.
Denis Vlasenko727752d2008-11-28 03:41:47 +000010519 */
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010520 if (g_parsefile->left_in_line < -90 || g_parsefile->buf == NULL) {
Denis Vlasenko727752d2008-11-28 03:41:47 +000010521 pgetc_debug("preadbuffer PEOF1");
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010522 /* even in failure keep left_in_line and next_to_pgetc
10523 * in lock step, for correct multi-layer pungetc.
10524 * left_in_line was decremented before preadbuffer(),
10525 * must inc next_to_pgetc: */
10526 g_parsefile->next_to_pgetc++;
Eric Andersencb57d552001-06-28 07:25:16 +000010527 return PEOF;
Denis Vlasenko727752d2008-11-28 03:41:47 +000010528 }
Eric Andersencb57d552001-06-28 07:25:16 +000010529
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010530 more = g_parsefile->left_in_buffer;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010531 if (more <= 0) {
Denis Vlasenko727752d2008-11-28 03:41:47 +000010532 flush_stdout_stderr();
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010533 again:
10534 more = preadfd();
10535 if (more <= 0) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010536 /* don't try reading again */
10537 g_parsefile->left_in_line = -99;
Denis Vlasenko727752d2008-11-28 03:41:47 +000010538 pgetc_debug("preadbuffer PEOF2");
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010539 g_parsefile->next_to_pgetc++;
Eric Andersencb57d552001-06-28 07:25:16 +000010540 return PEOF;
10541 }
10542 }
10543
Denis Vlasenko727752d2008-11-28 03:41:47 +000010544 /* Find out where's the end of line.
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010545 * Set g_parsefile->left_in_line
10546 * and g_parsefile->left_in_buffer acordingly.
Denis Vlasenko727752d2008-11-28 03:41:47 +000010547 * NUL chars are deleted.
10548 */
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010549 q = g_parsefile->next_to_pgetc;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010550 for (;;) {
Denis Vlasenko727752d2008-11-28 03:41:47 +000010551 char c;
Eric Andersencb57d552001-06-28 07:25:16 +000010552
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010553 more--;
Eric Andersenc470f442003-07-28 09:56:35 +000010554
Denis Vlasenko727752d2008-11-28 03:41:47 +000010555 c = *q;
10556 if (c == '\0') {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010557 memmove(q, q + 1, more);
Denis Vlasenko727752d2008-11-28 03:41:47 +000010558 } else {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010559 q++;
10560 if (c == '\n') {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010561 g_parsefile->left_in_line = q - g_parsefile->next_to_pgetc - 1;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010562 break;
10563 }
Eric Andersencb57d552001-06-28 07:25:16 +000010564 }
10565
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010566 if (more <= 0) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010567 g_parsefile->left_in_line = q - g_parsefile->next_to_pgetc - 1;
10568 if (g_parsefile->left_in_line < 0)
Eric Andersencb57d552001-06-28 07:25:16 +000010569 goto again;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010570 break;
Eric Andersencb57d552001-06-28 07:25:16 +000010571 }
10572 }
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010573 g_parsefile->left_in_buffer = more;
Eric Andersencb57d552001-06-28 07:25:16 +000010574
Eric Andersencb57d552001-06-28 07:25:16 +000010575 if (vflag) {
Denis Vlasenko727752d2008-11-28 03:41:47 +000010576 char save = *q;
10577 *q = '\0';
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010578 out2str(g_parsefile->next_to_pgetc);
Denis Vlasenko727752d2008-11-28 03:41:47 +000010579 *q = save;
Eric Andersencb57d552001-06-28 07:25:16 +000010580 }
10581
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010582 pgetc_debug("preadbuffer at %d:%p'%s'",
10583 g_parsefile->left_in_line,
10584 g_parsefile->next_to_pgetc,
10585 g_parsefile->next_to_pgetc);
Denys Vlasenkocd716832009-11-28 22:14:02 +010010586 return (unsigned char)*g_parsefile->next_to_pgetc++;
Eric Andersencb57d552001-06-28 07:25:16 +000010587}
10588
Denys Vlasenkoce332a22016-10-02 23:47:34 +020010589static void
10590nlprompt(void)
10591{
10592 g_parsefile->linno++;
10593 setprompt_if(doprompt, 2);
10594}
10595static void
10596nlnoprompt(void)
10597{
10598 g_parsefile->linno++;
10599 needprompt = doprompt;
10600}
10601
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010602static int
10603pgetc(void)
10604{
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010605 int c;
10606
10607 pgetc_debug("pgetc at %d:%p'%s'",
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010608 g_parsefile->left_in_line,
10609 g_parsefile->next_to_pgetc,
10610 g_parsefile->next_to_pgetc);
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010611 if (g_parsefile->unget)
10612 return g_parsefile->lastc[--g_parsefile->unget];
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010613
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010614 if (--g_parsefile->left_in_line >= 0)
Denys Vlasenko2fe66b12016-12-12 17:39:12 +010010615 c = (unsigned char)*g_parsefile->next_to_pgetc++;
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010616 else
10617 c = preadbuffer();
10618
10619 g_parsefile->lastc[1] = g_parsefile->lastc[0];
10620 g_parsefile->lastc[0] = c;
10621
10622 return c;
10623}
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010624
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010625#if ENABLE_ASH_ALIAS
10626static int
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010010627pgetc_without_PEOA(void)
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010628{
10629 int c;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010630 do {
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010631 pgetc_debug("pgetc at %d:%p'%s'",
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010632 g_parsefile->left_in_line,
10633 g_parsefile->next_to_pgetc,
10634 g_parsefile->next_to_pgetc);
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010635 c = pgetc();
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010636 } while (c == PEOA);
10637 return c;
10638}
10639#else
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010010640# define pgetc_without_PEOA() pgetc()
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010641#endif
10642
10643/*
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010644 * Undo a call to pgetc. Only two characters may be pushed back.
Eric Andersenc470f442003-07-28 09:56:35 +000010645 * PEOF may be pushed back.
10646 */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010647static void
Eric Andersenc470f442003-07-28 09:56:35 +000010648pungetc(void)
10649{
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010650 g_parsefile->unget++;
Eric Andersencb57d552001-06-28 07:25:16 +000010651}
10652
Denys Vlasenko73c3e072016-09-29 17:17:04 +020010653/* This one eats backslash+newline */
10654static int
10655pgetc_eatbnl(void)
10656{
10657 int c;
10658
10659 while ((c = pgetc()) == '\\') {
10660 if (pgetc() != '\n') {
10661 pungetc();
10662 break;
10663 }
10664
Denys Vlasenkoce332a22016-10-02 23:47:34 +020010665 nlprompt();
Denys Vlasenko73c3e072016-09-29 17:17:04 +020010666 }
10667
10668 return c;
10669}
10670
Denys Vlasenko216913c2018-04-02 12:35:04 +020010671struct synstack {
10672 smalluint syntax;
10673 uint8_t innerdq :1;
10674 uint8_t varpushed :1;
10675 uint8_t dblquote :1;
10676 int varnest; /* levels of variables expansion */
10677 int dqvarnest; /* levels of variables expansion within double quotes */
10678 int parenlevel; /* levels of parens in arithmetic */
10679 struct synstack *prev;
10680 struct synstack *next;
10681};
10682
10683static void
10684synstack_push(struct synstack **stack, struct synstack *next, int syntax)
10685{
10686 memset(next, 0, sizeof(*next));
10687 next->syntax = syntax;
10688 next->next = *stack;
10689 (*stack)->prev = next;
10690 *stack = next;
10691}
10692
10693static ALWAYS_INLINE void
10694synstack_pop(struct synstack **stack)
10695{
10696 *stack = (*stack)->next;
10697}
10698
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010699/*
10700 * To handle the "." command, a stack of input files is used. Pushfile
10701 * adds a new entry to the stack and popfile restores the previous level.
10702 */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010703static void
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010704pushfile(void)
Eric Andersenc470f442003-07-28 09:56:35 +000010705{
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010706 struct parsefile *pf;
10707
Denis Vlasenko597906c2008-02-20 16:38:54 +000010708 pf = ckzalloc(sizeof(*pf));
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010709 pf->prev = g_parsefile;
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010710 pf->pf_fd = -1;
Denis Vlasenko597906c2008-02-20 16:38:54 +000010711 /*pf->strpush = NULL; - ckzalloc did it */
10712 /*pf->basestrpush.prev = NULL;*/
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010713 /*pf->unget = 0;*/
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010714 g_parsefile = pf;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010715}
10716
10717static void
10718popfile(void)
10719{
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010720 struct parsefile *pf = g_parsefile;
Eric Andersenc470f442003-07-28 09:56:35 +000010721
Denys Vlasenko493b9ca2016-10-30 18:27:14 +010010722 if (pf == &basepf)
10723 return;
10724
Denis Vlasenkob012b102007-02-19 22:43:01 +000010725 INT_OFF;
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010726 if (pf->pf_fd >= 0)
10727 close(pf->pf_fd);
Denis Vlasenko60818682007-09-28 22:07:23 +000010728 free(pf->buf);
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010729 while (pf->strpush)
10730 popstring();
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010731 g_parsefile = pf->prev;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010732 free(pf);
Denis Vlasenkob012b102007-02-19 22:43:01 +000010733 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +000010734}
10735
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010736/*
10737 * Return to top level.
10738 */
10739static void
10740popallfiles(void)
10741{
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010742 while (g_parsefile != &basepf)
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010743 popfile();
10744}
10745
10746/*
10747 * Close the file(s) that the shell is reading commands from. Called
10748 * after a fork is done.
10749 */
10750static void
10751closescript(void)
10752{
10753 popallfiles();
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010754 if (g_parsefile->pf_fd > 0) {
10755 close(g_parsefile->pf_fd);
10756 g_parsefile->pf_fd = 0;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010757 }
10758}
10759
10760/*
10761 * Like setinputfile, but takes an open file descriptor. Call this with
10762 * interrupts off.
10763 */
10764static void
10765setinputfd(int fd, int push)
10766{
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010767 if (push) {
10768 pushfile();
Denis Vlasenko727752d2008-11-28 03:41:47 +000010769 g_parsefile->buf = NULL;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010770 }
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010771 g_parsefile->pf_fd = fd;
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010772 if (g_parsefile->buf == NULL)
10773 g_parsefile->buf = ckmalloc(IBUFSIZ);
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010774 g_parsefile->left_in_buffer = 0;
10775 g_parsefile->left_in_line = 0;
10776 g_parsefile->linno = 1;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010777}
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010778
Eric Andersenc470f442003-07-28 09:56:35 +000010779/*
10780 * Set the input to take input from a file. If push is set, push the
10781 * old input onto the stack first.
10782 */
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010783static int
10784setinputfile(const char *fname, int flags)
Eric Andersenc470f442003-07-28 09:56:35 +000010785{
10786 int fd;
Eric Andersenc470f442003-07-28 09:56:35 +000010787
Denis Vlasenkob012b102007-02-19 22:43:01 +000010788 INT_OFF;
Denys Vlasenko60fb98e2018-03-30 22:15:14 +020010789 fd = open(fname, O_RDONLY | O_CLOEXEC);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010790 if (fd < 0) {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010791 if (flags & INPUT_NOFILE_OK)
10792 goto out;
Denys Vlasenkob7adf7a2016-10-25 17:00:13 +020010793 exitstatus = 127;
Johannes Schindelin20a63b22017-08-22 22:03:17 +020010794 ash_msg_and_raise_perror("can't open '%s'", fname);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010795 }
Denys Vlasenko64774602016-10-26 15:24:30 +020010796 if (fd < 10)
10797 fd = savefd(fd);
Denys Vlasenko60fb98e2018-03-30 22:15:14 +020010798 else if (O_CLOEXEC == 0) /* old libc */
Denys Vlasenkoe19923f2016-10-26 15:38:44 +020010799 close_on_exec_on(fd);
Denys Vlasenko60fb98e2018-03-30 22:15:14 +020010800
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010801 setinputfd(fd, flags & INPUT_PUSH_FILE);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010802 out:
Denis Vlasenkob012b102007-02-19 22:43:01 +000010803 INT_ON;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010804 return fd;
Eric Andersenc470f442003-07-28 09:56:35 +000010805}
10806
Eric Andersencb57d552001-06-28 07:25:16 +000010807/*
10808 * Like setinputfile, but takes input from a string.
10809 */
Eric Andersenc470f442003-07-28 09:56:35 +000010810static void
10811setinputstring(char *string)
Eric Andersen62483552001-07-10 06:09:16 +000010812{
Denis Vlasenkob012b102007-02-19 22:43:01 +000010813 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +000010814 pushfile();
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010815 g_parsefile->next_to_pgetc = string;
10816 g_parsefile->left_in_line = strlen(string);
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010817 g_parsefile->buf = NULL;
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010818 g_parsefile->linno = 1;
Denis Vlasenkob012b102007-02-19 22:43:01 +000010819 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +000010820}
10821
10822
Denys Vlasenko70392332016-10-27 02:31:55 +020010823/*
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010824 * Routines to check for mail.
Eric Andersencb57d552001-06-28 07:25:16 +000010825 */
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010826
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010827#if ENABLE_ASH_MAIL
Eric Andersencb57d552001-06-28 07:25:16 +000010828
Denys Vlasenko23841622015-10-09 15:52:03 +020010829/* Hash of mtimes of mailboxes */
10830static unsigned mailtime_hash;
Eric Andersenc470f442003-07-28 09:56:35 +000010831/* Set if MAIL or MAILPATH is changed. */
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010832static smallint mail_var_path_changed;
Eric Andersencb57d552001-06-28 07:25:16 +000010833
Eric Andersencb57d552001-06-28 07:25:16 +000010834/*
Eric Andersenc470f442003-07-28 09:56:35 +000010835 * Print appropriate message(s) if mail has arrived.
10836 * If mail_var_path_changed is set,
10837 * then the value of MAIL has mail_var_path_changed,
10838 * so we just update the values.
Eric Andersencb57d552001-06-28 07:25:16 +000010839 */
Eric Andersenc470f442003-07-28 09:56:35 +000010840static void
10841chkmail(void)
Eric Andersencb57d552001-06-28 07:25:16 +000010842{
Eric Andersencb57d552001-06-28 07:25:16 +000010843 const char *mpath;
10844 char *p;
10845 char *q;
Denys Vlasenko23841622015-10-09 15:52:03 +020010846 unsigned new_hash;
Eric Andersencb57d552001-06-28 07:25:16 +000010847 struct stackmark smark;
10848 struct stat statb;
10849
Eric Andersencb57d552001-06-28 07:25:16 +000010850 setstackmark(&smark);
Eric Andersenc470f442003-07-28 09:56:35 +000010851 mpath = mpathset() ? mpathval() : mailval();
Denys Vlasenko23841622015-10-09 15:52:03 +020010852 new_hash = 0;
10853 for (;;) {
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020010854 p = path_advance(&mpath, nullstr);
Eric Andersencb57d552001-06-28 07:25:16 +000010855 if (p == NULL)
10856 break;
10857 if (*p == '\0')
10858 continue;
Denis Vlasenkof7d56652008-03-25 05:51:41 +000010859 for (q = p; *q; q++)
10860 continue;
Denis Vlasenkoa7189f02006-11-17 20:29:00 +000010861#if DEBUG
Eric Andersencb57d552001-06-28 07:25:16 +000010862 if (q[-1] != '/')
10863 abort();
10864#endif
Eric Andersenc470f442003-07-28 09:56:35 +000010865 q[-1] = '\0'; /* delete trailing '/' */
10866 if (stat(p, &statb) < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +000010867 continue;
Eric Andersencb57d552001-06-28 07:25:16 +000010868 }
Denys Vlasenko23841622015-10-09 15:52:03 +020010869 /* Very simplistic "hash": just a sum of all mtimes */
10870 new_hash += (unsigned)statb.st_mtime;
10871 }
10872 if (!mail_var_path_changed && mailtime_hash != new_hash) {
Denys Vlasenko4cd99e72015-10-09 16:02:53 +020010873 if (mailtime_hash != 0)
10874 out2str("you have mail\n");
Denys Vlasenko23841622015-10-09 15:52:03 +020010875 mailtime_hash = new_hash;
Eric Andersencb57d552001-06-28 07:25:16 +000010876 }
Eric Andersenc470f442003-07-28 09:56:35 +000010877 mail_var_path_changed = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010878 popstackmark(&smark);
10879}
Eric Andersencb57d552001-06-28 07:25:16 +000010880
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010881static void FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010882changemail(const char *val UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000010883{
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010884 mail_var_path_changed = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000010885}
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010886
Denis Vlasenko131ae172007-02-18 13:00:19 +000010887#endif /* ASH_MAIL */
Eric Andersenc470f442003-07-28 09:56:35 +000010888
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010889
10890/* ============ ??? */
10891
Eric Andersencb57d552001-06-28 07:25:16 +000010892/*
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010893 * Set the shell parameters.
Eric Andersencb57d552001-06-28 07:25:16 +000010894 */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010895static void
10896setparam(char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000010897{
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010898 char **newparam;
10899 char **ap;
10900 int nparam;
Eric Andersencb57d552001-06-28 07:25:16 +000010901
Denis Vlasenkof7d56652008-03-25 05:51:41 +000010902 for (nparam = 0; argv[nparam]; nparam++)
10903 continue;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010904 ap = newparam = ckmalloc((nparam + 1) * sizeof(*ap));
10905 while (*argv) {
10906 *ap++ = ckstrdup(*argv++);
Eric Andersencb57d552001-06-28 07:25:16 +000010907 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010908 *ap = NULL;
10909 freeparam(&shellparam);
Denis Vlasenko01631112007-12-16 17:20:38 +000010910 shellparam.malloced = 1;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010911 shellparam.nparam = nparam;
10912 shellparam.p = newparam;
10913#if ENABLE_ASH_GETOPTS
10914 shellparam.optind = 1;
10915 shellparam.optoff = -1;
10916#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010917}
10918
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010919/*
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010920 * Process shell options. The global variable argptr contains a pointer
10921 * to the argument list; we advance it past the options.
Denis Vlasenko94e87bc2008-02-14 16:51:58 +000010922 *
10923 * SUSv3 section 2.8.1 "Consequences of Shell Errors" says:
10924 * For a non-interactive shell, an error condition encountered
10925 * by a special built-in ... shall cause the shell to write a diagnostic message
10926 * to standard error and exit as shown in the following table:
Denis Vlasenko56244732008-02-17 15:14:04 +000010927 * Error Special Built-In
Denis Vlasenko94e87bc2008-02-14 16:51:58 +000010928 * ...
10929 * Utility syntax error (option or operand error) Shall exit
10930 * ...
10931 * However, in bug 1142 (http://busybox.net/bugs/view.php?id=1142)
10932 * we see that bash does not do that (set "finishes" with error code 1 instead,
10933 * and shell continues), and people rely on this behavior!
10934 * Testcase:
10935 * set -o barfoo 2>/dev/null
10936 * echo $?
10937 *
10938 * Oh well. Let's mimic that.
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010939 */
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010940static int
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010941plus_minus_o(char *name, int val)
Eric Andersen62483552001-07-10 06:09:16 +000010942{
10943 int i;
10944
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010945 if (name) {
10946 for (i = 0; i < NOPTS; i++) {
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000010947 if (strcmp(name, optnames(i)) == 0) {
Eric Andersenc470f442003-07-28 09:56:35 +000010948 optlist[i] = val;
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010949 return 0;
Eric Andersen62483552001-07-10 06:09:16 +000010950 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010951 }
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010952 ash_msg("illegal option %co %s", val ? '-' : '+', name);
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010953 return 1;
Eric Andersen62483552001-07-10 06:09:16 +000010954 }
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000010955 for (i = 0; i < NOPTS; i++) {
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010956 if (val) {
10957 out1fmt("%-16s%s\n", optnames(i), optlist[i] ? "on" : "off");
10958 } else {
10959 out1fmt("set %co %s\n", optlist[i] ? '-' : '+', optnames(i));
10960 }
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000010961 }
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010962 return 0;
Eric Andersen62483552001-07-10 06:09:16 +000010963}
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010964static void
10965setoption(int flag, int val)
10966{
10967 int i;
10968
10969 for (i = 0; i < NOPTS; i++) {
10970 if (optletters(i) == flag) {
10971 optlist[i] = val;
10972 return;
10973 }
10974 }
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010975 ash_msg_and_raise_error("illegal option %c%c", val ? '-' : '+', flag);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010976 /* NOTREACHED */
10977}
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010978static int
Denys Vlasenkoec05df12017-07-31 19:43:47 +020010979options(int cmdline, int *login_sh)
Eric Andersencb57d552001-06-28 07:25:16 +000010980{
10981 char *p;
10982 int val;
10983 int c;
10984
10985 if (cmdline)
10986 minusc = NULL;
10987 while ((p = *argptr) != NULL) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010988 c = *p++;
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010989 if (c != '-' && c != '+')
10990 break;
10991 argptr++;
10992 val = 0; /* val = 0 if c == '+' */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010993 if (c == '-') {
Eric Andersencb57d552001-06-28 07:25:16 +000010994 val = 1;
Denis Vlasenko9f739442006-12-16 23:49:13 +000010995 if (p[0] == '\0' || LONE_DASH(p)) {
Eric Andersen2870d962001-07-02 17:27:21 +000010996 if (!cmdline) {
10997 /* "-" means turn off -x and -v */
10998 if (p[0] == '\0')
10999 xflag = vflag = 0;
11000 /* "--" means reset params */
11001 else if (*argptr == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +000011002 setparam(argptr);
Eric Andersen2870d962001-07-02 17:27:21 +000011003 }
Denys Vlasenkob0b83432011-03-07 12:34:59 +010011004 break; /* "-" or "--" terminates options */
Eric Andersencb57d552001-06-28 07:25:16 +000011005 }
Eric Andersencb57d552001-06-28 07:25:16 +000011006 }
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000011007 /* first char was + or - */
Eric Andersencb57d552001-06-28 07:25:16 +000011008 while ((c = *p++) != '\0') {
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000011009 /* bash 3.2 indeed handles -c CMD and +c CMD the same */
Eric Andersencb57d552001-06-28 07:25:16 +000011010 if (c == 'c' && cmdline) {
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000011011 minusc = p; /* command is after shell args */
Eric Andersencb57d552001-06-28 07:25:16 +000011012 } else if (c == 'o') {
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000011013 if (plus_minus_o(*argptr, val)) {
Denis Vlasenko28bf6712008-02-14 15:01:47 +000011014 /* it already printed err message */
11015 return 1; /* error */
11016 }
Eric Andersencb57d552001-06-28 07:25:16 +000011017 if (*argptr)
11018 argptr++;
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000011019 } else if (cmdline && (c == 'l')) { /* -l or +l == --login */
Denys Vlasenkoec05df12017-07-31 19:43:47 +020011020 if (login_sh)
11021 *login_sh = 1;
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000011022 /* bash does not accept +-login, we also won't */
11023 } else if (cmdline && val && (c == '-')) { /* long options */
Denys Vlasenkoec05df12017-07-31 19:43:47 +020011024 if (strcmp(p, "login") == 0) {
11025 if (login_sh)
11026 *login_sh = 1;
11027 }
Robert Griebl64f70cc2002-05-14 23:22:06 +000011028 break;
Eric Andersencb57d552001-06-28 07:25:16 +000011029 } else {
11030 setoption(c, val);
11031 }
11032 }
11033 }
Denis Vlasenko28bf6712008-02-14 15:01:47 +000011034 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +000011035}
11036
Eric Andersencb57d552001-06-28 07:25:16 +000011037/*
Eric Andersencb57d552001-06-28 07:25:16 +000011038 * The shift builtin command.
11039 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020011040static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000011041shiftcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000011042{
11043 int n;
11044 char **ap1, **ap2;
11045
11046 n = 1;
Denis Vlasenko68404f12008-03-17 09:00:54 +000011047 if (argv[1])
Eric Andersencb57d552001-06-28 07:25:16 +000011048 n = number(argv[1]);
11049 if (n > shellparam.nparam)
Ingo van Lil9c8e94b2018-01-05 15:04:23 +010011050 return 1;
Denis Vlasenkob012b102007-02-19 22:43:01 +000011051 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +000011052 shellparam.nparam -= n;
Denis Vlasenko2da584f2007-02-19 22:44:05 +000011053 for (ap1 = shellparam.p; --n >= 0; ap1++) {
Denis Vlasenko01631112007-12-16 17:20:38 +000011054 if (shellparam.malloced)
Denis Vlasenkob012b102007-02-19 22:43:01 +000011055 free(*ap1);
Eric Andersencb57d552001-06-28 07:25:16 +000011056 }
11057 ap2 = shellparam.p;
Denis Vlasenkof7d56652008-03-25 05:51:41 +000011058 while ((*ap2++ = *ap1++) != NULL)
11059 continue;
Denis Vlasenko131ae172007-02-18 13:00:19 +000011060#if ENABLE_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +000011061 shellparam.optind = 1;
11062 shellparam.optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +000011063#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +000011064 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +000011065 return 0;
11066}
11067
Eric Andersencb57d552001-06-28 07:25:16 +000011068/*
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011069 * POSIX requires that 'set' (but not export or readonly) output the
11070 * variables in lexicographic order - by the locale's collating order (sigh).
11071 * Maybe we could keep them in an ordered balanced binary tree
11072 * instead of hashed lists.
11073 * For now just roll 'em through qsort for printing...
11074 */
11075static int
11076showvars(const char *sep_prefix, int on, int off)
11077{
11078 const char *sep;
11079 char **ep, **epend;
11080
Denys Vlasenkoa5060b82017-11-03 14:16:25 +010011081 ep = listvars(on, off, /*strlist:*/ NULL, &epend);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011082 qsort(ep, epend - ep, sizeof(char *), vpcmp);
11083
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000011084 sep = *sep_prefix ? " " : sep_prefix;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011085
11086 for (; ep < epend; ep++) {
11087 const char *p;
11088 const char *q;
11089
Denys Vlasenko9c143ce2017-11-02 12:56:24 +010011090 p = endofname(*ep);
11091/* Used to have simple "p = strchrnul(*ep, '=')" here instead, but this
11092 * makes "export -p" to have output not suitable for "eval":
11093 * import os
11094 * os.environ["test-test"]="test"
11095 * if os.fork() == 0:
11096 * os.execv("ash", [ 'ash', '-c', 'eval $(export -p); echo OK' ]) # fixes this
11097 * os.execv("ash", [ 'ash', '-c', 'env | grep test-test' ])
11098 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011099 q = nullstr;
Denys Vlasenko9c143ce2017-11-02 12:56:24 +010011100 if (*p == '=')
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011101 q = single_quote(++p);
11102 out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
11103 }
11104 return 0;
11105}
11106
11107/*
Eric Andersencb57d552001-06-28 07:25:16 +000011108 * The set command builtin.
11109 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020011110static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000011111setcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +000011112{
Denis Vlasenko28bf6712008-02-14 15:01:47 +000011113 int retval;
11114
Denis Vlasenko68404f12008-03-17 09:00:54 +000011115 if (!argv[1])
Eric Andersenc470f442003-07-28 09:56:35 +000011116 return showvars(nullstr, 0, VUNSET);
Denys Vlasenkob0b83432011-03-07 12:34:59 +010011117
Denis Vlasenkob012b102007-02-19 22:43:01 +000011118 INT_OFF;
Denys Vlasenkoec05df12017-07-31 19:43:47 +020011119 retval = options(/*cmdline:*/ 0, NULL);
Denys Vlasenkob0b83432011-03-07 12:34:59 +010011120 if (retval == 0) { /* if no parse error... */
Denis Vlasenko28bf6712008-02-14 15:01:47 +000011121 optschanged();
11122 if (*argptr != NULL) {
11123 setparam(argptr);
11124 }
Eric Andersencb57d552001-06-28 07:25:16 +000011125 }
Denis Vlasenkob012b102007-02-19 22:43:01 +000011126 INT_ON;
Denis Vlasenko28bf6712008-02-14 15:01:47 +000011127 return retval;
Eric Andersencb57d552001-06-28 07:25:16 +000011128}
11129
Denis Vlasenko131ae172007-02-18 13:00:19 +000011130#if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020011131static void FAST_FUNC
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000011132change_random(const char *value)
Eric Andersenef02f822004-03-11 13:34:24 +000011133{
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020011134 uint32_t t;
11135
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011136 if (value == NULL) {
Eric Andersen16767e22004-03-16 05:14:10 +000011137 /* "get", generate */
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020011138 t = next_random(&random_gen);
Eric Andersen16767e22004-03-16 05:14:10 +000011139 /* set without recursion */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +020011140 setvar(vrandom.var_text, utoa(t), VNOFUNC);
Eric Andersen16767e22004-03-16 05:14:10 +000011141 vrandom.flags &= ~VNOFUNC;
11142 } else {
11143 /* set/reset */
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020011144 t = strtoul(value, NULL, 10);
11145 INIT_RANDOM_T(&random_gen, (t ? t : 1), t);
Eric Andersen16767e22004-03-16 05:14:10 +000011146 }
Eric Andersenef02f822004-03-11 13:34:24 +000011147}
Eric Andersen16767e22004-03-16 05:14:10 +000011148#endif
11149
Denis Vlasenko131ae172007-02-18 13:00:19 +000011150#if ENABLE_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +000011151static int
Denys Vlasenko35c2a132016-10-26 17:34:26 +020011152getopts(char *optstr, char *optvar, char **optfirst)
Eric Andersencb57d552001-06-28 07:25:16 +000011153{
11154 char *p, *q;
11155 char c = '?';
11156 int done = 0;
Denys Vlasenko9c541002015-10-07 15:44:36 +020011157 char sbuf[2];
Eric Andersena48b0a32003-10-22 10:56:47 +000011158 char **optnext;
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020011159 int ind = shellparam.optind;
11160 int off = shellparam.optoff;
Eric Andersencb57d552001-06-28 07:25:16 +000011161
Denys Vlasenko9c541002015-10-07 15:44:36 +020011162 sbuf[1] = '\0';
11163
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020011164 shellparam.optind = -1;
11165 optnext = optfirst + ind - 1;
Eric Andersena48b0a32003-10-22 10:56:47 +000011166
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020011167 if (ind <= 1 || off < 0 || (int)strlen(optnext[-1]) < off)
Eric Andersencb57d552001-06-28 07:25:16 +000011168 p = NULL;
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020011169 else
11170 p = optnext[-1] + off;
Eric Andersencb57d552001-06-28 07:25:16 +000011171 if (p == NULL || *p == '\0') {
11172 /* Current word is done, advance */
Eric Andersencb57d552001-06-28 07:25:16 +000011173 p = *optnext;
11174 if (p == NULL || *p != '-' || *++p == '\0') {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011175 atend:
Denys Vlasenko9832bba2017-08-15 15:44:41 +020011176 unsetvar("OPTARG");
Eric Andersencb57d552001-06-28 07:25:16 +000011177 p = NULL;
11178 done = 1;
11179 goto out;
11180 }
11181 optnext++;
Denis Vlasenko9f739442006-12-16 23:49:13 +000011182 if (LONE_DASH(p)) /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +000011183 goto atend;
11184 }
11185
11186 c = *p++;
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +000011187 for (q = optstr; *q != c;) {
Eric Andersencb57d552001-06-28 07:25:16 +000011188 if (*q == '\0') {
Denys Vlasenko9832bba2017-08-15 15:44:41 +020011189 /* OPTERR is a bashism */
11190 const char *cp = lookupvar("OPTERR");
11191 if ((cp && LONE_CHAR(cp, '0'))
11192 || (optstr[0] == ':')
11193 ) {
Denys Vlasenko9c541002015-10-07 15:44:36 +020011194 sbuf[0] = c;
11195 /*sbuf[1] = '\0'; - already is */
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020011196 setvar0("OPTARG", sbuf);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011197 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000011198 fprintf(stderr, "Illegal option -%c\n", c);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011199 unsetvar("OPTARG");
Eric Andersencb57d552001-06-28 07:25:16 +000011200 }
11201 c = '?';
Eric Andersenc470f442003-07-28 09:56:35 +000011202 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +000011203 }
11204 if (*++q == ':')
11205 q++;
11206 }
11207
11208 if (*++q == ':') {
11209 if (*p == '\0' && (p = *optnext) == NULL) {
Denys Vlasenko9832bba2017-08-15 15:44:41 +020011210 /* OPTERR is a bashism */
11211 const char *cp = lookupvar("OPTERR");
11212 if ((cp && LONE_CHAR(cp, '0'))
11213 || (optstr[0] == ':')
11214 ) {
Denys Vlasenko9c541002015-10-07 15:44:36 +020011215 sbuf[0] = c;
11216 /*sbuf[1] = '\0'; - already is */
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020011217 setvar0("OPTARG", sbuf);
Eric Andersencb57d552001-06-28 07:25:16 +000011218 c = ':';
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011219 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000011220 fprintf(stderr, "No arg for -%c option\n", c);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011221 unsetvar("OPTARG");
Eric Andersencb57d552001-06-28 07:25:16 +000011222 c = '?';
11223 }
Eric Andersenc470f442003-07-28 09:56:35 +000011224 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +000011225 }
11226
11227 if (p == *optnext)
11228 optnext++;
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020011229 setvar0("OPTARG", p);
Eric Andersencb57d552001-06-28 07:25:16 +000011230 p = NULL;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011231 } else
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020011232 setvar0("OPTARG", nullstr);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011233 out:
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020011234 ind = optnext - optfirst + 1;
11235 setvar("OPTIND", itoa(ind), VNOFUNC);
Denys Vlasenko9c541002015-10-07 15:44:36 +020011236 sbuf[0] = c;
11237 /*sbuf[1] = '\0'; - already is */
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020011238 setvar0(optvar, sbuf);
11239
11240 shellparam.optoff = p ? p - *(optnext - 1) : -1;
11241 shellparam.optind = ind;
11242
Eric Andersencb57d552001-06-28 07:25:16 +000011243 return done;
11244}
Eric Andersenc470f442003-07-28 09:56:35 +000011245
11246/*
11247 * The getopts builtin. Shellparam.optnext points to the next argument
11248 * to be processed. Shellparam.optptr points to the next character to
11249 * be processed in the current argument. If shellparam.optnext is NULL,
11250 * then it's the first time getopts has been called.
11251 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020011252static int FAST_FUNC
Eric Andersenc470f442003-07-28 09:56:35 +000011253getoptscmd(int argc, char **argv)
11254{
11255 char **optbase;
11256
11257 if (argc < 3)
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +000011258 ash_msg_and_raise_error("usage: getopts optstring var [arg]");
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011259 if (argc == 3) {
Eric Andersenc470f442003-07-28 09:56:35 +000011260 optbase = shellparam.p;
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020011261 if ((unsigned)shellparam.optind > shellparam.nparam + 1) {
Eric Andersenc470f442003-07-28 09:56:35 +000011262 shellparam.optind = 1;
11263 shellparam.optoff = -1;
11264 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011265 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000011266 optbase = &argv[3];
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020011267 if ((unsigned)shellparam.optind > argc - 2) {
Eric Andersenc470f442003-07-28 09:56:35 +000011268 shellparam.optind = 1;
11269 shellparam.optoff = -1;
11270 }
11271 }
11272
Denys Vlasenko35c2a132016-10-26 17:34:26 +020011273 return getopts(argv[1], argv[2], optbase);
Eric Andersenc470f442003-07-28 09:56:35 +000011274}
Denis Vlasenko131ae172007-02-18 13:00:19 +000011275#endif /* ASH_GETOPTS */
Eric Andersencb57d552001-06-28 07:25:16 +000011276
Eric Andersencb57d552001-06-28 07:25:16 +000011277
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011278/* ============ Shell parser */
Eric Andersencb57d552001-06-28 07:25:16 +000011279
Denis Vlasenkob07a4962008-06-22 13:16:23 +000011280struct heredoc {
11281 struct heredoc *next; /* next here document in list */
11282 union node *here; /* redirection node */
11283 char *eofmark; /* string indicating end of input */
11284 smallint striptabs; /* if set, strip leading tabs */
11285};
11286
11287static smallint tokpushback; /* last token pushed back */
Denis Vlasenkob07a4962008-06-22 13:16:23 +000011288static smallint quoteflag; /* set if (part of) last token was quoted */
11289static token_id_t lasttoken; /* last token read (integer id Txxx) */
11290static struct heredoc *heredoclist; /* list of here documents to read */
11291static char *wordtext; /* text of last word returned by readtoken */
11292static struct nodelist *backquotelist;
11293static union node *redirnode;
11294static struct heredoc *heredoc;
Denis Vlasenko99eb8502007-02-23 21:09:49 +000011295
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020011296static const char *
11297tokname(char *buf, int tok)
11298{
11299 if (tok < TSEMI)
Denys Vlasenko888527c2016-10-02 16:54:17 +020011300 return tokname_array[tok];
11301 sprintf(buf, "\"%s\"", tokname_array[tok]);
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020011302 return buf;
11303}
11304
11305/* raise_error_unexpected_syntax:
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011306 * Called when an unexpected token is read during the parse. The argument
11307 * is the token that is expected, or -1 if more than one type of token can
11308 * occur at this point.
11309 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000011310static void raise_error_unexpected_syntax(int) NORETURN;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011311static void
11312raise_error_unexpected_syntax(int token)
11313{
11314 char msg[64];
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020011315 char buf[16];
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011316 int l;
11317
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020011318 l = sprintf(msg, "unexpected %s", tokname(buf, lasttoken));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011319 if (token >= 0)
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020011320 sprintf(msg + l, " (expecting %s)", tokname(buf, token));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011321 raise_error_syntax(msg);
11322 /* NOTREACHED */
11323}
Eric Andersencb57d552001-06-28 07:25:16 +000011324
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011325/* parsing is heavily cross-recursive, need these forward decls */
11326static union node *andor(void);
11327static union node *pipeline(void);
11328static union node *parse_command(void);
11329static void parseheredoc(void);
Ron Yorstonc0e00762015-10-29 11:30:55 +000011330static int peektoken(void);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011331static int readtoken(void);
Eric Andersencb57d552001-06-28 07:25:16 +000011332
Eric Andersenc470f442003-07-28 09:56:35 +000011333static union node *
11334list(int nlflag)
Eric Andersencb57d552001-06-28 07:25:16 +000011335{
11336 union node *n1, *n2, *n3;
11337 int tok;
11338
Eric Andersencb57d552001-06-28 07:25:16 +000011339 n1 = NULL;
11340 for (;;) {
Ron Yorstonc0e00762015-10-29 11:30:55 +000011341 switch (peektoken()) {
11342 case TNL:
11343 if (!(nlflag & 1))
11344 break;
11345 parseheredoc();
11346 return n1;
11347
11348 case TEOF:
11349 if (!n1 && (nlflag & 1))
11350 n1 = NODE_EOF;
11351 parseheredoc();
11352 return n1;
11353 }
11354
11355 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Denys Vlasenko888527c2016-10-02 16:54:17 +020011356 if (nlflag == 2 && ((1 << peektoken()) & tokendlist))
Ron Yorstonc0e00762015-10-29 11:30:55 +000011357 return n1;
11358 nlflag |= 2;
11359
Eric Andersencb57d552001-06-28 07:25:16 +000011360 n2 = andor();
11361 tok = readtoken();
11362 if (tok == TBACKGND) {
Eric Andersenc470f442003-07-28 09:56:35 +000011363 if (n2->type == NPIPE) {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +000011364 n2->npipe.pipe_backgnd = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011365 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000011366 if (n2->type != NREDIR) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011367 n3 = stzalloc(sizeof(struct nredir));
Eric Andersenc470f442003-07-28 09:56:35 +000011368 n3->nredir.n = n2;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011369 /*n3->nredir.redirect = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011370 n2 = n3;
11371 }
11372 n2->type = NBACKGND;
Eric Andersencb57d552001-06-28 07:25:16 +000011373 }
11374 }
11375 if (n1 == NULL) {
11376 n1 = n2;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011377 } else {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011378 n3 = stzalloc(sizeof(struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +000011379 n3->type = NSEMI;
11380 n3->nbinary.ch1 = n1;
11381 n3->nbinary.ch2 = n2;
11382 n1 = n3;
11383 }
11384 switch (tok) {
Ron Yorstonc0e00762015-10-29 11:30:55 +000011385 case TNL:
11386 case TEOF:
11387 tokpushback = 1;
11388 /* fall through */
Eric Andersencb57d552001-06-28 07:25:16 +000011389 case TBACKGND:
11390 case TSEMI:
Eric Andersencb57d552001-06-28 07:25:16 +000011391 break;
Eric Andersencb57d552001-06-28 07:25:16 +000011392 default:
Ron Yorstonc0e00762015-10-29 11:30:55 +000011393 if ((nlflag & 1))
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011394 raise_error_unexpected_syntax(-1);
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011395 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011396 return n1;
11397 }
11398 }
11399}
11400
Eric Andersenc470f442003-07-28 09:56:35 +000011401static union node *
11402andor(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011403{
Eric Andersencb57d552001-06-28 07:25:16 +000011404 union node *n1, *n2, *n3;
11405 int t;
11406
Eric Andersencb57d552001-06-28 07:25:16 +000011407 n1 = pipeline();
11408 for (;;) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011409 t = readtoken();
11410 if (t == TAND) {
Eric Andersencb57d552001-06-28 07:25:16 +000011411 t = NAND;
11412 } else if (t == TOR) {
11413 t = NOR;
11414 } else {
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011415 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011416 return n1;
11417 }
Eric Andersenc470f442003-07-28 09:56:35 +000011418 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000011419 n2 = pipeline();
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011420 n3 = stzalloc(sizeof(struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +000011421 n3->type = t;
11422 n3->nbinary.ch1 = n1;
11423 n3->nbinary.ch2 = n2;
11424 n1 = n3;
11425 }
11426}
11427
Eric Andersenc470f442003-07-28 09:56:35 +000011428static union node *
11429pipeline(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011430{
Eric Andersencb57d552001-06-28 07:25:16 +000011431 union node *n1, *n2, *pipenode;
11432 struct nodelist *lp, *prev;
11433 int negate;
11434
11435 negate = 0;
11436 TRACE(("pipeline: entered\n"));
11437 if (readtoken() == TNOT) {
11438 negate = !negate;
Eric Andersenc470f442003-07-28 09:56:35 +000011439 checkkwd = CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000011440 } else
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011441 tokpushback = 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011442 n1 = parse_command();
Eric Andersencb57d552001-06-28 07:25:16 +000011443 if (readtoken() == TPIPE) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011444 pipenode = stzalloc(sizeof(struct npipe));
Eric Andersencb57d552001-06-28 07:25:16 +000011445 pipenode->type = NPIPE;
Denis Vlasenko2dc240c2008-07-24 06:07:50 +000011446 /*pipenode->npipe.pipe_backgnd = 0; - stzalloc did it */
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011447 lp = stzalloc(sizeof(struct nodelist));
Eric Andersencb57d552001-06-28 07:25:16 +000011448 pipenode->npipe.cmdlist = lp;
11449 lp->n = n1;
11450 do {
11451 prev = lp;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011452 lp = stzalloc(sizeof(struct nodelist));
Eric Andersenc470f442003-07-28 09:56:35 +000011453 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011454 lp->n = parse_command();
Eric Andersencb57d552001-06-28 07:25:16 +000011455 prev->next = lp;
11456 } while (readtoken() == TPIPE);
11457 lp->next = NULL;
11458 n1 = pipenode;
11459 }
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011460 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011461 if (negate) {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011462 n2 = stzalloc(sizeof(struct nnot));
Eric Andersencb57d552001-06-28 07:25:16 +000011463 n2->type = NNOT;
11464 n2->nnot.com = n1;
11465 return n2;
Denis Vlasenko2da584f2007-02-19 22:44:05 +000011466 }
11467 return n1;
Eric Andersencb57d552001-06-28 07:25:16 +000011468}
11469
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011470static union node *
11471makename(void)
11472{
11473 union node *n;
11474
Denis Vlasenko597906c2008-02-20 16:38:54 +000011475 n = stzalloc(sizeof(struct narg));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011476 n->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011477 /*n->narg.next = NULL; - stzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011478 n->narg.text = wordtext;
11479 n->narg.backquote = backquotelist;
11480 return n;
11481}
11482
11483static void
11484fixredir(union node *n, const char *text, int err)
11485{
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000011486 int fd;
11487
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011488 TRACE(("Fix redir %s %d\n", text, err));
11489 if (!err)
11490 n->ndup.vname = NULL;
11491
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000011492 fd = bb_strtou(text, NULL, 10);
11493 if (!errno && fd >= 0)
11494 n->ndup.dupfd = fd;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011495 else if (LONE_DASH(text))
11496 n->ndup.dupfd = -1;
11497 else {
11498 if (err)
Denis Vlasenko559691a2008-10-05 18:39:31 +000011499 raise_error_syntax("bad fd number");
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011500 n->ndup.vname = makename();
11501 }
11502}
11503
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011504static void
11505parsefname(void)
11506{
11507 union node *n = redirnode;
11508
Denys Vlasenkoa7328982017-07-29 19:57:28 +020011509 if (n->type == NHERE)
11510 checkkwd = CHKEOFMARK;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011511 if (readtoken() != TWORD)
11512 raise_error_unexpected_syntax(-1);
11513 if (n->type == NHERE) {
11514 struct heredoc *here = heredoc;
11515 struct heredoc *p;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011516
11517 if (quoteflag == 0)
11518 n->type = NXHERE;
11519 TRACE(("Here document %d\n", n->type));
Denys Vlasenko740058b2018-01-09 17:01:00 +010011520 rmescapes(wordtext, 0, NULL);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011521 here->eofmark = wordtext;
11522 here->next = NULL;
11523 if (heredoclist == NULL)
11524 heredoclist = here;
11525 else {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011526 for (p = heredoclist; p->next; p = p->next)
11527 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011528 p->next = here;
11529 }
11530 } else if (n->type == NTOFD || n->type == NFROMFD) {
11531 fixredir(n, wordtext, 0);
11532 } else {
11533 n->nfile.fname = makename();
11534 }
11535}
Eric Andersencb57d552001-06-28 07:25:16 +000011536
Eric Andersenc470f442003-07-28 09:56:35 +000011537static union node *
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011538simplecmd(void)
11539{
11540 union node *args, **app;
11541 union node *n = NULL;
11542 union node *vars, **vpp;
11543 union node **rpp, *redir;
11544 int savecheckkwd;
Denys Vlasenko675d24a2018-01-27 22:02:05 +010011545 int savelinno;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011546#if BASH_TEST2
Denis Vlasenko80591b02008-03-25 07:49:43 +000011547 smallint double_brackets_flag = 0;
11548#endif
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011549 IF_BASH_FUNCTION(smallint function_flag = 0;)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011550
11551 args = NULL;
11552 app = &args;
11553 vars = NULL;
11554 vpp = &vars;
11555 redir = NULL;
11556 rpp = &redir;
11557
11558 savecheckkwd = CHKALIAS;
Denys Vlasenko675d24a2018-01-27 22:02:05 +010011559 savelinno = g_parsefile->linno;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011560 for (;;) {
Denis Vlasenko80591b02008-03-25 07:49:43 +000011561 int t;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011562 checkkwd = savecheckkwd;
Denis Vlasenko80591b02008-03-25 07:49:43 +000011563 t = readtoken();
11564 switch (t) {
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011565#if BASH_FUNCTION
Ron Yorston95ebcf72015-11-03 09:42:23 +000011566 case TFUNCTION:
11567 if (peektoken() != TWORD)
11568 raise_error_unexpected_syntax(TWORD);
11569 function_flag = 1;
11570 break;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011571#endif
11572#if BASH_TEST2
Denis Vlasenko80591b02008-03-25 07:49:43 +000011573 case TAND: /* "&&" */
11574 case TOR: /* "||" */
11575 if (!double_brackets_flag) {
11576 tokpushback = 1;
11577 goto out;
11578 }
11579 wordtext = (char *) (t == TAND ? "-a" : "-o");
11580#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011581 case TWORD:
Denis Vlasenko597906c2008-02-20 16:38:54 +000011582 n = stzalloc(sizeof(struct narg));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011583 n->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011584 /*n->narg.next = NULL; - stzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011585 n->narg.text = wordtext;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011586#if BASH_TEST2
Denis Vlasenko80591b02008-03-25 07:49:43 +000011587 if (strcmp("[[", wordtext) == 0)
11588 double_brackets_flag = 1;
11589 else if (strcmp("]]", wordtext) == 0)
11590 double_brackets_flag = 0;
11591#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011592 n->narg.backquote = backquotelist;
11593 if (savecheckkwd && isassignment(wordtext)) {
11594 *vpp = n;
11595 vpp = &n->narg.next;
11596 } else {
11597 *app = n;
11598 app = &n->narg.next;
11599 savecheckkwd = 0;
11600 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011601#if BASH_FUNCTION
Ron Yorston95ebcf72015-11-03 09:42:23 +000011602 if (function_flag) {
11603 checkkwd = CHKNL | CHKKWD;
11604 switch (peektoken()) {
11605 case TBEGIN:
11606 case TIF:
11607 case TCASE:
11608 case TUNTIL:
11609 case TWHILE:
11610 case TFOR:
11611 goto do_func;
11612 case TLP:
11613 function_flag = 0;
11614 break;
11615 case TWORD:
11616 if (strcmp("[[", wordtext) == 0)
11617 goto do_func;
11618 /* fall through */
11619 default:
11620 raise_error_unexpected_syntax(-1);
11621 }
11622 }
11623#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011624 break;
11625 case TREDIR:
11626 *rpp = n = redirnode;
11627 rpp = &n->nfile.next;
11628 parsefname(); /* read name of redirection file */
11629 break;
11630 case TLP:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011631 IF_BASH_FUNCTION(do_func:)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011632 if (args && app == &args->narg.next
11633 && !vars && !redir
11634 ) {
11635 struct builtincmd *bcmd;
11636 const char *name;
11637
11638 /* We have a function */
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011639 if (IF_BASH_FUNCTION(!function_flag &&) readtoken() != TRP)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011640 raise_error_unexpected_syntax(TRP);
11641 name = n->narg.text;
11642 if (!goodname(name)
11643 || ((bcmd = find_builtin(name)) && IS_BUILTIN_SPECIAL(bcmd))
11644 ) {
Denis Vlasenko559691a2008-10-05 18:39:31 +000011645 raise_error_syntax("bad function name");
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011646 }
11647 n->type = NDEFUN;
11648 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Denys Vlasenko675d24a2018-01-27 22:02:05 +010011649 n->ndefun.text = n->narg.text;
11650 n->ndefun.linno = g_parsefile->linno;
11651 n->ndefun.body = parse_command();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011652 return n;
11653 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011654 IF_BASH_FUNCTION(function_flag = 0;)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011655 /* fall through */
11656 default:
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011657 tokpushback = 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011658 goto out;
11659 }
11660 }
11661 out:
11662 *app = NULL;
11663 *vpp = NULL;
11664 *rpp = NULL;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011665 n = stzalloc(sizeof(struct ncmd));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011666 n->type = NCMD;
Denys Vlasenko675d24a2018-01-27 22:02:05 +010011667 n->ncmd.linno = savelinno;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011668 n->ncmd.args = args;
11669 n->ncmd.assign = vars;
11670 n->ncmd.redirect = redir;
11671 return n;
11672}
11673
11674static union node *
11675parse_command(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011676{
Eric Andersencb57d552001-06-28 07:25:16 +000011677 union node *n1, *n2;
11678 union node *ap, **app;
11679 union node *cp, **cpp;
11680 union node *redir, **rpp;
Eric Andersenc470f442003-07-28 09:56:35 +000011681 union node **rpp2;
Eric Andersencb57d552001-06-28 07:25:16 +000011682 int t;
Denys Vlasenko675d24a2018-01-27 22:02:05 +010011683 int savelinno;
Eric Andersencb57d552001-06-28 07:25:16 +000011684
11685 redir = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +000011686 rpp2 = &redir;
Eric Andersen88cec252001-09-06 17:35:20 +000011687
Denys Vlasenko675d24a2018-01-27 22:02:05 +010011688 savelinno = g_parsefile->linno;
11689
Eric Andersencb57d552001-06-28 07:25:16 +000011690 switch (readtoken()) {
Eric Andersenc470f442003-07-28 09:56:35 +000011691 default:
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011692 raise_error_unexpected_syntax(-1);
Eric Andersenc470f442003-07-28 09:56:35 +000011693 /* NOTREACHED */
Eric Andersencb57d552001-06-28 07:25:16 +000011694 case TIF:
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011695 n1 = stzalloc(sizeof(struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +000011696 n1->type = NIF;
11697 n1->nif.test = list(0);
11698 if (readtoken() != TTHEN)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011699 raise_error_unexpected_syntax(TTHEN);
Eric Andersencb57d552001-06-28 07:25:16 +000011700 n1->nif.ifpart = list(0);
11701 n2 = n1;
11702 while (readtoken() == TELIF) {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011703 n2->nif.elsepart = stzalloc(sizeof(struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +000011704 n2 = n2->nif.elsepart;
11705 n2->type = NIF;
11706 n2->nif.test = list(0);
11707 if (readtoken() != TTHEN)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011708 raise_error_unexpected_syntax(TTHEN);
Eric Andersencb57d552001-06-28 07:25:16 +000011709 n2->nif.ifpart = list(0);
11710 }
11711 if (lasttoken == TELSE)
11712 n2->nif.elsepart = list(0);
11713 else {
11714 n2->nif.elsepart = NULL;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011715 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011716 }
Eric Andersenc470f442003-07-28 09:56:35 +000011717 t = TFI;
Eric Andersencb57d552001-06-28 07:25:16 +000011718 break;
11719 case TWHILE:
Eric Andersenc470f442003-07-28 09:56:35 +000011720 case TUNTIL: {
Eric Andersencb57d552001-06-28 07:25:16 +000011721 int got;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011722 n1 = stzalloc(sizeof(struct nbinary));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011723 n1->type = (lasttoken == TWHILE) ? NWHILE : NUNTIL;
Eric Andersencb57d552001-06-28 07:25:16 +000011724 n1->nbinary.ch1 = list(0);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011725 got = readtoken();
11726 if (got != TDO) {
Denys Vlasenko888527c2016-10-02 16:54:17 +020011727 TRACE(("expecting DO got '%s' %s\n", tokname_array[got],
Denis Vlasenko131ae172007-02-18 13:00:19 +000011728 got == TWORD ? wordtext : ""));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011729 raise_error_unexpected_syntax(TDO);
Eric Andersencb57d552001-06-28 07:25:16 +000011730 }
11731 n1->nbinary.ch2 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +000011732 t = TDONE;
Eric Andersencb57d552001-06-28 07:25:16 +000011733 break;
11734 }
11735 case TFOR:
Denis Vlasenko2dc240c2008-07-24 06:07:50 +000011736 if (readtoken() != TWORD || quoteflag || !goodname(wordtext))
Denis Vlasenko559691a2008-10-05 18:39:31 +000011737 raise_error_syntax("bad for loop variable");
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011738 n1 = stzalloc(sizeof(struct nfor));
Eric Andersencb57d552001-06-28 07:25:16 +000011739 n1->type = NFOR;
Denys Vlasenko675d24a2018-01-27 22:02:05 +010011740 n1->nfor.linno = savelinno;
Eric Andersencb57d552001-06-28 07:25:16 +000011741 n1->nfor.var = wordtext;
Ron Yorstonab80e012015-08-03 13:46:00 +010011742 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000011743 if (readtoken() == TIN) {
11744 app = &ap;
11745 while (readtoken() == TWORD) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011746 n2 = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000011747 n2->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011748 /*n2->narg.next = NULL; - stzalloc did it */
Eric Andersencb57d552001-06-28 07:25:16 +000011749 n2->narg.text = wordtext;
11750 n2->narg.backquote = backquotelist;
11751 *app = n2;
11752 app = &n2->narg.next;
11753 }
11754 *app = NULL;
11755 n1->nfor.args = ap;
11756 if (lasttoken != TNL && lasttoken != TSEMI)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011757 raise_error_unexpected_syntax(-1);
Eric Andersencb57d552001-06-28 07:25:16 +000011758 } else {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011759 n2 = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000011760 n2->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011761 /*n2->narg.next = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011762 n2->narg.text = (char *)dolatstr;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011763 /*n2->narg.backquote = NULL;*/
Eric Andersencb57d552001-06-28 07:25:16 +000011764 n1->nfor.args = n2;
11765 /*
11766 * Newline or semicolon here is optional (but note
11767 * that the original Bourne shell only allowed NL).
11768 */
Ron Yorstonab80e012015-08-03 13:46:00 +010011769 if (lasttoken != TSEMI)
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011770 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011771 }
Eric Andersenc470f442003-07-28 09:56:35 +000011772 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000011773 if (readtoken() != TDO)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011774 raise_error_unexpected_syntax(TDO);
Eric Andersencb57d552001-06-28 07:25:16 +000011775 n1->nfor.body = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +000011776 t = TDONE;
Eric Andersencb57d552001-06-28 07:25:16 +000011777 break;
11778 case TCASE:
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011779 n1 = stzalloc(sizeof(struct ncase));
Eric Andersencb57d552001-06-28 07:25:16 +000011780 n1->type = NCASE;
Denys Vlasenko675d24a2018-01-27 22:02:05 +010011781 n1->ncase.linno = savelinno;
Eric Andersencb57d552001-06-28 07:25:16 +000011782 if (readtoken() != TWORD)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011783 raise_error_unexpected_syntax(TWORD);
Denis Vlasenko597906c2008-02-20 16:38:54 +000011784 n1->ncase.expr = n2 = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000011785 n2->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011786 /*n2->narg.next = NULL; - stzalloc did it */
Eric Andersencb57d552001-06-28 07:25:16 +000011787 n2->narg.text = wordtext;
11788 n2->narg.backquote = backquotelist;
Ron Yorston383b8852015-08-03 13:46:25 +010011789 checkkwd = CHKNL | CHKKWD | CHKALIAS;
11790 if (readtoken() != TIN)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011791 raise_error_unexpected_syntax(TIN);
Eric Andersencb57d552001-06-28 07:25:16 +000011792 cpp = &n1->ncase.cases;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011793 next_case:
Eric Andersenc470f442003-07-28 09:56:35 +000011794 checkkwd = CHKNL | CHKKWD;
11795 t = readtoken();
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011796 while (t != TESAC) {
Eric Andersencb57d552001-06-28 07:25:16 +000011797 if (lasttoken == TLP)
11798 readtoken();
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011799 *cpp = cp = stzalloc(sizeof(struct nclist));
Eric Andersencb57d552001-06-28 07:25:16 +000011800 cp->type = NCLIST;
11801 app = &cp->nclist.pattern;
11802 for (;;) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011803 *app = ap = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000011804 ap->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011805 /*ap->narg.next = NULL; - stzalloc did it */
Eric Andersencb57d552001-06-28 07:25:16 +000011806 ap->narg.text = wordtext;
11807 ap->narg.backquote = backquotelist;
Eric Andersenc470f442003-07-28 09:56:35 +000011808 if (readtoken() != TPIPE)
Eric Andersencb57d552001-06-28 07:25:16 +000011809 break;
11810 app = &ap->narg.next;
11811 readtoken();
11812 }
Denis Vlasenko597906c2008-02-20 16:38:54 +000011813 //ap->narg.next = NULL;
Eric Andersencb57d552001-06-28 07:25:16 +000011814 if (lasttoken != TRP)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011815 raise_error_unexpected_syntax(TRP);
Eric Andersenc470f442003-07-28 09:56:35 +000011816 cp->nclist.body = list(2);
Eric Andersencb57d552001-06-28 07:25:16 +000011817
Eric Andersenc470f442003-07-28 09:56:35 +000011818 cpp = &cp->nclist.next;
11819
11820 checkkwd = CHKNL | CHKKWD;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011821 t = readtoken();
11822 if (t != TESAC) {
Eric Andersencb57d552001-06-28 07:25:16 +000011823 if (t != TENDCASE)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011824 raise_error_unexpected_syntax(TENDCASE);
11825 goto next_case;
Eric Andersencb57d552001-06-28 07:25:16 +000011826 }
Eric Andersenc470f442003-07-28 09:56:35 +000011827 }
Eric Andersencb57d552001-06-28 07:25:16 +000011828 *cpp = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +000011829 goto redir;
Eric Andersencb57d552001-06-28 07:25:16 +000011830 case TLP:
Denis Vlasenko597906c2008-02-20 16:38:54 +000011831 n1 = stzalloc(sizeof(struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +000011832 n1->type = NSUBSHELL;
Denys Vlasenko675d24a2018-01-27 22:02:05 +010011833 n1->nredir.linno = savelinno;
Eric Andersencb57d552001-06-28 07:25:16 +000011834 n1->nredir.n = list(0);
Denis Vlasenko597906c2008-02-20 16:38:54 +000011835 /*n1->nredir.redirect = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011836 t = TRP;
Eric Andersencb57d552001-06-28 07:25:16 +000011837 break;
11838 case TBEGIN:
11839 n1 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +000011840 t = TEND;
Eric Andersencb57d552001-06-28 07:25:16 +000011841 break;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011842 IF_BASH_FUNCTION(case TFUNCTION:)
Eric Andersencb57d552001-06-28 07:25:16 +000011843 case TWORD:
Eric Andersenc470f442003-07-28 09:56:35 +000011844 case TREDIR:
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011845 tokpushback = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000011846 return simplecmd();
Eric Andersencb57d552001-06-28 07:25:16 +000011847 }
11848
Eric Andersenc470f442003-07-28 09:56:35 +000011849 if (readtoken() != t)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011850 raise_error_unexpected_syntax(t);
Eric Andersenc470f442003-07-28 09:56:35 +000011851
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011852 redir:
Eric Andersencb57d552001-06-28 07:25:16 +000011853 /* Now check for redirection which may follow command */
Eric Andersenc470f442003-07-28 09:56:35 +000011854 checkkwd = CHKKWD | CHKALIAS;
11855 rpp = rpp2;
Eric Andersencb57d552001-06-28 07:25:16 +000011856 while (readtoken() == TREDIR) {
11857 *rpp = n2 = redirnode;
11858 rpp = &n2->nfile.next;
11859 parsefname();
11860 }
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011861 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011862 *rpp = NULL;
11863 if (redir) {
11864 if (n1->type != NSUBSHELL) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011865 n2 = stzalloc(sizeof(struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +000011866 n2->type = NREDIR;
Denys Vlasenko675d24a2018-01-27 22:02:05 +010011867 n2->nredir.linno = savelinno;
Eric Andersencb57d552001-06-28 07:25:16 +000011868 n2->nredir.n = n1;
11869 n1 = n2;
11870 }
11871 n1->nredir.redirect = redir;
11872 }
Eric Andersencb57d552001-06-28 07:25:16 +000011873 return n1;
11874}
11875
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011876#if BASH_DOLLAR_SQUOTE
Denys Vlasenko37dc08b2016-10-02 04:38:07 +020011877static int
11878decode_dollar_squote(void)
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011879{
11880 static const char C_escapes[] ALIGN1 = "nrbtfav""x\\01234567";
11881 int c, cnt;
11882 char *p;
11883 char buf[4];
11884
11885 c = pgetc();
11886 p = strchr(C_escapes, c);
11887 if (p) {
11888 buf[0] = c;
11889 p = buf;
11890 cnt = 3;
11891 if ((unsigned char)(c - '0') <= 7) { /* \ooo */
11892 do {
11893 c = pgetc();
11894 *++p = c;
11895 } while ((unsigned char)(c - '0') <= 7 && --cnt);
11896 pungetc();
11897 } else if (c == 'x') { /* \xHH */
11898 do {
11899 c = pgetc();
11900 *++p = c;
11901 } while (isxdigit(c) && --cnt);
11902 pungetc();
11903 if (cnt == 3) { /* \x but next char is "bad" */
11904 c = 'x';
11905 goto unrecognized;
11906 }
11907 } else { /* simple seq like \\ or \t */
11908 p++;
11909 }
11910 *p = '\0';
11911 p = buf;
11912 c = bb_process_escape_sequence((void*)&p);
11913 } else { /* unrecognized "\z": print both chars unless ' or " */
11914 if (c != '\'' && c != '"') {
11915 unrecognized:
11916 c |= 0x100; /* "please encode \, then me" */
11917 }
11918 }
11919 return c;
11920}
11921#endif
11922
Denys Vlasenko46999802017-07-29 21:12:29 +020011923/* Used by expandstr to get here-doc like behaviour. */
11924#define FAKEEOFMARK ((char*)(uintptr_t)1)
11925
11926static ALWAYS_INLINE int
11927realeofmark(const char *eofmark)
11928{
11929 return eofmark && eofmark != FAKEEOFMARK;
11930}
11931
Eric Andersencb57d552001-06-28 07:25:16 +000011932/*
11933 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
11934 * is not NULL, read a here document. In the latter case, eofmark is the
11935 * word which marks the end of the document and striptabs is true if
Denys Vlasenkocd716832009-11-28 22:14:02 +010011936 * leading tabs should be stripped from the document. The argument c
Eric Andersencb57d552001-06-28 07:25:16 +000011937 * is the first character of the input token or document.
11938 *
11939 * Because C does not have internal subroutines, I have simulated them
11940 * using goto's to implement the subroutine linkage. The following macros
11941 * will run code that appears at the end of readtoken1.
11942 */
Eric Andersen2870d962001-07-02 17:27:21 +000011943#define CHECKEND() {goto checkend; checkend_return:;}
11944#define PARSEREDIR() {goto parseredir; parseredir_return:;}
11945#define PARSESUB() {goto parsesub; parsesub_return:;}
11946#define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
11947#define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
11948#define PARSEARITH() {goto parsearith; parsearith_return:;}
Eric Andersencb57d552001-06-28 07:25:16 +000011949static int
Denys Vlasenkocd716832009-11-28 22:14:02 +010011950readtoken1(int c, int syntax, char *eofmark, int striptabs)
Manuel Novoa III 16815d42001-08-10 19:36:07 +000011951{
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011952 /* NB: syntax parameter fits into smallint */
Denys Vlasenkocd716832009-11-28 22:14:02 +010011953 /* c parameter is an unsigned char or PEOF or PEOA */
Eric Andersencb57d552001-06-28 07:25:16 +000011954 char *out;
Denys Vlasenko50e6d422016-09-30 11:35:54 +020011955 size_t len;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011956 struct nodelist *bqlist;
11957 smallint quotef;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011958 smallint oldstyle;
Denis Vlasenko46a53062007-09-24 18:30:02 +000011959 smallint pssyntax; /* we are expanding a prompt string */
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011960 IF_BASH_DOLLAR_SQUOTE(smallint bash_dollar_squote = 0;)
Denys Vlasenko216913c2018-04-02 12:35:04 +020011961 /* syntax stack */
Denys Vlasenkoee1fd122018-04-04 13:59:53 +020011962 struct synstack synbase = { };
Denys Vlasenko216913c2018-04-02 12:35:04 +020011963 struct synstack *synstack = &synbase;
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011964
Denys Vlasenko5f0a75f2017-07-29 22:58:44 +020011965#if ENABLE_ASH_EXPAND_PRMT
Denis Vlasenko46a53062007-09-24 18:30:02 +000011966 pssyntax = (syntax == PSSYNTAX);
11967 if (pssyntax)
11968 syntax = DQSYNTAX;
Denys Vlasenko5f0a75f2017-07-29 22:58:44 +020011969#else
11970 pssyntax = 0; /* constant */
11971#endif
Denys Vlasenkoee1fd122018-04-04 13:59:53 +020011972 synstack->syntax = syntax;
11973
Denys Vlasenko216913c2018-04-02 12:35:04 +020011974 if (syntax == DQSYNTAX)
11975 synstack->dblquote = 1;
11976 quotef = 0;
11977 bqlist = NULL;
Eric Andersencb57d552001-06-28 07:25:16 +000011978
11979 STARTSTACKSTR(out);
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011980 loop:
11981 /* For each line, until end of word */
Denys Vlasenko958581a2010-09-12 15:04:27 +020011982 CHECKEND(); /* set c to PEOF if at end of here document */
11983 for (;;) { /* until end of line or end of word */
11984 CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */
Denys Vlasenko216913c2018-04-02 12:35:04 +020011985 switch (SIT(c, synstack->syntax)) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020011986 case CNL: /* '\n' */
Denys Vlasenko216913c2018-04-02 12:35:04 +020011987 if (synstack->syntax == BASESYNTAX)
Denys Vlasenko958581a2010-09-12 15:04:27 +020011988 goto endword; /* exit outer loop */
11989 USTPUTC(c, out);
Denys Vlasenkoce332a22016-10-02 23:47:34 +020011990 nlprompt();
Denys Vlasenko958581a2010-09-12 15:04:27 +020011991 c = pgetc();
11992 goto loop; /* continue outer loop */
11993 case CWORD:
11994 USTPUTC(c, out);
11995 break;
11996 case CCTL:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011997#if BASH_DOLLAR_SQUOTE
Denys Vlasenko958581a2010-09-12 15:04:27 +020011998 if (c == '\\' && bash_dollar_squote) {
11999 c = decode_dollar_squote();
Denys Vlasenko13f20912016-09-25 20:54:25 +020012000 if (c == '\0') {
12001 /* skip $'\000', $'\x00' (like bash) */
12002 break;
12003 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020012004 if (c & 0x100) {
Denys Vlasenko13f20912016-09-25 20:54:25 +020012005 /* Unknown escape. Encode as '\z' */
Denys Vlasenko958581a2010-09-12 15:04:27 +020012006 c = (unsigned char)c;
Denys Vlasenko216913c2018-04-02 12:35:04 +020012007 if (eofmark == NULL || synstack->dblquote)
Denys Vlasenko13f20912016-09-25 20:54:25 +020012008 USTPUTC(CTLESC, out);
12009 USTPUTC('\\', out);
Denis Vlasenkoef527f52008-06-23 01:52:30 +000012010 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020012011 }
Denis Vlasenkoef527f52008-06-23 01:52:30 +000012012#endif
Denys Vlasenkoc4c20122018-04-02 13:29:20 +020012013 if (!eofmark || synstack->dblquote || synstack->varnest)
Denys Vlasenko13f20912016-09-25 20:54:25 +020012014 USTPUTC(CTLESC, out);
Denys Vlasenko958581a2010-09-12 15:04:27 +020012015 USTPUTC(c, out);
12016 break;
12017 case CBACK: /* backslash */
12018 c = pgetc_without_PEOA();
12019 if (c == PEOF) {
12020 USTPUTC(CTLESC, out);
12021 USTPUTC('\\', out);
12022 pungetc();
12023 } else if (c == '\n') {
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012024 nlprompt();
Denys Vlasenko958581a2010-09-12 15:04:27 +020012025 } else {
Denys Vlasenko5f0a75f2017-07-29 22:58:44 +020012026 if (pssyntax && c == '$') {
Eric Andersenc470f442003-07-28 09:56:35 +000012027 USTPUTC(CTLESC, out);
Eric Andersencb57d552001-06-28 07:25:16 +000012028 USTPUTC('\\', out);
Denys Vlasenko958581a2010-09-12 15:04:27 +020012029 }
Denys Vlasenko8de5b9f2018-02-13 14:43:29 +010012030 /* Backslash is retained if we are in "str"
12031 * and next char isn't dquote-special.
12032 */
Denys Vlasenko216913c2018-04-02 12:35:04 +020012033 if (synstack->dblquote
Denys Vlasenko958581a2010-09-12 15:04:27 +020012034 && c != '\\'
12035 && c != '`'
12036 && c != '$'
Denys Vlasenko216913c2018-04-02 12:35:04 +020012037 && (c != '"' || (eofmark != NULL && !synstack->varnest))
12038 && (c != '}' || !synstack->varnest)
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000012039 ) {
Denys Vlasenko8de5b9f2018-02-13 14:43:29 +010012040 USTPUTC(CTLESC, out); /* protect '\' from glob */
Denys Vlasenko958581a2010-09-12 15:04:27 +020012041 USTPUTC('\\', out);
Eric Andersencb57d552001-06-28 07:25:16 +000012042 }
Ron Yorston549deab2015-05-18 09:57:51 +020012043 USTPUTC(CTLESC, out);
Denys Vlasenko0ff78a02010-08-30 15:20:07 +020012044 USTPUTC(c, out);
Denys Vlasenko958581a2010-09-12 15:04:27 +020012045 quotef = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000012046 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020012047 break;
12048 case CSQUOTE:
Denys Vlasenko216913c2018-04-02 12:35:04 +020012049 synstack->syntax = SQSYNTAX;
Denys Vlasenko958581a2010-09-12 15:04:27 +020012050 quotemark:
12051 if (eofmark == NULL) {
12052 USTPUTC(CTLQUOTEMARK, out);
12053 }
12054 break;
12055 case CDQUOTE:
Denys Vlasenko216913c2018-04-02 12:35:04 +020012056 synstack->syntax = DQSYNTAX;
12057 synstack->dblquote = 1;
12058 toggledq:
12059 if (synstack->varnest)
12060 synstack->innerdq ^= 1;
Denys Vlasenko958581a2010-09-12 15:04:27 +020012061 goto quotemark;
12062 case CENDQUOTE:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010012063 IF_BASH_DOLLAR_SQUOTE(bash_dollar_squote = 0;)
Denys Vlasenko216913c2018-04-02 12:35:04 +020012064 if (eofmark != NULL && synstack->varnest == 0) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020012065 USTPUTC(c, out);
Denys Vlasenko216913c2018-04-02 12:35:04 +020012066 break;
Denys Vlasenko958581a2010-09-12 15:04:27 +020012067 }
Denys Vlasenko216913c2018-04-02 12:35:04 +020012068
12069 if (synstack->dqvarnest == 0) {
12070 synstack->syntax = BASESYNTAX;
12071 synstack->dblquote = 0;
12072 }
12073
12074 quotef = 1;
12075
12076 if (c == '"')
12077 goto toggledq;
12078
12079 goto quotemark;
Denys Vlasenko958581a2010-09-12 15:04:27 +020012080 case CVAR: /* '$' */
12081 PARSESUB(); /* parse substitution */
12082 break;
12083 case CENDVAR: /* '}' */
Denys Vlasenko216913c2018-04-02 12:35:04 +020012084 if (!synstack->innerdq && synstack->varnest > 0) {
12085 if (!--synstack->varnest && synstack->varpushed)
12086 synstack_pop(&synstack);
12087 else if (synstack->dqvarnest > 0)
12088 synstack->dqvarnest--;
Denys Vlasenko958581a2010-09-12 15:04:27 +020012089 c = CTLENDVAR;
12090 }
12091 USTPUTC(c, out);
12092 break;
Denys Vlasenko0b883582016-12-23 16:49:07 +010012093#if ENABLE_FEATURE_SH_MATH
Denys Vlasenko958581a2010-09-12 15:04:27 +020012094 case CLP: /* '(' in arithmetic */
Denys Vlasenko216913c2018-04-02 12:35:04 +020012095 synstack->parenlevel++;
Denys Vlasenko958581a2010-09-12 15:04:27 +020012096 USTPUTC(c, out);
12097 break;
12098 case CRP: /* ')' in arithmetic */
Denys Vlasenko216913c2018-04-02 12:35:04 +020012099 if (synstack->parenlevel > 0) {
12100 synstack->parenlevel--;
Denys Vlasenko958581a2010-09-12 15:04:27 +020012101 } else {
Denys Vlasenko459293b2016-09-29 17:58:58 +020012102 if (pgetc_eatbnl() == ')') {
Ron Yorstonad88bde2015-05-18 09:56:16 +020012103 c = CTLENDARI;
Denys Vlasenko216913c2018-04-02 12:35:04 +020012104 synstack_pop(&synstack);
Denys Vlasenko958581a2010-09-12 15:04:27 +020012105 } else {
12106 /*
12107 * unbalanced parens
12108 * (don't 2nd guess - no error)
12109 */
12110 pungetc();
12111 }
12112 }
12113 USTPUTC(c, out);
12114 break;
12115#endif
12116 case CBQUOTE: /* '`' */
Denys Vlasenko41fddb42018-04-01 16:38:32 +020012117 if (checkkwd & CHKEOFMARK) {
12118 quotef = 1;
12119 USTPUTC('`', out);
12120 break;
12121 }
12122
Denys Vlasenko958581a2010-09-12 15:04:27 +020012123 PARSEBACKQOLD();
12124 break;
12125 case CENDFILE:
12126 goto endword; /* exit outer loop */
12127 case CIGN:
12128 break;
12129 default:
Denys Vlasenko216913c2018-04-02 12:35:04 +020012130 if (synstack->varnest == 0) {
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010012131#if BASH_REDIR_OUTPUT
Denys Vlasenko958581a2010-09-12 15:04:27 +020012132 if (c == '&') {
Denys Vlasenko459293b2016-09-29 17:58:58 +020012133//Can't call pgetc_eatbnl() here, this requires three-deep pungetc()
Denys Vlasenko958581a2010-09-12 15:04:27 +020012134 if (pgetc() == '>')
12135 c = 0x100 + '>'; /* flag &> */
12136 pungetc();
12137 }
12138#endif
12139 goto endword; /* exit outer loop */
12140 }
12141 IF_ASH_ALIAS(if (c != PEOA))
12142 USTPUTC(c, out);
12143 }
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020012144 c = pgetc();
Denys Vlasenko958581a2010-09-12 15:04:27 +020012145 } /* for (;;) */
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000012146 endword:
Denys Vlasenko958581a2010-09-12 15:04:27 +020012147
Denys Vlasenko0b883582016-12-23 16:49:07 +010012148#if ENABLE_FEATURE_SH_MATH
Denys Vlasenko216913c2018-04-02 12:35:04 +020012149 if (synstack->syntax == ARISYNTAX)
Denis Vlasenko559691a2008-10-05 18:39:31 +000012150 raise_error_syntax("missing '))'");
Eric Andersenc470f442003-07-28 09:56:35 +000012151#endif
Denys Vlasenko216913c2018-04-02 12:35:04 +020012152 if (synstack->syntax != BASESYNTAX && eofmark == NULL)
Denis Vlasenko559691a2008-10-05 18:39:31 +000012153 raise_error_syntax("unterminated quoted string");
Denys Vlasenko216913c2018-04-02 12:35:04 +020012154 if (synstack->varnest != 0) {
Eric Andersenc470f442003-07-28 09:56:35 +000012155 /* { */
Denis Vlasenko559691a2008-10-05 18:39:31 +000012156 raise_error_syntax("missing '}'");
Eric Andersencb57d552001-06-28 07:25:16 +000012157 }
12158 USTPUTC('\0', out);
Eric Andersenc470f442003-07-28 09:56:35 +000012159 len = out - (char *)stackblock();
Eric Andersencb57d552001-06-28 07:25:16 +000012160 out = stackblock();
12161 if (eofmark == NULL) {
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010012162 if ((c == '>' || c == '<' IF_BASH_REDIR_OUTPUT( || c == 0x100 + '>'))
Denis Vlasenko834dee72008-10-07 09:18:30 +000012163 && quotef == 0
12164 ) {
Denis Vlasenko559691a2008-10-05 18:39:31 +000012165 if (isdigit_str9(out)) {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000012166 PARSEREDIR(); /* passed as params: out, c */
12167 lasttoken = TREDIR;
12168 return lasttoken;
12169 }
12170 /* else: non-number X seen, interpret it
12171 * as "NNNX>file" = "NNNX >file" */
Eric Andersencb57d552001-06-28 07:25:16 +000012172 }
Denis Vlasenkoef527f52008-06-23 01:52:30 +000012173 pungetc();
Eric Andersencb57d552001-06-28 07:25:16 +000012174 }
12175 quoteflag = quotef;
12176 backquotelist = bqlist;
12177 grabstackblock(len);
12178 wordtext = out;
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000012179 lasttoken = TWORD;
12180 return lasttoken;
Eric Andersencb57d552001-06-28 07:25:16 +000012181/* end of readtoken routine */
12182
Eric Andersencb57d552001-06-28 07:25:16 +000012183/*
12184 * Check to see whether we are at the end of the here document. When this
12185 * is called, c is set to the first character of the next input line. If
12186 * we are at the end of the here document, this routine sets the c to PEOF.
12187 */
Eric Andersenc470f442003-07-28 09:56:35 +000012188checkend: {
Denys Vlasenko46999802017-07-29 21:12:29 +020012189 if (realeofmark(eofmark)) {
Denys Vlasenkoa7328982017-07-29 19:57:28 +020012190 int markloc;
12191 char *p;
12192
Denis Vlasenko131ae172007-02-18 13:00:19 +000012193#if ENABLE_ASH_ALIAS
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010012194 if (c == PEOA)
12195 c = pgetc_without_PEOA();
Eric Andersenc470f442003-07-28 09:56:35 +000012196#endif
12197 if (striptabs) {
12198 while (c == '\t') {
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010012199 c = pgetc_without_PEOA();
Eric Andersencb57d552001-06-28 07:25:16 +000012200 }
Eric Andersenc470f442003-07-28 09:56:35 +000012201 }
Eric Andersencb57d552001-06-28 07:25:16 +000012202
Denys Vlasenkoa7328982017-07-29 19:57:28 +020012203 markloc = out - (char *)stackblock();
12204 for (p = eofmark; STPUTC(c, out), *p; p++) {
12205 if (c != *p)
12206 goto more_heredoc;
12207
12208 c = pgetc_without_PEOA();
12209 }
12210
12211 if (c == '\n' || c == PEOF) {
12212 c = PEOF;
12213 g_parsefile->linno++;
12214 needprompt = doprompt;
12215 } else {
12216 int len_here;
12217
12218 more_heredoc:
12219 p = (char *)stackblock() + markloc + 1;
12220 len_here = out - p;
12221
12222 if (len_here) {
12223 len_here -= (c >= PEOF);
12224 c = p[-1];
12225
12226 if (len_here) {
12227 char *str;
12228
12229 str = alloca(len_here + 1);
12230 *(char *)mempcpy(str, p, len_here) = '\0';
12231
12232 pushstring(str, NULL);
Eric Andersencb57d552001-06-28 07:25:16 +000012233 }
12234 }
12235 }
Denys Vlasenkoa7328982017-07-29 19:57:28 +020012236
12237 STADJUST((char *)stackblock() + markloc - out, out);
Eric Andersencb57d552001-06-28 07:25:16 +000012238 }
Eric Andersenc470f442003-07-28 09:56:35 +000012239 goto checkend_return;
12240}
Eric Andersencb57d552001-06-28 07:25:16 +000012241
Eric Andersencb57d552001-06-28 07:25:16 +000012242/*
12243 * Parse a redirection operator. The variable "out" points to a string
12244 * specifying the fd to be redirected. The variable "c" contains the
12245 * first character of the redirection operator.
12246 */
Eric Andersenc470f442003-07-28 09:56:35 +000012247parseredir: {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000012248 /* out is already checked to be a valid number or "" */
12249 int fd = (*out == '\0' ? -1 : atoi(out));
Eric Andersenc470f442003-07-28 09:56:35 +000012250 union node *np;
Eric Andersencb57d552001-06-28 07:25:16 +000012251
Denis Vlasenko597906c2008-02-20 16:38:54 +000012252 np = stzalloc(sizeof(struct nfile));
Eric Andersenc470f442003-07-28 09:56:35 +000012253 if (c == '>') {
12254 np->nfile.fd = 1;
Denys Vlasenko220be532018-03-31 19:21:31 +020012255 c = pgetc_eatbnl();
Eric Andersenc470f442003-07-28 09:56:35 +000012256 if (c == '>')
12257 np->type = NAPPEND;
12258 else if (c == '|')
12259 np->type = NCLOBBER;
12260 else if (c == '&')
12261 np->type = NTOFD;
Denis Vlasenko559691a2008-10-05 18:39:31 +000012262 /* it also can be NTO2 (>&file), but we can't figure it out yet */
Eric Andersenc470f442003-07-28 09:56:35 +000012263 else {
12264 np->type = NTO;
12265 pungetc();
Eric Andersencb57d552001-06-28 07:25:16 +000012266 }
Denis Vlasenko834dee72008-10-07 09:18:30 +000012267 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010012268#if BASH_REDIR_OUTPUT
Denis Vlasenko834dee72008-10-07 09:18:30 +000012269 else if (c == 0x100 + '>') { /* this flags &> redirection */
12270 np->nfile.fd = 1;
12271 pgetc(); /* this is '>', no need to check */
12272 np->type = NTO2;
12273 }
12274#endif
12275 else { /* c == '<' */
Denis Vlasenko597906c2008-02-20 16:38:54 +000012276 /*np->nfile.fd = 0; - stzalloc did it */
Denys Vlasenko220be532018-03-31 19:21:31 +020012277 c = pgetc_eatbnl();
Denis Vlasenko5cedb752007-02-18 19:56:41 +000012278 switch (c) {
Eric Andersenc470f442003-07-28 09:56:35 +000012279 case '<':
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000012280 if (sizeof(struct nfile) != sizeof(struct nhere)) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000012281 np = stzalloc(sizeof(struct nhere));
12282 /*np->nfile.fd = 0; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000012283 }
12284 np->type = NHERE;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000012285 heredoc = stzalloc(sizeof(struct heredoc));
Eric Andersenc470f442003-07-28 09:56:35 +000012286 heredoc->here = np;
Denys Vlasenko220be532018-03-31 19:21:31 +020012287 c = pgetc_eatbnl();
Denis Vlasenko5cedb752007-02-18 19:56:41 +000012288 if (c == '-') {
Eric Andersenc470f442003-07-28 09:56:35 +000012289 heredoc->striptabs = 1;
12290 } else {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000012291 /*heredoc->striptabs = 0; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000012292 pungetc();
12293 }
12294 break;
12295
12296 case '&':
12297 np->type = NFROMFD;
12298 break;
12299
12300 case '>':
12301 np->type = NFROMTO;
12302 break;
12303
12304 default:
12305 np->type = NFROM;
12306 pungetc();
12307 break;
12308 }
Eric Andersencb57d552001-06-28 07:25:16 +000012309 }
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000012310 if (fd >= 0)
12311 np->nfile.fd = fd;
Eric Andersenc470f442003-07-28 09:56:35 +000012312 redirnode = np;
12313 goto parseredir_return;
12314}
Eric Andersencb57d552001-06-28 07:25:16 +000012315
Eric Andersencb57d552001-06-28 07:25:16 +000012316/*
12317 * Parse a substitution. At this point, we have read the dollar sign
12318 * and nothing else.
12319 */
Denis Vlasenkocc571512007-02-23 21:10:35 +000012320
12321/* is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise
12322 * (assuming ascii char codes, as the original implementation did) */
12323#define is_special(c) \
Denis Vlasenkoef527f52008-06-23 01:52:30 +000012324 (((unsigned)(c) - 33 < 32) \
12325 && ((0xc1ff920dU >> ((unsigned)(c) - 33)) & 1))
Eric Andersenc470f442003-07-28 09:56:35 +000012326parsesub: {
Denys Vlasenkocd716832009-11-28 22:14:02 +010012327 unsigned char subtype;
Eric Andersenc470f442003-07-28 09:56:35 +000012328 int typeloc;
Eric Andersencb57d552001-06-28 07:25:16 +000012329
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012330 c = pgetc_eatbnl();
Denys Vlasenkoa7328982017-07-29 19:57:28 +020012331 if ((checkkwd & CHKEOFMARK)
12332 || c > 255 /* PEOA or PEOF */
Denis Vlasenkoef527f52008-06-23 01:52:30 +000012333 || (c != '(' && c != '{' && !is_name(c) && !is_special(c))
Eric Andersenc470f442003-07-28 09:56:35 +000012334 ) {
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010012335#if BASH_DOLLAR_SQUOTE
Denys Vlasenko216913c2018-04-02 12:35:04 +020012336 if (synstack->syntax != DQSYNTAX && c == '\'')
Denis Vlasenkoef527f52008-06-23 01:52:30 +000012337 bash_dollar_squote = 1;
12338 else
12339#endif
12340 USTPUTC('$', out);
Eric Andersenc470f442003-07-28 09:56:35 +000012341 pungetc();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012342 } else if (c == '(') {
12343 /* $(command) or $((arith)) */
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012344 if (pgetc_eatbnl() == '(') {
Denys Vlasenko0b883582016-12-23 16:49:07 +010012345#if ENABLE_FEATURE_SH_MATH
Eric Andersenc470f442003-07-28 09:56:35 +000012346 PARSEARITH();
12347#else
Denys Vlasenko4f8079d2017-07-17 17:11:48 +020012348 raise_error_syntax("support for $((arith)) is disabled");
Eric Andersenc470f442003-07-28 09:56:35 +000012349#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012350 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000012351 pungetc();
12352 PARSEBACKQNEW();
12353 }
12354 } else {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012355 /* $VAR, $<specialchar>, ${...}, or PEOA/PEOF */
Denys Vlasenko216913c2018-04-02 12:35:04 +020012356 smalluint newsyn = synstack->syntax;
12357
Eric Andersenc470f442003-07-28 09:56:35 +000012358 USTPUTC(CTLVAR, out);
12359 typeloc = out - (char *)stackblock();
Denys Vlasenko3df14102016-10-26 16:41:13 +020012360 STADJUST(1, out);
Eric Andersenc470f442003-07-28 09:56:35 +000012361 subtype = VSNORMAL;
12362 if (c == '{') {
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012363 c = pgetc_eatbnl();
Denys Vlasenkof15aa572016-10-26 15:56:53 +020012364 subtype = 0;
Eric Andersenc470f442003-07-28 09:56:35 +000012365 }
Denys Vlasenkof15aa572016-10-26 15:56:53 +020012366 varname:
Denys Vlasenko3df14102016-10-26 16:41:13 +020012367 if (is_name(c)) {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012368 /* $[{[#]]NAME[}] */
Eric Andersenc470f442003-07-28 09:56:35 +000012369 do {
12370 STPUTC(c, out);
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012371 c = pgetc_eatbnl();
Denys Vlasenko3df14102016-10-26 16:41:13 +020012372 } while (is_in_name(c));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012373 } else if (isdigit(c)) {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012374 /* $[{[#]]NUM[}] */
Eric Andersenc470f442003-07-28 09:56:35 +000012375 do {
12376 STPUTC(c, out);
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012377 c = pgetc_eatbnl();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012378 } while (isdigit(c));
Denys Vlasenko452cc1d2017-08-14 14:23:45 +020012379 } else {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012380 /* $[{[#]]<specialchar>[}] */
Denys Vlasenkof15aa572016-10-26 15:56:53 +020012381 int cc = c;
12382
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012383 c = pgetc_eatbnl();
Denys Vlasenkof15aa572016-10-26 15:56:53 +020012384 if (!subtype && cc == '#') {
12385 subtype = VSLENGTH;
12386 if (c == '_' || isalnum(c))
12387 goto varname;
12388 cc = c;
12389 c = pgetc_eatbnl();
12390 if (cc == '}' || c != '}') {
12391 pungetc();
12392 subtype = 0;
12393 c = cc;
12394 cc = '#';
12395 }
12396 }
Denys Vlasenko452cc1d2017-08-14 14:23:45 +020012397
12398 if (!is_special(cc)) {
12399 if (subtype == VSLENGTH)
12400 subtype = 0;
12401 goto badsub;
12402 }
12403
Denys Vlasenkof15aa572016-10-26 15:56:53 +020012404 USTPUTC(cc, out);
Denis Vlasenko559691a2008-10-05 18:39:31 +000012405 }
Denys Vlasenko452cc1d2017-08-14 14:23:45 +020012406
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012407 if (c != '}' && subtype == VSLENGTH) {
12408 /* ${#VAR didn't end with } */
Cristian Ionescu-Idbohrn301f5ec2009-10-05 02:07:23 +020012409 goto badsub;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012410 }
Eric Andersencb57d552001-06-28 07:25:16 +000012411
Eric Andersenc470f442003-07-28 09:56:35 +000012412 if (subtype == 0) {
Denys Vlasenkof8ddbe12016-07-25 03:56:00 +020012413 static const char types[] ALIGN1 = "}-+?=";
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012414 /* ${VAR...} but not $VAR or ${#VAR} */
12415 /* c == first char after VAR */
Denys Vlasenko216913c2018-04-02 12:35:04 +020012416 int cc = c;
12417
Eric Andersenc470f442003-07-28 09:56:35 +000012418 switch (c) {
12419 case ':':
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012420 c = pgetc_eatbnl();
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010012421#if BASH_SUBSTR
Denys Vlasenkof8ddbe12016-07-25 03:56:00 +020012422 /* This check is only needed to not misinterpret
12423 * ${VAR:-WORD}, ${VAR:+WORD}, ${VAR:=WORD}, ${VAR:?WORD}
12424 * constructs.
12425 */
12426 if (!strchr(types, c)) {
Denis Vlasenko92e13c22008-03-25 01:17:40 +000012427 subtype = VSSUBSTR;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012428 pungetc();
Denys Vlasenko88e15702016-10-26 01:55:56 +020012429 break; /* "goto badsub" is bigger (!) */
Denis Vlasenko92e13c22008-03-25 01:17:40 +000012430 }
12431#endif
Denys Vlasenko3df14102016-10-26 16:41:13 +020012432 subtype = VSNUL;
Eric Andersenc470f442003-07-28 09:56:35 +000012433 /*FALLTHROUGH*/
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012434 default: {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012435 const char *p = strchr(types, c);
Eric Andersenc470f442003-07-28 09:56:35 +000012436 if (p == NULL)
Denys Vlasenko88e15702016-10-26 01:55:56 +020012437 break;
Denys Vlasenko3df14102016-10-26 16:41:13 +020012438 subtype |= p - types + VSNORMAL;
Eric Andersenc470f442003-07-28 09:56:35 +000012439 break;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012440 }
Eric Andersenc470f442003-07-28 09:56:35 +000012441 case '%':
Denys Vlasenko216913c2018-04-02 12:35:04 +020012442 case '#':
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012443 subtype = (c == '#' ? VSTRIMLEFT : VSTRIMRIGHT);
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012444 c = pgetc_eatbnl();
Denys Vlasenko216913c2018-04-02 12:35:04 +020012445 if (c == cc)
12446 subtype++;
12447 else
12448 pungetc();
12449
12450 newsyn = BASESYNTAX;
Denis Vlasenko92e13c22008-03-25 01:17:40 +000012451 break;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010012452#if BASH_PATTERN_SUBST
Denis Vlasenko92e13c22008-03-25 01:17:40 +000012453 case '/':
Denys Vlasenko6040fe82010-09-12 15:03:16 +020012454 /* ${v/[/]pattern/repl} */
12455//TODO: encode pattern and repl separately.
Denys Vlasenko216913c2018-04-02 12:35:04 +020012456// Currently cases like: v=1;echo ${v/$((1/1))/ONE}
12457// are broken (should print "ONE")
Denis Vlasenko92e13c22008-03-25 01:17:40 +000012458 subtype = VSREPLACE;
Denys Vlasenko216913c2018-04-02 12:35:04 +020012459 newsyn = BASESYNTAX;
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012460 c = pgetc_eatbnl();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012461 if (c != '/')
Denys Vlasenko88e15702016-10-26 01:55:56 +020012462 goto badsub;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012463 subtype++; /* VSREPLACEALL */
Denis Vlasenko92e13c22008-03-25 01:17:40 +000012464 break;
12465#endif
Eric Andersencb57d552001-06-28 07:25:16 +000012466 }
Eric Andersenc470f442003-07-28 09:56:35 +000012467 } else {
Denys Vlasenko88e15702016-10-26 01:55:56 +020012468 badsub:
Eric Andersenc470f442003-07-28 09:56:35 +000012469 pungetc();
12470 }
Denys Vlasenko216913c2018-04-02 12:35:04 +020012471
Denys Vlasenkof50e1462018-04-02 21:00:59 +020012472 if (newsyn == ARISYNTAX)
Denys Vlasenko216913c2018-04-02 12:35:04 +020012473 newsyn = DQSYNTAX;
12474
Denys Vlasenkof50e1462018-04-02 21:00:59 +020012475 if ((newsyn != synstack->syntax || synstack->innerdq)
12476 && subtype != VSNORMAL
12477 ) {
Denys Vlasenko216913c2018-04-02 12:35:04 +020012478 synstack_push(&synstack,
12479 synstack->prev ?: alloca(sizeof(*synstack)),
12480 newsyn);
12481
12482 synstack->varpushed = 1;
12483 synstack->dblquote = newsyn != BASESYNTAX;
12484 }
12485
Denys Vlasenko3df14102016-10-26 16:41:13 +020012486 ((unsigned char *)stackblock())[typeloc] = subtype;
Eric Andersenc470f442003-07-28 09:56:35 +000012487 if (subtype != VSNORMAL) {
Denys Vlasenko216913c2018-04-02 12:35:04 +020012488 synstack->varnest++;
12489 if (synstack->dblquote)
12490 synstack->dqvarnest++;
Eric Andersencb57d552001-06-28 07:25:16 +000012491 }
Denys Vlasenko88e15702016-10-26 01:55:56 +020012492 STPUTC('=', out);
Eric Andersencb57d552001-06-28 07:25:16 +000012493 }
Eric Andersenc470f442003-07-28 09:56:35 +000012494 goto parsesub_return;
12495}
Eric Andersencb57d552001-06-28 07:25:16 +000012496
Eric Andersencb57d552001-06-28 07:25:16 +000012497/*
12498 * Called to parse command substitutions. Newstyle is set if the command
12499 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
12500 * list of commands (passed by reference), and savelen is the number of
12501 * characters on the top of the stack which must be preserved.
12502 */
Eric Andersenc470f442003-07-28 09:56:35 +000012503parsebackq: {
12504 struct nodelist **nlpp;
Eric Andersenc470f442003-07-28 09:56:35 +000012505 union node *n;
Ron Yorston072fc602015-07-01 16:46:18 +010012506 char *str;
Eric Andersenc470f442003-07-28 09:56:35 +000012507 size_t savelen;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000012508 smallint saveprompt = 0;
12509
Eric Andersenc470f442003-07-28 09:56:35 +000012510 str = NULL;
12511 savelen = out - (char *)stackblock();
12512 if (savelen > 0) {
Denys Vlasenko7bc3d392016-09-17 20:53:47 +020012513 /*
12514 * FIXME: this can allocate very large block on stack and SEGV.
12515 * Example:
12516 * echo "..<100kbytes>..`true` $(true) `true` ..."
Denys Vlasenko73737592016-09-17 20:58:22 +020012517 * allocates 100kb for every command subst. With about
Denys Vlasenko7bc3d392016-09-17 20:53:47 +020012518 * a hundred command substitutions stack overflows.
12519 * With larger prepended string, SEGV happens sooner.
12520 */
Ron Yorston072fc602015-07-01 16:46:18 +010012521 str = alloca(savelen);
Eric Andersenc470f442003-07-28 09:56:35 +000012522 memcpy(str, stackblock(), savelen);
12523 }
Denys Vlasenko7bc3d392016-09-17 20:53:47 +020012524
Eric Andersenc470f442003-07-28 09:56:35 +000012525 if (oldstyle) {
12526 /* We must read until the closing backquote, giving special
Denys Vlasenko60cb48c2013-01-14 15:57:44 +010012527 * treatment to some slashes, and then push the string and
12528 * reread it as input, interpreting it normally.
12529 */
Eric Andersenc470f442003-07-28 09:56:35 +000012530 char *pout;
Eric Andersenc470f442003-07-28 09:56:35 +000012531 size_t psavelen;
12532 char *pstr;
12533
Eric Andersenc470f442003-07-28 09:56:35 +000012534 STARTSTACKSTR(pout);
12535 for (;;) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020012536 int pc;
12537
12538 setprompt_if(needprompt, 2);
Denys Vlasenko220be532018-03-31 19:21:31 +020012539 pc = pgetc_eatbnl();
Denis Vlasenko5cedb752007-02-18 19:56:41 +000012540 switch (pc) {
Eric Andersenc470f442003-07-28 09:56:35 +000012541 case '`':
12542 goto done;
12543
12544 case '\\':
Denys Vlasenko220be532018-03-31 19:21:31 +020012545 pc = pgetc(); /* or pgetc_eatbnl()? why (example)? */
Eric Andersenc470f442003-07-28 09:56:35 +000012546 if (pc != '\\' && pc != '`' && pc != '$'
Denys Vlasenko216913c2018-04-02 12:35:04 +020012547 && (!synstack->dblquote || pc != '"')
Denys Vlasenko76bc2d62009-11-29 01:37:46 +010012548 ) {
Eric Andersenc470f442003-07-28 09:56:35 +000012549 STPUTC('\\', pout);
Denys Vlasenko76bc2d62009-11-29 01:37:46 +010012550 }
Denys Vlasenkocd716832009-11-28 22:14:02 +010012551 if (pc <= 255 /* not PEOA or PEOF */) {
Eric Andersenc470f442003-07-28 09:56:35 +000012552 break;
12553 }
12554 /* fall through */
12555
12556 case PEOF:
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010012557 IF_ASH_ALIAS(case PEOA:)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000012558 raise_error_syntax("EOF in backquote substitution");
Eric Andersenc470f442003-07-28 09:56:35 +000012559
12560 case '\n':
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012561 nlnoprompt();
Eric Andersenc470f442003-07-28 09:56:35 +000012562 break;
12563
12564 default:
12565 break;
12566 }
12567 STPUTC(pc, pout);
12568 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +000012569 done:
Eric Andersenc470f442003-07-28 09:56:35 +000012570 STPUTC('\0', pout);
12571 psavelen = pout - (char *)stackblock();
12572 if (psavelen > 0) {
12573 pstr = grabstackstr(pout);
12574 setinputstring(pstr);
12575 }
12576 }
12577 nlpp = &bqlist;
12578 while (*nlpp)
12579 nlpp = &(*nlpp)->next;
Denis Vlasenko597906c2008-02-20 16:38:54 +000012580 *nlpp = stzalloc(sizeof(**nlpp));
12581 /* (*nlpp)->next = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000012582
12583 if (oldstyle) {
12584 saveprompt = doprompt;
12585 doprompt = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000012586 }
12587
Eric Andersenc470f442003-07-28 09:56:35 +000012588 n = list(2);
12589
12590 if (oldstyle)
12591 doprompt = saveprompt;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012592 else if (readtoken() != TRP)
12593 raise_error_unexpected_syntax(TRP);
Eric Andersenc470f442003-07-28 09:56:35 +000012594
12595 (*nlpp)->n = n;
12596 if (oldstyle) {
12597 /*
12598 * Start reading from old file again, ignoring any pushed back
12599 * tokens left from the backquote parsing
12600 */
12601 popfile();
12602 tokpushback = 0;
12603 }
12604 while (stackblocksize() <= savelen)
12605 growstackblock();
12606 STARTSTACKSTR(out);
12607 if (str) {
12608 memcpy(out, str, savelen);
12609 STADJUST(savelen, out);
Eric Andersenc470f442003-07-28 09:56:35 +000012610 }
Ron Yorston549deab2015-05-18 09:57:51 +020012611 USTPUTC(CTLBACKQ, out);
Eric Andersenc470f442003-07-28 09:56:35 +000012612 if (oldstyle)
12613 goto parsebackq_oldreturn;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000012614 goto parsebackq_newreturn;
Eric Andersenc470f442003-07-28 09:56:35 +000012615}
12616
Denys Vlasenko0b883582016-12-23 16:49:07 +010012617#if ENABLE_FEATURE_SH_MATH
Eric Andersencb57d552001-06-28 07:25:16 +000012618/*
12619 * Parse an arithmetic expansion (indicate start of one and set state)
12620 */
Eric Andersenc470f442003-07-28 09:56:35 +000012621parsearith: {
Denys Vlasenko216913c2018-04-02 12:35:04 +020012622
12623 synstack_push(&synstack,
12624 synstack->prev ?: alloca(sizeof(*synstack)),
12625 ARISYNTAX);
12626 synstack->dblquote = 1;
Ron Yorstonad88bde2015-05-18 09:56:16 +020012627 USTPUTC(CTLARI, out);
Eric Andersenc470f442003-07-28 09:56:35 +000012628 goto parsearith_return;
12629}
12630#endif
Eric Andersenc470f442003-07-28 09:56:35 +000012631} /* end of readtoken */
12632
Eric Andersencb57d552001-06-28 07:25:16 +000012633/*
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012634 * Read the next input token.
12635 * If the token is a word, we set backquotelist to the list of cmds in
12636 * backquotes. We set quoteflag to true if any part of the word was
12637 * quoted.
12638 * If the token is TREDIR, then we set redirnode to a structure containing
12639 * the redirection.
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012640 *
12641 * [Change comment: here documents and internal procedures]
12642 * [Readtoken shouldn't have any arguments. Perhaps we should make the
12643 * word parsing code into a separate routine. In this case, readtoken
12644 * doesn't need to have any internal procedures, but parseword does.
12645 * We could also make parseoperator in essence the main routine, and
12646 * have parseword (readtoken1?) handle both words and redirection.]
Eric Andersencb57d552001-06-28 07:25:16 +000012647 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012648#define NEW_xxreadtoken
12649#ifdef NEW_xxreadtoken
12650/* singles must be first! */
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000012651static const char xxreadtoken_chars[7] ALIGN1 = {
Denis Vlasenko834dee72008-10-07 09:18:30 +000012652 '\n', '(', ')', /* singles */
12653 '&', '|', ';', /* doubles */
12654 0
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000012655};
Eric Andersencb57d552001-06-28 07:25:16 +000012656
Denis Vlasenko834dee72008-10-07 09:18:30 +000012657#define xxreadtoken_singles 3
12658#define xxreadtoken_doubles 3
12659
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000012660static const char xxreadtoken_tokens[] ALIGN1 = {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012661 TNL, TLP, TRP, /* only single occurrence allowed */
12662 TBACKGND, TPIPE, TSEMI, /* if single occurrence */
12663 TEOF, /* corresponds to trailing nul */
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000012664 TAND, TOR, TENDCASE /* if double occurrence */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012665};
12666
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012667static int
12668xxreadtoken(void)
12669{
12670 int c;
12671
12672 if (tokpushback) {
12673 tokpushback = 0;
12674 return lasttoken;
Eric Andersencb57d552001-06-28 07:25:16 +000012675 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020012676 setprompt_if(needprompt, 2);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012677 for (;;) { /* until token or start of word found */
Denys Vlasenko220be532018-03-31 19:21:31 +020012678 c = pgetc_eatbnl();
Denis Vlasenko5e34ff22009-04-21 11:09:40 +000012679 if (c == ' ' || c == '\t' IF_ASH_ALIAS( || c == PEOA))
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012680 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012681
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012682 if (c == '#') {
12683 while ((c = pgetc()) != '\n' && c != PEOF)
12684 continue;
12685 pungetc();
12686 } else if (c == '\\') {
Denys Vlasenko220be532018-03-31 19:21:31 +020012687 break; /* return readtoken1(...) */
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012688 } else {
12689 const char *p;
12690
12691 p = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
12692 if (c != PEOF) {
12693 if (c == '\n') {
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012694 nlnoprompt();
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012695 }
12696
12697 p = strchr(xxreadtoken_chars, c);
Denis Vlasenko834dee72008-10-07 09:18:30 +000012698 if (p == NULL)
12699 break; /* return readtoken1(...) */
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012700
Denis Vlasenko834dee72008-10-07 09:18:30 +000012701 if ((int)(p - xxreadtoken_chars) >= xxreadtoken_singles) {
Denys Vlasenko1e5111b2018-04-01 03:04:55 +020012702 int cc = pgetc_eatbnl();
Denis Vlasenko834dee72008-10-07 09:18:30 +000012703 if (cc == c) { /* double occurrence? */
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012704 p += xxreadtoken_doubles + 1;
12705 } else {
12706 pungetc();
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010012707#if BASH_REDIR_OUTPUT
Denis Vlasenko834dee72008-10-07 09:18:30 +000012708 if (c == '&' && cc == '>') /* &> */
12709 break; /* return readtoken1(...) */
12710#endif
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012711 }
12712 }
12713 }
12714 lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
12715 return lasttoken;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012716 }
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012717 } /* for (;;) */
Denis Vlasenko834dee72008-10-07 09:18:30 +000012718
12719 return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012720}
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012721#else /* old xxreadtoken */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012722#define RETURN(token) return lasttoken = token
12723static int
12724xxreadtoken(void)
12725{
12726 int c;
12727
12728 if (tokpushback) {
12729 tokpushback = 0;
12730 return lasttoken;
12731 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020012732 setprompt_if(needprompt, 2);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012733 for (;;) { /* until token or start of word found */
Denys Vlasenko220be532018-03-31 19:21:31 +020012734 c = pgetc_eatbnl();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012735 switch (c) {
12736 case ' ': case '\t':
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010012737 IF_ASH_ALIAS(case PEOA:)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012738 continue;
12739 case '#':
Denis Vlasenkof7d56652008-03-25 05:51:41 +000012740 while ((c = pgetc()) != '\n' && c != PEOF)
12741 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012742 pungetc();
12743 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012744 case '\n':
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012745 nlnoprompt();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012746 RETURN(TNL);
12747 case PEOF:
12748 RETURN(TEOF);
12749 case '&':
Denys Vlasenko220be532018-03-31 19:21:31 +020012750 if (pgetc_eatbnl() == '&')
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012751 RETURN(TAND);
12752 pungetc();
12753 RETURN(TBACKGND);
12754 case '|':
Denys Vlasenko220be532018-03-31 19:21:31 +020012755 if (pgetc_eatbnl() == '|')
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012756 RETURN(TOR);
12757 pungetc();
12758 RETURN(TPIPE);
12759 case ';':
Denys Vlasenko220be532018-03-31 19:21:31 +020012760 if (pgetc_eatbnl() == ';')
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012761 RETURN(TENDCASE);
12762 pungetc();
12763 RETURN(TSEMI);
12764 case '(':
12765 RETURN(TLP);
12766 case ')':
12767 RETURN(TRP);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012768 }
Denys Vlasenko220be532018-03-31 19:21:31 +020012769 break;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012770 }
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012771 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
12772#undef RETURN
12773}
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012774#endif /* old xxreadtoken */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012775
12776static int
12777readtoken(void)
12778{
12779 int t;
Ron Yorston713f07d2015-10-29 16:44:56 +000012780 int kwd = checkkwd;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012781#if DEBUG
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000012782 smallint alreadyseen = tokpushback;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012783#endif
12784
12785#if ENABLE_ASH_ALIAS
12786 top:
12787#endif
12788
12789 t = xxreadtoken();
12790
12791 /*
12792 * eat newlines
12793 */
Ron Yorston713f07d2015-10-29 16:44:56 +000012794 if (kwd & CHKNL) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012795 while (t == TNL) {
12796 parseheredoc();
12797 t = xxreadtoken();
12798 }
12799 }
12800
12801 if (t != TWORD || quoteflag) {
12802 goto out;
12803 }
12804
12805 /*
12806 * check for keywords
12807 */
Ron Yorston713f07d2015-10-29 16:44:56 +000012808 if (kwd & CHKKWD) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012809 const char *const *pp;
12810
12811 pp = findkwd(wordtext);
12812 if (pp) {
12813 lasttoken = t = pp - tokname_array;
Denys Vlasenko888527c2016-10-02 16:54:17 +020012814 TRACE(("keyword '%s' recognized\n", tokname_array[t]));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012815 goto out;
12816 }
12817 }
12818
12819 if (checkkwd & CHKALIAS) {
12820#if ENABLE_ASH_ALIAS
12821 struct alias *ap;
12822 ap = lookupalias(wordtext, 1);
12823 if (ap != NULL) {
12824 if (*ap->val) {
12825 pushstring(ap->val, ap);
12826 }
12827 goto top;
12828 }
12829#endif
12830 }
12831 out:
12832 checkkwd = 0;
12833#if DEBUG
12834 if (!alreadyseen)
Denys Vlasenko888527c2016-10-02 16:54:17 +020012835 TRACE(("token '%s' %s\n", tokname_array[t], t == TWORD ? wordtext : ""));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012836 else
Denys Vlasenko888527c2016-10-02 16:54:17 +020012837 TRACE(("reread token '%s' %s\n", tokname_array[t], t == TWORD ? wordtext : ""));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012838#endif
12839 return t;
Eric Andersencb57d552001-06-28 07:25:16 +000012840}
12841
Ron Yorstonc0e00762015-10-29 11:30:55 +000012842static int
Ron Yorston6bd2fab2015-10-29 11:30:22 +000012843peektoken(void)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012844{
12845 int t;
12846
12847 t = readtoken();
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000012848 tokpushback = 1;
Ron Yorstonc0e00762015-10-29 11:30:55 +000012849 return t;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012850}
Eric Andersencb57d552001-06-28 07:25:16 +000012851
12852/*
Denys Vlasenko86e83ec2009-07-23 22:07:07 +020012853 * Read and parse a command. Returns NODE_EOF on end of file.
12854 * (NULL is a valid parse tree indicating a blank line.)
Eric Andersencb57d552001-06-28 07:25:16 +000012855 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012856static union node *
12857parsecmd(int interact)
Eric Andersen90898442003-08-06 11:20:52 +000012858{
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012859 tokpushback = 0;
Ron Yorstonc0e00762015-10-29 11:30:55 +000012860 checkkwd = 0;
12861 heredoclist = 0;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012862 doprompt = interact;
Denys Vlasenko958581a2010-09-12 15:04:27 +020012863 setprompt_if(doprompt, doprompt);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012864 needprompt = 0;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012865 return list(1);
12866}
12867
12868/*
12869 * Input any here documents.
12870 */
12871static void
12872parseheredoc(void)
12873{
12874 struct heredoc *here;
12875 union node *n;
12876
12877 here = heredoclist;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000012878 heredoclist = NULL;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012879
12880 while (here) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020012881 setprompt_if(needprompt, 2);
12882 readtoken1(pgetc(), here->here->type == NHERE ? SQSYNTAX : DQSYNTAX,
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012883 here->eofmark, here->striptabs);
Denis Vlasenko597906c2008-02-20 16:38:54 +000012884 n = stzalloc(sizeof(struct narg));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012885 n->narg.type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000012886 /*n->narg.next = NULL; - stzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012887 n->narg.text = wordtext;
12888 n->narg.backquote = backquotelist;
12889 here->here->nhere.doc = n;
12890 here = here->next;
Eric Andersencb57d552001-06-28 07:25:16 +000012891 }
Eric Andersencb57d552001-06-28 07:25:16 +000012892}
12893
12894
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012895static const char *
Denys Vlasenko46999802017-07-29 21:12:29 +020012896expandstr(const char *ps, int syntax_type)
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012897{
12898 union node n;
Denys Vlasenko2a6d29a2016-10-25 21:17:52 +020012899 int saveprompt;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012900
Denys Vlasenko46999802017-07-29 21:12:29 +020012901 /* XXX Fix (char *) cast. */
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012902 setinputstring((char *)ps);
Denys Vlasenko2a6d29a2016-10-25 21:17:52 +020012903
12904 saveprompt = doprompt;
12905 doprompt = 0;
Denys Vlasenkoa2e32b32017-10-12 19:20:13 +020012906
12907 /* readtoken1() might die horribly.
Denys Vlasenko3c183a82017-10-12 19:35:42 +020012908 * Try a prompt with syntactically wrong command:
Denys Vlasenkoa2e32b32017-10-12 19:20:13 +020012909 * PS1='$(date "+%H:%M:%S) > '
12910 */
12911 {
12912 volatile int saveint;
12913 struct jmploc *volatile savehandler = exception_handler;
12914 struct jmploc jmploc;
12915 SAVE_INT(saveint);
12916 if (setjmp(jmploc.loc) == 0) {
12917 exception_handler = &jmploc;
12918 readtoken1(pgetc(), syntax_type, FAKEEOFMARK, 0);
12919 }
12920 exception_handler = savehandler;
12921 RESTORE_INT(saveint);
12922 }
12923
Denys Vlasenko2a6d29a2016-10-25 21:17:52 +020012924 doprompt = saveprompt;
12925
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012926 popfile();
12927
12928 n.narg.type = NARG;
12929 n.narg.next = NULL;
12930 n.narg.text = wordtext;
12931 n.narg.backquote = backquotelist;
12932
Ron Yorston549deab2015-05-18 09:57:51 +020012933 expandarg(&n, NULL, EXP_QUOTED);
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012934 return stackblock();
12935}
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012936
Denys Vlasenko1e3e2cc2017-07-25 20:31:14 +020012937static inline int
12938parser_eof(void)
12939{
12940 return tokpushback && lasttoken == TEOF;
12941}
12942
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012943/*
12944 * Execute a command or commands contained in a string.
12945 */
12946static int
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020012947evalstring(char *s, int flags)
Eric Andersenc470f442003-07-28 09:56:35 +000012948{
Denys Vlasenko493b9ca2016-10-30 18:27:14 +010012949 struct jmploc *volatile savehandler;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012950 struct jmploc jmploc;
12951 int ex;
12952
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012953 union node *n;
12954 struct stackmark smark;
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012955 int status;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012956
Denys Vlasenko8e2bc472016-09-28 23:02:57 +020012957 s = sstrdup(s);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012958 setinputstring(s);
12959 setstackmark(&smark);
12960
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012961 status = 0;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012962 /* On exception inside execution loop, we must popfile().
12963 * Try interactively:
12964 * readonly a=a
12965 * command eval "a=b" # throws "is read only" error
12966 * "command BLTIN" is not supposed to abort (even in non-interactive use).
12967 * But if we skip popfile(), we hit EOF in eval's string, and exit.
12968 */
12969 savehandler = exception_handler;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012970 ex = setjmp(jmploc.loc);
12971 if (ex)
12972 goto out;
Denys Vlasenko493b9ca2016-10-30 18:27:14 +010012973 exception_handler = &jmploc;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012974
Denys Vlasenko86e83ec2009-07-23 22:07:07 +020012975 while ((n = parsecmd(0)) != NODE_EOF) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020012976 int i;
12977
Denys Vlasenko1e3e2cc2017-07-25 20:31:14 +020012978 i = evaltree(n, flags & ~(parser_eof() ? 0 : EV_EXIT));
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012979 if (n)
12980 status = i;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012981 popstackmark(&smark);
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012982 if (evalskip)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012983 break;
12984 }
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012985 out:
Denys Vlasenko8e2bc472016-09-28 23:02:57 +020012986 popstackmark(&smark);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012987 popfile();
Denys Vlasenko8e2bc472016-09-28 23:02:57 +020012988 stunalloc(s);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012989
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012990 exception_handler = savehandler;
12991 if (ex)
Denys Vlasenko14c85eb2017-10-12 19:40:47 +020012992 longjmp(exception_handler->loc, ex);
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012993
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012994 return status;
Eric Andersenc470f442003-07-28 09:56:35 +000012995}
12996
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012997/*
12998 * The eval command.
12999 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013000static int FAST_FUNC
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020013001evalcmd(int argc UNUSED_PARAM, char **argv, int flags)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013002{
13003 char *p;
13004 char *concat;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013005
Denis Vlasenko68404f12008-03-17 09:00:54 +000013006 if (argv[1]) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013007 p = argv[1];
Denis Vlasenko68404f12008-03-17 09:00:54 +000013008 argv += 2;
13009 if (argv[0]) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013010 STARTSTACKSTR(concat);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013011 for (;;) {
13012 concat = stack_putstr(p, concat);
Denis Vlasenko68404f12008-03-17 09:00:54 +000013013 p = *argv++;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013014 if (p == NULL)
13015 break;
13016 STPUTC(' ', concat);
13017 }
13018 STPUTC('\0', concat);
13019 p = grabstackstr(concat);
13020 }
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020013021 return evalstring(p, flags & EV_TESTED);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013022 }
Denys Vlasenko928e2a72016-09-29 00:30:31 +020013023 return 0;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013024}
13025
13026/*
Denys Vlasenko285ad152009-12-04 23:02:27 +010013027 * Read and execute commands.
13028 * "Top" is nonzero for the top level command loop;
13029 * it turns on prompting if the shell is interactive.
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013030 */
13031static int
13032cmdloop(int top)
13033{
13034 union node *n;
13035 struct stackmark smark;
13036 int inter;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020013037 int status = 0;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013038 int numeof = 0;
13039
13040 TRACE(("cmdloop(%d) called\n", top));
13041 for (;;) {
13042 int skip;
13043
13044 setstackmark(&smark);
13045#if JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +000013046 if (doing_jobctl)
Denys Vlasenko9c541002015-10-07 15:44:36 +020013047 showjobs(SHOW_CHANGED|SHOW_STDERR);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013048#endif
13049 inter = 0;
13050 if (iflag && top) {
13051 inter++;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013052 chkmail();
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013053 }
13054 n = parsecmd(inter);
Denys Vlasenko7cee00e2009-07-24 01:08:03 +020013055#if DEBUG
13056 if (DEBUG > 2 && debug && (n != NODE_EOF))
Denys Vlasenko883cea42009-07-11 15:31:59 +020013057 showtree(n);
Denis Vlasenko135cecb2009-04-12 00:00:57 +000013058#endif
Denys Vlasenko86e83ec2009-07-23 22:07:07 +020013059 if (n == NODE_EOF) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013060 if (!top || numeof >= 50)
13061 break;
13062 if (!stoppedjobs()) {
13063 if (!Iflag)
13064 break;
13065 out2str("\nUse \"exit\" to leave shell.\n");
13066 }
13067 numeof++;
13068 } else if (nflag == 0) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020013069 int i;
13070
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +000013071 /* job_warning can only be 2,1,0. Here 2->1, 1/0->0 */
13072 job_warning >>= 1;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013073 numeof = 0;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020013074 i = evaltree(n, 0);
13075 if (n)
13076 status = i;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013077 }
13078 popstackmark(&smark);
13079 skip = evalskip;
13080
13081 if (skip) {
Denys Vlasenko6a0710e2016-09-30 14:18:34 +020013082 evalskip &= ~SKIPFUNC;
Denys Vlasenko0840c912016-10-01 15:27:44 +020013083 break;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013084 }
13085 }
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020013086 return status;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013087}
13088
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000013089/*
13090 * Take commands from a file. To be compatible we should do a path
13091 * search for the file, which is necessary to find sub-commands.
13092 */
13093static char *
13094find_dot_file(char *name)
13095{
13096 char *fullname;
13097 const char *path = pathval();
13098 struct stat statb;
13099
13100 /* don't try this for absolute or relative paths */
13101 if (strchr(name, '/'))
13102 return name;
13103
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020013104 while ((fullname = path_advance(&path, name)) != NULL) {
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000013105 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
13106 /*
13107 * Don't bother freeing here, since it will
13108 * be freed by the caller.
13109 */
13110 return fullname;
13111 }
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020013112 if (fullname != name)
13113 stunalloc(fullname);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000013114 }
Denys Vlasenko01f7b9e2018-01-26 15:15:43 +010013115 /* not found in PATH */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000013116
Denys Vlasenko01f7b9e2018-01-26 15:15:43 +010013117#if ENABLE_ASH_BASH_SOURCE_CURDIR
13118 return name;
13119#else
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000013120 ash_msg_and_raise_error("%s: not found", name);
13121 /* NOTREACHED */
Denys Vlasenko01f7b9e2018-01-26 15:15:43 +010013122#endif
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000013123}
13124
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013125static int FAST_FUNC
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020013126dotcmd(int argc_ UNUSED_PARAM, char **argv_ UNUSED_PARAM)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013127{
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020013128 /* "false; . empty_file; echo $?" should print 0, not 1: */
13129 int status = 0;
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020013130 char *fullname;
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020013131 char **argv;
Denys Vlasenkofb87d932017-01-09 08:22:06 +010013132 char *args_need_save;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013133 volatile struct shparam saveparam;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013134
Denys Vlasenko981a0562017-07-26 19:53:11 +020013135//???
13136// struct strlist *sp;
13137// for (sp = cmdenviron; sp; sp = sp->next)
13138// setvareq(ckstrdup(sp->text), VSTRFIXED | VTEXTFIXED);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013139
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020013140 nextopt(nullstr); /* handle possible "--" */
13141 argv = argptr;
13142
13143 if (!argv[0]) {
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020013144 /* bash says: "bash: .: filename argument required" */
13145 return 2; /* bash compat */
13146 }
13147
Denys Vlasenko091f8312013-03-17 14:25:22 +010013148 /* This aborts if file isn't found, which is POSIXly correct.
13149 * bash returns exitcode 1 instead.
13150 */
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020013151 fullname = find_dot_file(argv[0]);
13152 argv++;
Denys Vlasenkofb87d932017-01-09 08:22:06 +010013153 args_need_save = argv[0];
Denys Vlasenko5f7c82b2017-02-03 13:00:06 +010013154 if (args_need_save) { /* ". FILE ARGS", and ARGS are not empty */
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020013155 int argc;
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020013156 saveparam = shellparam;
13157 shellparam.malloced = 0;
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020013158 argc = 1;
13159 while (argv[argc])
13160 argc++;
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020013161 shellparam.nparam = argc;
13162 shellparam.p = argv;
13163 };
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013164
Denys Vlasenko091f8312013-03-17 14:25:22 +010013165 /* This aborts if file can't be opened, which is POSIXly correct.
13166 * bash returns exitcode 1 instead.
13167 */
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020013168 setinputfile(fullname, INPUT_PUSH_FILE);
13169 commandname = fullname;
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020013170 status = cmdloop(0);
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020013171 popfile();
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013172
Denys Vlasenkofb87d932017-01-09 08:22:06 +010013173 if (args_need_save) {
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020013174 freeparam(&shellparam);
13175 shellparam = saveparam;
13176 };
13177
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020013178 return status;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013179}
13180
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013181static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013182exitcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013183{
13184 if (stoppedjobs())
13185 return 0;
Denis Vlasenko68404f12008-03-17 09:00:54 +000013186 if (argv[1])
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013187 exitstatus = number(argv[1]);
13188 raise_exception(EXEXIT);
13189 /* NOTREACHED */
13190}
13191
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013192/*
13193 * Read a file containing shell functions.
13194 */
13195static void
13196readcmdfile(char *name)
13197{
13198 setinputfile(name, INPUT_PUSH_FILE);
13199 cmdloop(0);
13200 popfile();
13201}
13202
13203
Denis Vlasenkocc571512007-02-23 21:10:35 +000013204/* ============ find_command inplementation */
13205
13206/*
13207 * Resolve a command name. If you change this routine, you may have to
13208 * change the shellexec routine as well.
13209 */
13210static void
13211find_command(char *name, struct cmdentry *entry, int act, const char *path)
13212{
13213 struct tblentry *cmdp;
13214 int idx;
13215 int prev;
13216 char *fullname;
13217 struct stat statb;
13218 int e;
13219 int updatetbl;
13220 struct builtincmd *bcmd;
13221
13222 /* If name contains a slash, don't use PATH or hash table */
13223 if (strchr(name, '/') != NULL) {
13224 entry->u.index = -1;
13225 if (act & DO_ABS) {
13226 while (stat(name, &statb) < 0) {
13227#ifdef SYSV
13228 if (errno == EINTR)
13229 continue;
13230#endif
13231 entry->cmdtype = CMDUNKNOWN;
13232 return;
13233 }
13234 }
13235 entry->cmdtype = CMDNORMAL;
13236 return;
13237 }
13238
Denis Vlasenkof20de5b2007-04-29 23:42:54 +000013239/* #if ENABLE_FEATURE_SH_STANDALONE... moved after builtin check */
Denis Vlasenkocc571512007-02-23 21:10:35 +000013240
13241 updatetbl = (path == pathval());
13242 if (!updatetbl) {
13243 act |= DO_ALTPATH;
13244 if (strstr(path, "%builtin") != NULL)
13245 act |= DO_ALTBLTIN;
13246 }
13247
13248 /* If name is in the table, check answer will be ok */
13249 cmdp = cmdlookup(name, 0);
13250 if (cmdp != NULL) {
13251 int bit;
13252
13253 switch (cmdp->cmdtype) {
13254 default:
13255#if DEBUG
13256 abort();
13257#endif
13258 case CMDNORMAL:
13259 bit = DO_ALTPATH;
13260 break;
13261 case CMDFUNCTION:
13262 bit = DO_NOFUNC;
13263 break;
13264 case CMDBUILTIN:
13265 bit = DO_ALTBLTIN;
13266 break;
13267 }
13268 if (act & bit) {
13269 updatetbl = 0;
13270 cmdp = NULL;
13271 } else if (cmdp->rehash == 0)
13272 /* if not invalidated by cd, we're done */
13273 goto success;
13274 }
13275
13276 /* If %builtin not in path, check for builtin next */
13277 bcmd = find_builtin(name);
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000013278 if (bcmd) {
13279 if (IS_BUILTIN_REGULAR(bcmd))
13280 goto builtin_success;
13281 if (act & DO_ALTPATH) {
13282 if (!(act & DO_ALTBLTIN))
13283 goto builtin_success;
13284 } else if (builtinloc <= 0) {
13285 goto builtin_success;
Denis Vlasenko8e858e22007-03-07 09:35:43 +000013286 }
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000013287 }
Denis Vlasenkocc571512007-02-23 21:10:35 +000013288
Denis Vlasenkof20de5b2007-04-29 23:42:54 +000013289#if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko7465dbc2008-04-13 02:25:53 +000013290 {
13291 int applet_no = find_applet_by_name(name);
13292 if (applet_no >= 0) {
13293 entry->cmdtype = CMDNORMAL;
13294 entry->u.index = -2 - applet_no;
13295 return;
13296 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +000013297 }
13298#endif
13299
Denis Vlasenkocc571512007-02-23 21:10:35 +000013300 /* We have to search path. */
13301 prev = -1; /* where to start */
13302 if (cmdp && cmdp->rehash) { /* doing a rehash */
13303 if (cmdp->cmdtype == CMDBUILTIN)
13304 prev = builtinloc;
13305 else
13306 prev = cmdp->param.index;
13307 }
13308
13309 e = ENOENT;
13310 idx = -1;
13311 loop:
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020013312 while ((fullname = path_advance(&path, name)) != NULL) {
Denis Vlasenkocc571512007-02-23 21:10:35 +000013313 stunalloc(fullname);
Denis Vlasenkodee82b62007-07-29 14:05:27 +000013314 /* NB: code below will still use fullname
13315 * despite it being "unallocated" */
Denis Vlasenkocc571512007-02-23 21:10:35 +000013316 idx++;
13317 if (pathopt) {
13318 if (prefix(pathopt, "builtin")) {
13319 if (bcmd)
13320 goto builtin_success;
13321 continue;
Denis Vlasenko4a9ca132008-04-12 20:07:08 +000013322 }
13323 if ((act & DO_NOFUNC)
13324 || !prefix(pathopt, "func")
Denys Vlasenkoe4dcba12010-10-28 18:57:19 +020013325 ) { /* ignore unimplemented options */
Denis Vlasenkocc571512007-02-23 21:10:35 +000013326 continue;
13327 }
13328 }
13329 /* if rehash, don't redo absolute path names */
13330 if (fullname[0] == '/' && idx <= prev) {
13331 if (idx < prev)
13332 continue;
13333 TRACE(("searchexec \"%s\": no change\n", name));
13334 goto success;
13335 }
13336 while (stat(fullname, &statb) < 0) {
13337#ifdef SYSV
13338 if (errno == EINTR)
13339 continue;
13340#endif
13341 if (errno != ENOENT && errno != ENOTDIR)
13342 e = errno;
13343 goto loop;
13344 }
13345 e = EACCES; /* if we fail, this will be the error */
13346 if (!S_ISREG(statb.st_mode))
13347 continue;
13348 if (pathopt) { /* this is a %func directory */
13349 stalloc(strlen(fullname) + 1);
Denis Vlasenkodee82b62007-07-29 14:05:27 +000013350 /* NB: stalloc will return space pointed by fullname
13351 * (because we don't have any intervening allocations
13352 * between stunalloc above and this stalloc) */
Denis Vlasenkocc571512007-02-23 21:10:35 +000013353 readcmdfile(fullname);
13354 cmdp = cmdlookup(name, 0);
13355 if (cmdp == NULL || cmdp->cmdtype != CMDFUNCTION)
13356 ash_msg_and_raise_error("%s not defined in %s", name, fullname);
13357 stunalloc(fullname);
13358 goto success;
13359 }
13360 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
13361 if (!updatetbl) {
13362 entry->cmdtype = CMDNORMAL;
13363 entry->u.index = idx;
13364 return;
13365 }
13366 INT_OFF;
13367 cmdp = cmdlookup(name, 1);
13368 cmdp->cmdtype = CMDNORMAL;
13369 cmdp->param.index = idx;
13370 INT_ON;
13371 goto success;
13372 }
13373
13374 /* We failed. If there was an entry for this command, delete it */
13375 if (cmdp && updatetbl)
13376 delete_cmd_entry();
William Pitcockd8fd88a2018-01-24 18:33:18 +010013377 if (act & DO_ERR) {
13378#if ENABLE_ASH_BASH_NOT_FOUND_HOOK
13379 struct tblentry *hookp = cmdlookup("command_not_found_handle", 0);
13380 if (hookp && hookp->cmdtype == CMDFUNCTION) {
13381 char *argv[3];
13382 argv[0] = (char*) "command_not_found_handle";
13383 argv[1] = name;
13384 argv[2] = NULL;
13385 evalfun(hookp->param.func, 2, argv, 0);
13386 entry->cmdtype = CMDUNKNOWN;
13387 return;
13388 }
13389#endif
Denis Vlasenkocc571512007-02-23 21:10:35 +000013390 ash_msg("%s: %s", name, errmsg(e, "not found"));
William Pitcockd8fd88a2018-01-24 18:33:18 +010013391 }
Denis Vlasenkocc571512007-02-23 21:10:35 +000013392 entry->cmdtype = CMDUNKNOWN;
13393 return;
13394
13395 builtin_success:
13396 if (!updatetbl) {
13397 entry->cmdtype = CMDBUILTIN;
13398 entry->u.cmd = bcmd;
13399 return;
13400 }
13401 INT_OFF;
13402 cmdp = cmdlookup(name, 1);
13403 cmdp->cmdtype = CMDBUILTIN;
13404 cmdp->param.cmd = bcmd;
13405 INT_ON;
13406 success:
13407 cmdp->rehash = 0;
13408 entry->cmdtype = cmdp->cmdtype;
13409 entry->u = cmdp->param;
13410}
13411
13412
Eric Andersencb57d552001-06-28 07:25:16 +000013413/*
Eric Andersencb57d552001-06-28 07:25:16 +000013414 * The trap builtin.
13415 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013416static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013417trapcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +000013418{
13419 char *action;
13420 char **ap;
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010013421 int signo, exitcode;
Eric Andersencb57d552001-06-28 07:25:16 +000013422
Eric Andersenc470f442003-07-28 09:56:35 +000013423 nextopt(nullstr);
13424 ap = argptr;
13425 if (!*ap) {
Denis Vlasenko2da584f2007-02-19 22:44:05 +000013426 for (signo = 0; signo < NSIG; signo++) {
Denys Vlasenko21d87d42009-09-25 00:06:51 +020013427 char *tr = trap_ptr[signo];
13428 if (tr) {
Denys Vlasenkoe74aaf92009-09-27 02:05:45 +020013429 /* note: bash adds "SIG", but only if invoked
13430 * as "bash". If called as "sh", or if set -o posix,
13431 * then it prints short signal names.
13432 * We are printing short names: */
13433 out1fmt("trap -- %s %s\n",
Denys Vlasenko21d87d42009-09-25 00:06:51 +020013434 single_quote(tr),
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +000013435 get_signame(signo));
Denys Vlasenko726e1a02009-09-25 02:58:20 +020013436 /* trap_ptr != trap only if we are in special-cased `trap` code.
13437 * In this case, we will exit very soon, no need to free(). */
Denys Vlasenkoe74aaf92009-09-27 02:05:45 +020013438 /* if (trap_ptr != trap && tp[0]) */
Denys Vlasenko726e1a02009-09-25 02:58:20 +020013439 /* free(tr); */
Eric Andersencb57d552001-06-28 07:25:16 +000013440 }
13441 }
Denys Vlasenko726e1a02009-09-25 02:58:20 +020013442 /*
Denys Vlasenko21d87d42009-09-25 00:06:51 +020013443 if (trap_ptr != trap) {
13444 free(trap_ptr);
13445 trap_ptr = trap;
13446 }
Denys Vlasenko726e1a02009-09-25 02:58:20 +020013447 */
Eric Andersencb57d552001-06-28 07:25:16 +000013448 return 0;
13449 }
Denys Vlasenko21d87d42009-09-25 00:06:51 +020013450
Denys Vlasenko86981e32017-07-25 20:06:17 +020013451 /* Why the second check?
13452 * "trap NUM [sig2]..." is the same as "trap - NUM [sig2]..."
13453 * In this case, NUM is signal no, not an action.
13454 */
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +000013455 action = NULL;
Denys Vlasenko86981e32017-07-25 20:06:17 +020013456 if (ap[1] && !is_number(ap[0]))
Eric Andersencb57d552001-06-28 07:25:16 +000013457 action = *ap++;
Denys Vlasenko86981e32017-07-25 20:06:17 +020013458
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010013459 exitcode = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000013460 while (*ap) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000013461 signo = get_signum(*ap);
Denys Vlasenko86981e32017-07-25 20:06:17 +020013462 if (signo < 0) {
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010013463 /* Mimic bash message exactly */
13464 ash_msg("%s: invalid signal specification", *ap);
13465 exitcode = 1;
13466 goto next;
13467 }
Denis Vlasenkob012b102007-02-19 22:43:01 +000013468 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +000013469 if (action) {
Denis Vlasenko9f739442006-12-16 23:49:13 +000013470 if (LONE_DASH(action))
Eric Andersencb57d552001-06-28 07:25:16 +000013471 action = NULL;
Denys Vlasenkob4f51d32016-10-27 12:55:09 +020013472 else {
13473 if (action[0]) /* not NULL and not "" and not "-" */
13474 may_have_traps = 1;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013475 action = ckstrdup(action);
Denys Vlasenkob4f51d32016-10-27 12:55:09 +020013476 }
Eric Andersencb57d552001-06-28 07:25:16 +000013477 }
Denis Vlasenko60818682007-09-28 22:07:23 +000013478 free(trap[signo]);
Eric Andersencb57d552001-06-28 07:25:16 +000013479 trap[signo] = action;
13480 if (signo != 0)
13481 setsignal(signo);
Denis Vlasenkob012b102007-02-19 22:43:01 +000013482 INT_ON;
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010013483 next:
Eric Andersencb57d552001-06-28 07:25:16 +000013484 ap++;
13485 }
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010013486 return exitcode;
Eric Andersencb57d552001-06-28 07:25:16 +000013487}
13488
Eric Andersenc470f442003-07-28 09:56:35 +000013489
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013490/* ============ Builtins */
Eric Andersenc470f442003-07-28 09:56:35 +000013491
Denys Vlasenko2ec34962014-09-08 16:52:39 +020013492#if ENABLE_ASH_HELP
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013493static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013494helpcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000013495{
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000013496 unsigned col;
13497 unsigned i;
Eric Andersenc470f442003-07-28 09:56:35 +000013498
Denys Vlasenkod6b05eb2009-06-06 20:59:55 +020013499 out1fmt(
Denis Vlasenko34d4d892009-04-04 20:24:37 +000013500 "Built-in commands:\n"
13501 "------------------\n");
Denis Vlasenkob71c6682007-07-21 15:08:09 +000013502 for (col = 0, i = 0; i < ARRAY_SIZE(builtintab); i++) {
Eric Andersenc470f442003-07-28 09:56:35 +000013503 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
Denis Vlasenko52764022007-02-24 13:42:56 +000013504 builtintab[i].name + 1);
Eric Andersenc470f442003-07-28 09:56:35 +000013505 if (col > 60) {
13506 out1fmt("\n");
13507 col = 0;
13508 }
13509 }
Denys Vlasenko2ec34962014-09-08 16:52:39 +020013510# if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko1aa7e472007-11-28 06:49:03 +000013511 {
13512 const char *a = applet_names;
13513 while (*a) {
13514 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), a);
13515 if (col > 60) {
13516 out1fmt("\n");
13517 col = 0;
13518 }
Ron Yorston2b919582016-04-08 11:57:20 +010013519 while (*a++ != '\0')
13520 continue;
Eric Andersenc470f442003-07-28 09:56:35 +000013521 }
13522 }
Denys Vlasenko2ec34962014-09-08 16:52:39 +020013523# endif
Denys Vlasenkoebedb942016-10-02 18:45:09 +020013524 newline_and_flush(stdout);
Eric Andersenc470f442003-07-28 09:56:35 +000013525 return EXIT_SUCCESS;
13526}
Denys Vlasenko2ec34962014-09-08 16:52:39 +020013527#endif
Eric Andersenc470f442003-07-28 09:56:35 +000013528
Flemming Madsend96ffda2013-04-07 18:47:24 +020013529#if MAX_HISTORY
13530static int FAST_FUNC
13531historycmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
13532{
13533 show_history(line_input_state);
13534 return EXIT_SUCCESS;
13535}
13536#endif
13537
Eric Andersencb57d552001-06-28 07:25:16 +000013538/*
Eric Andersencb57d552001-06-28 07:25:16 +000013539 * The export and readonly commands.
13540 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013541static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013542exportcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000013543{
13544 struct var *vp;
13545 char *name;
13546 const char *p;
Eric Andersenc470f442003-07-28 09:56:35 +000013547 char **aptr;
Denys Vlasenkod5275882012-10-01 13:41:17 +020013548 char opt;
13549 int flag;
13550 int flag_off;
Eric Andersencb57d552001-06-28 07:25:16 +000013551
Denys Vlasenkod5275882012-10-01 13:41:17 +020013552 /* "readonly" in bash accepts, but ignores -n.
13553 * We do the same: it saves a conditional in nextopt's param.
13554 */
13555 flag_off = 0;
13556 while ((opt = nextopt("np")) != '\0') {
13557 if (opt == 'n')
13558 flag_off = VEXPORT;
13559 }
13560 flag = VEXPORT;
13561 if (argv[0][0] == 'r') {
13562 flag = VREADONLY;
13563 flag_off = 0; /* readonly ignores -n */
13564 }
13565 flag_off = ~flag_off;
13566
Denys Vlasenko10ad6222017-04-17 16:13:32 +020013567 /*if (opt_p_not_specified) - bash doesn't check this. Try "export -p NAME" */
Denys Vlasenkod5275882012-10-01 13:41:17 +020013568 {
Denis Vlasenko2da584f2007-02-19 22:44:05 +000013569 aptr = argptr;
13570 name = *aptr;
13571 if (name) {
13572 do {
13573 p = strchr(name, '=');
13574 if (p != NULL) {
13575 p++;
13576 } else {
13577 vp = *findvar(hashvar(name), name);
13578 if (vp) {
Denys Vlasenkod5275882012-10-01 13:41:17 +020013579 vp->flags = ((vp->flags | flag) & flag_off);
Denis Vlasenko2da584f2007-02-19 22:44:05 +000013580 continue;
13581 }
Eric Andersencb57d552001-06-28 07:25:16 +000013582 }
Denys Vlasenkod5275882012-10-01 13:41:17 +020013583 setvar(name, p, (flag & flag_off));
Denis Vlasenko2da584f2007-02-19 22:44:05 +000013584 } while ((name = *++aptr) != NULL);
13585 return 0;
13586 }
Eric Andersencb57d552001-06-28 07:25:16 +000013587 }
Denys Vlasenkod5275882012-10-01 13:41:17 +020013588
13589 /* No arguments. Show the list of exported or readonly vars.
13590 * -n is ignored.
13591 */
Denis Vlasenko2da584f2007-02-19 22:44:05 +000013592 showvars(argv[0], flag, 0);
Eric Andersencb57d552001-06-28 07:25:16 +000013593 return 0;
13594}
13595
Eric Andersencb57d552001-06-28 07:25:16 +000013596/*
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000013597 * Delete a function if it exists.
Eric Andersencb57d552001-06-28 07:25:16 +000013598 */
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +000013599static void
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000013600unsetfunc(const char *name)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000013601{
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000013602 struct tblentry *cmdp;
Eric Andersencb57d552001-06-28 07:25:16 +000013603
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000013604 cmdp = cmdlookup(name, 0);
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020013605 if (cmdp != NULL && cmdp->cmdtype == CMDFUNCTION)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000013606 delete_cmd_entry();
Eric Andersenc470f442003-07-28 09:56:35 +000013607}
13608
Eric Andersencb57d552001-06-28 07:25:16 +000013609/*
Eric Andersencb57d552001-06-28 07:25:16 +000013610 * The unset builtin command. We unset the function before we unset the
13611 * variable to allow a function to be unset when there is a readonly variable
13612 * with the same name.
13613 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013614static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013615unsetcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +000013616{
13617 char **ap;
13618 int i;
Eric Andersenc470f442003-07-28 09:56:35 +000013619 int flag = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000013620
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020013621 while ((i = nextopt("vf")) != 0) {
Eric Andersenc470f442003-07-28 09:56:35 +000013622 flag = i;
Eric Andersencb57d552001-06-28 07:25:16 +000013623 }
Eric Andersencb57d552001-06-28 07:25:16 +000013624
Denis Vlasenko2da584f2007-02-19 22:44:05 +000013625 for (ap = argptr; *ap; ap++) {
Eric Andersenc470f442003-07-28 09:56:35 +000013626 if (flag != 'f') {
Denys Vlasenkob28d4c32017-07-25 16:29:36 +020013627 unsetvar(*ap);
13628 continue;
Eric Andersenc470f442003-07-28 09:56:35 +000013629 }
13630 if (flag != 'v')
Eric Andersencb57d552001-06-28 07:25:16 +000013631 unsetfunc(*ap);
Eric Andersencb57d552001-06-28 07:25:16 +000013632 }
Denys Vlasenkob28d4c32017-07-25 16:29:36 +020013633 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +000013634}
13635
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000013636static const unsigned char timescmd_str[] ALIGN1 = {
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013637 ' ', offsetof(struct tms, tms_utime),
13638 '\n', offsetof(struct tms, tms_stime),
13639 ' ', offsetof(struct tms, tms_cutime),
13640 '\n', offsetof(struct tms, tms_cstime),
13641 0
13642};
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013643static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013644timescmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013645{
Denys Vlasenko11f2e992017-08-10 16:34:03 +020013646 unsigned clk_tck;
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013647 const unsigned char *p;
13648 struct tms buf;
13649
Bartosz Golaszewski5d2e4092014-06-22 14:01:13 +020013650 clk_tck = bb_clk_tck();
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013651
Denys Vlasenko11f2e992017-08-10 16:34:03 +020013652 times(&buf);
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013653 p = timescmd_str;
13654 do {
Denys Vlasenko11f2e992017-08-10 16:34:03 +020013655 unsigned sec, frac;
13656 unsigned long t;
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013657 t = *(clock_t *)(((char *) &buf) + p[1]);
Denys Vlasenko11f2e992017-08-10 16:34:03 +020013658 sec = t / clk_tck;
13659 frac = t % clk_tck;
13660 out1fmt("%um%u.%03us%c",
13661 sec / 60, sec % 60,
13662 (frac * 1000) / clk_tck,
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013663 p[0]);
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020013664 p += 2;
13665 } while (*p);
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013666
Eric Andersencb57d552001-06-28 07:25:16 +000013667 return 0;
13668}
13669
Denys Vlasenko0b883582016-12-23 16:49:07 +010013670#if ENABLE_FEATURE_SH_MATH
Eric Andersenc470f442003-07-28 09:56:35 +000013671/*
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020013672 * The let builtin. Partially stolen from GNU Bash, the Bourne Again SHell.
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +000013673 * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
Eric Andersen90898442003-08-06 11:20:52 +000013674 *
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +000013675 * Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
Eric Andersenc470f442003-07-28 09:56:35 +000013676 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013677static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013678letcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersenc470f442003-07-28 09:56:35 +000013679{
Denis Vlasenko68404f12008-03-17 09:00:54 +000013680 arith_t i;
Eric Andersenc470f442003-07-28 09:56:35 +000013681
Denis Vlasenko68404f12008-03-17 09:00:54 +000013682 argv++;
13683 if (!*argv)
Denis Vlasenkob012b102007-02-19 22:43:01 +000013684 ash_msg_and_raise_error("expression expected");
Denis Vlasenko68404f12008-03-17 09:00:54 +000013685 do {
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +000013686 i = ash_arith(*argv);
Denis Vlasenko68404f12008-03-17 09:00:54 +000013687 } while (*++argv);
Eric Andersenc470f442003-07-28 09:56:35 +000013688
Denis Vlasenkod9e15f22006-11-27 16:49:55 +000013689 return !i;
Eric Andersenc470f442003-07-28 09:56:35 +000013690}
Eric Andersenc470f442003-07-28 09:56:35 +000013691#endif
Eric Andersen74bcd162001-07-30 21:41:37 +000013692
Eric Andersenc470f442003-07-28 09:56:35 +000013693/*
Denis Vlasenko59f351c2008-03-25 00:07:12 +000013694 * The read builtin. Options:
13695 * -r Do not interpret '\' specially
13696 * -s Turn off echo (tty only)
13697 * -n NCHARS Read NCHARS max
13698 * -p PROMPT Display PROMPT on stderr (if input is from tty)
13699 * -t SECONDS Timeout after SECONDS (tty or pipe only)
13700 * -u FD Read from given FD instead of fd 0
Johannes Schindelin3bef5d82017-08-08 16:46:39 +020013701 * -d DELIM End on DELIM char, not newline
Eric Andersenc470f442003-07-28 09:56:35 +000013702 * This uses unbuffered input, which may be avoidable in some cases.
Denis Vlasenko59f351c2008-03-25 00:07:12 +000013703 * TODO: bash also has:
13704 * -a ARRAY Read into array[0],[1],etc
Denis Vlasenko59f351c2008-03-25 00:07:12 +000013705 * -e Use line editing (tty only)
Eric Andersenc470f442003-07-28 09:56:35 +000013706 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013707static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013708readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000013709{
Denys Vlasenko73067272010-01-12 22:11:24 +010013710 char *opt_n = NULL;
13711 char *opt_p = NULL;
13712 char *opt_t = NULL;
13713 char *opt_u = NULL;
Johannes Schindelin3bef5d82017-08-08 16:46:39 +020013714 char *opt_d = NULL; /* optimized out if !BASH */
Denys Vlasenko73067272010-01-12 22:11:24 +010013715 int read_flags = 0;
13716 const char *r;
Eric Andersenc470f442003-07-28 09:56:35 +000013717 int i;
13718
Johannes Schindelin3bef5d82017-08-08 16:46:39 +020013719 while ((i = nextopt("p:u:rt:n:sd:")) != '\0') {
Denis Vlasenkobf0a2012006-12-26 10:42:51 +000013720 switch (i) {
Paul Fox02eb9342005-09-07 16:56:02 +000013721 case 'p':
Denys Vlasenko73067272010-01-12 22:11:24 +010013722 opt_p = optionarg;
Paul Fox02eb9342005-09-07 16:56:02 +000013723 break;
Paul Fox02eb9342005-09-07 16:56:02 +000013724 case 'n':
Denys Vlasenko73067272010-01-12 22:11:24 +010013725 opt_n = optionarg;
Paul Fox02eb9342005-09-07 16:56:02 +000013726 break;
13727 case 's':
Denys Vlasenko73067272010-01-12 22:11:24 +010013728 read_flags |= BUILTIN_READ_SILENT;
Paul Fox02eb9342005-09-07 16:56:02 +000013729 break;
Paul Fox02eb9342005-09-07 16:56:02 +000013730 case 't':
Denys Vlasenko73067272010-01-12 22:11:24 +010013731 opt_t = optionarg;
Paul Fox02eb9342005-09-07 16:56:02 +000013732 break;
Paul Fox02eb9342005-09-07 16:56:02 +000013733 case 'r':
Denys Vlasenko73067272010-01-12 22:11:24 +010013734 read_flags |= BUILTIN_READ_RAW;
Paul Fox02eb9342005-09-07 16:56:02 +000013735 break;
Denis Vlasenko59f351c2008-03-25 00:07:12 +000013736 case 'u':
Denys Vlasenko73067272010-01-12 22:11:24 +010013737 opt_u = optionarg;
Denis Vlasenko59f351c2008-03-25 00:07:12 +000013738 break;
Johannes Schindelin3bef5d82017-08-08 16:46:39 +020013739#if BASH_READ_D
13740 case 'd':
13741 opt_d = optionarg;
13742 break;
13743#endif
Paul Fox02eb9342005-09-07 16:56:02 +000013744 default:
13745 break;
13746 }
Eric Andersenc470f442003-07-28 09:56:35 +000013747 }
Paul Fox02eb9342005-09-07 16:56:02 +000013748
Denys Vlasenko9e71e3c2012-09-06 13:28:10 +020013749 /* "read -s" needs to save/restore termios, can't allow ^C
13750 * to jump out of it.
13751 */
Denys Vlasenkof5470412017-05-22 19:34:45 +020013752 again:
Denys Vlasenko9e71e3c2012-09-06 13:28:10 +020013753 INT_OFF;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020013754 r = shell_builtin_read(setvar0,
Denys Vlasenko73067272010-01-12 22:11:24 +010013755 argptr,
13756 bltinlookup("IFS"), /* can be NULL */
13757 read_flags,
13758 opt_n,
13759 opt_p,
13760 opt_t,
Johannes Schindelin3bef5d82017-08-08 16:46:39 +020013761 opt_u,
13762 opt_d
Denys Vlasenko73067272010-01-12 22:11:24 +010013763 );
Denys Vlasenko9e71e3c2012-09-06 13:28:10 +020013764 INT_ON;
Denis Vlasenko46aeab92009-03-31 19:18:17 +000013765
Denys Vlasenkof5470412017-05-22 19:34:45 +020013766 if ((uintptr_t)r == 1 && errno == EINTR) {
Denys Vlasenko49e6bf22017-08-04 14:28:16 +020013767 /* To get SIGCHLD: sleep 1 & read x; echo $x
13768 * Correct behavior is to not exit "read"
13769 */
Denys Vlasenkof5470412017-05-22 19:34:45 +020013770 if (pending_sig == 0)
13771 goto again;
13772 }
13773
Denys Vlasenko73067272010-01-12 22:11:24 +010013774 if ((uintptr_t)r > 1)
13775 ash_msg_and_raise_error(r);
Denis Vlasenko037576d2007-10-20 18:30:38 +000013776
Denys Vlasenko73067272010-01-12 22:11:24 +010013777 return (uintptr_t)r;
Eric Andersenc470f442003-07-28 09:56:35 +000013778}
13779
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013780static int FAST_FUNC
Denys Vlasenko6283f982015-10-07 16:56:20 +020013781umaskcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000013782{
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013783 static const char permuser[3] ALIGN1 = "ogu";
Eric Andersenc470f442003-07-28 09:56:35 +000013784
Eric Andersenc470f442003-07-28 09:56:35 +000013785 mode_t mask;
Eric Andersenc470f442003-07-28 09:56:35 +000013786 int symbolic_mode = 0;
13787
13788 while (nextopt("S") != '\0') {
13789 symbolic_mode = 1;
13790 }
13791
Denis Vlasenkob012b102007-02-19 22:43:01 +000013792 INT_OFF;
Eric Andersenc470f442003-07-28 09:56:35 +000013793 mask = umask(0);
13794 umask(mask);
Denis Vlasenkob012b102007-02-19 22:43:01 +000013795 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +000013796
Denys Vlasenko6283f982015-10-07 16:56:20 +020013797 if (*argptr == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +000013798 if (symbolic_mode) {
Denys Vlasenko005c4922015-10-10 20:17:12 +020013799 char buf[sizeof(",u=rwx,g=rwx,o=rwx")];
Eric Andersenc470f442003-07-28 09:56:35 +000013800 char *p = buf;
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013801 int i;
Eric Andersenc470f442003-07-28 09:56:35 +000013802
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013803 i = 2;
13804 for (;;) {
Denys Vlasenko005c4922015-10-10 20:17:12 +020013805 *p++ = ',';
Eric Andersenc470f442003-07-28 09:56:35 +000013806 *p++ = permuser[i];
13807 *p++ = '=';
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013808 /* mask is 0..0uuugggooo. i=2 selects uuu bits */
Denys Vlasenko005c4922015-10-10 20:17:12 +020013809 if (!(mask & 0400)) *p++ = 'r';
13810 if (!(mask & 0200)) *p++ = 'w';
13811 if (!(mask & 0100)) *p++ = 'x';
13812 mask <<= 3;
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013813 if (--i < 0)
13814 break;
Eric Andersenc470f442003-07-28 09:56:35 +000013815 }
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013816 *p = '\0';
Denys Vlasenko005c4922015-10-10 20:17:12 +020013817 puts(buf + 1);
Eric Andersenc470f442003-07-28 09:56:35 +000013818 } else {
Denys Vlasenkoec046f72015-10-07 17:57:53 +020013819 out1fmt("%04o\n", mask);
Eric Andersenc470f442003-07-28 09:56:35 +000013820 }
13821 } else {
Denys Vlasenko6283f982015-10-07 16:56:20 +020013822 char *modestr = *argptr;
Denys Vlasenko14c85eb2017-10-12 19:40:47 +020013823 /* numeric umasks are taken as-is */
13824 /* symbolic umasks are inverted: "umask a=rx" calls umask(222) */
Denys Vlasenko6283f982015-10-07 16:56:20 +020013825 if (!isdigit(modestr[0]))
13826 mask ^= 0777;
Denys Vlasenko5711a2a2015-10-07 17:55:33 +020013827 mask = bb_parse_mode(modestr, mask);
13828 if ((unsigned)mask > 0777) {
Denys Vlasenko6283f982015-10-07 16:56:20 +020013829 ash_msg_and_raise_error("illegal mode: %s", modestr);
Eric Andersenc470f442003-07-28 09:56:35 +000013830 }
Denys Vlasenko6283f982015-10-07 16:56:20 +020013831 if (!isdigit(modestr[0]))
13832 mask ^= 0777;
13833 umask(mask);
Eric Andersenc470f442003-07-28 09:56:35 +000013834 }
13835 return 0;
13836}
13837
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013838static int FAST_FUNC
Denys Vlasenkof3c742f2010-03-06 20:12:00 +010013839ulimitcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersenc470f442003-07-28 09:56:35 +000013840{
Denys Vlasenkof3c742f2010-03-06 20:12:00 +010013841 return shell_builtin_ulimit(argv);
Eric Andersenc470f442003-07-28 09:56:35 +000013842}
13843
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013844/* ============ main() and helpers */
13845
13846/*
13847 * Called to exit the shell.
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013848 */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013849static void
13850exitshell(void)
13851{
13852 struct jmploc loc;
13853 char *p;
13854 int status;
13855
Denys Vlasenkobede2152011-09-04 16:12:33 +020013856#if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT
13857 save_history(line_input_state);
13858#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013859 status = exitstatus;
13860 TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
13861 if (setjmp(loc.loc)) {
Denis Vlasenko7f88e342009-03-19 03:36:18 +000013862 if (exception_type == EXEXIT)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013863 status = exitstatus;
13864 goto out;
13865 }
13866 exception_handler = &loc;
13867 p = trap[0];
13868 if (p) {
13869 trap[0] = NULL;
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020013870 evalskip = 0;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013871 evalstring(p, 0);
Denys Vlasenkof37e1152016-10-07 03:17:28 +020013872 /*free(p); - we'll exit soon */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013873 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013874 out:
Denys Vlasenkof37e1152016-10-07 03:17:28 +020013875 /* dash wraps setjobctl(0) in "if (setjmp(loc.loc) == 0) {...}".
13876 * our setjobctl(0) does not panic if tcsetpgrp fails inside it.
13877 */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013878 setjobctl(0);
Denys Vlasenkocaee80c2016-10-25 20:49:53 +020013879 flush_stdout_stderr();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013880 _exit(status);
13881 /* NOTREACHED */
13882}
13883
Denys Vlasenko49e6bf22017-08-04 14:28:16 +020013884/* Don't inline: conserve stack of caller from having our locals too */
13885static NOINLINE void
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +000013886init(void)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013887{
Denys Vlasenko82dd14a2010-05-17 10:10:01 +020013888 /* we will never free this */
13889 basepf.next_to_pgetc = basepf.buf = ckmalloc(IBUFSIZ);
Denys Vlasenko0485b672017-08-14 19:46:56 +020013890 basepf.linno = 1;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013891
Denys Vlasenko49e6bf22017-08-04 14:28:16 +020013892 sigmode[SIGCHLD - 1] = S_DFL; /* ensure we install handler even if it is SIG_IGNed */
Denys Vlasenko458c1f22016-10-27 23:51:19 +020013893 setsignal(SIGCHLD);
13894
Denys Vlasenko7a7b0342009-12-04 04:18:31 +010013895 /* bash re-enables SIGHUP which is SIG_IGNed on entry.
13896 * Try: "trap '' HUP; bash; echo RET" and type "kill -HUP $$"
13897 */
Denys Vlasenkocacb2cd2010-10-05 00:13:02 +020013898 signal(SIGHUP, SIG_DFL);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013899
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013900 {
13901 char **envp;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013902 const char *p;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013903
13904 initvar();
13905 for (envp = environ; envp && *envp; envp++) {
Denys Vlasenko9c143ce2017-11-02 12:56:24 +010013906/* Used to have
13907 * p = endofname(*envp);
13908 * if (p != *envp && *p == '=') {
13909 * here to weed out badly-named variables, but this breaks
13910 * scenarios where people do want them passed to children:
13911 * import os
13912 * os.environ["test-test"]="test"
13913 * if os.fork() == 0:
13914 * os.execv("ash", [ 'ash', '-c', 'eval $(export -p); echo OK' ]) # fixes this
13915 * os.execv("ash", [ 'ash', '-c', 'env | grep test-test' ]) # breaks this
13916 */
13917 if (strchr(*envp, '=')) {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013918 setvareq(*envp, VEXPORT|VTEXTFIXED);
13919 }
13920 }
13921
Denys Vlasenkoe627ac92016-09-30 14:36:59 +020013922 setvareq((char*)defoptindvar, VTEXTFIXED);
13923
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020013924 setvar0("PPID", utoa(getppid()));
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010013925#if BASH_SHLVL_VAR
Bernhard Reutner-Fischer80f8cdf2013-11-08 14:25:24 +010013926 p = lookupvar("SHLVL");
Denys Vlasenko5680e982014-01-07 16:12:48 +010013927 setvar("SHLVL", utoa((p ? atoi(p) : 0) + 1), VEXPORT);
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010013928#endif
13929#if BASH_HOSTNAME_VAR
Denys Vlasenko3fa97af2014-04-15 11:43:29 +020013930 if (!lookupvar("HOSTNAME")) {
13931 struct utsname uts;
13932 uname(&uts);
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020013933 setvar0("HOSTNAME", uts.nodename);
Denys Vlasenko3fa97af2014-04-15 11:43:29 +020013934 }
Bernhard Reutner-Fischer80f8cdf2013-11-08 14:25:24 +010013935#endif
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013936 p = lookupvar("PWD");
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013937 if (p) {
Denys Vlasenko49e6bf22017-08-04 14:28:16 +020013938 struct stat st1, st2;
Denys Vlasenkoef159702016-09-01 11:16:22 +020013939 if (p[0] != '/' || stat(p, &st1) || stat(".", &st2)
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013940 || st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino
13941 ) {
Denys Vlasenkoef159702016-09-01 11:16:22 +020013942 p = NULL;
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013943 }
13944 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013945 setpwd(p, 0);
13946 }
13947}
13948
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013949
13950//usage:#define ash_trivial_usage
Denys Vlasenko6b6af532011-03-08 10:24:17 +010013951//usage: "[-/+OPTIONS] [-/+o OPT]... [-c 'SCRIPT' [ARG0 [ARGS]] / FILE [ARGS]]"
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013952//usage:#define ash_full_usage "\n\n"
13953//usage: "Unix shell interpreter"
13954
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013955/*
13956 * Process the shell command line arguments.
13957 */
Denys Vlasenkoec05df12017-07-31 19:43:47 +020013958static int
Denis Vlasenko68404f12008-03-17 09:00:54 +000013959procargs(char **argv)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013960{
13961 int i;
13962 const char *xminusc;
13963 char **xargv;
Denys Vlasenkoec05df12017-07-31 19:43:47 +020013964 int login_sh;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013965
13966 xargv = argv;
Denys Vlasenkoec05df12017-07-31 19:43:47 +020013967 login_sh = xargv[0] && xargv[0][0] == '-';
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013968 arg0 = xargv[0];
Denis Vlasenko68404f12008-03-17 09:00:54 +000013969 /* if (xargv[0]) - mmm, this is always true! */
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013970 xargv++;
13971 for (i = 0; i < NOPTS; i++)
13972 optlist[i] = 2;
13973 argptr = xargv;
Denys Vlasenkoec05df12017-07-31 19:43:47 +020013974 if (options(/*cmdline:*/ 1, &login_sh)) {
Denis Vlasenko28bf6712008-02-14 15:01:47 +000013975 /* it already printed err message */
13976 raise_exception(EXERROR);
13977 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013978 xargv = argptr;
13979 xminusc = minusc;
13980 if (*xargv == NULL) {
13981 if (xminusc)
13982 ash_msg_and_raise_error(bb_msg_requires_arg, "-c");
13983 sflag = 1;
13984 }
13985 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
13986 iflag = 1;
13987 if (mflag == 2)
13988 mflag = iflag;
13989 for (i = 0; i < NOPTS; i++)
13990 if (optlist[i] == 2)
13991 optlist[i] = 0;
13992#if DEBUG == 2
13993 debug = 1;
13994#endif
Denys Vlasenko5f7c82b2017-02-03 13:00:06 +010013995 /* POSIX 1003.2: first arg after "-c CMD" is $0, remainder $1... */
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013996 if (xminusc) {
13997 minusc = *xargv++;
13998 if (*xargv)
13999 goto setarg0;
14000 } else if (!sflag) {
14001 setinputfile(*xargv, 0);
14002 setarg0:
14003 arg0 = *xargv++;
14004 commandname = arg0;
14005 }
14006
14007 shellparam.p = xargv;
14008#if ENABLE_ASH_GETOPTS
14009 shellparam.optind = 1;
14010 shellparam.optoff = -1;
14011#endif
Denis Vlasenko01631112007-12-16 17:20:38 +000014012 /* assert(shellparam.malloced == 0 && shellparam.nparam == 0); */
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014013 while (*xargv) {
14014 shellparam.nparam++;
14015 xargv++;
14016 }
14017 optschanged();
Denys Vlasenkoec05df12017-07-31 19:43:47 +020014018
14019 return login_sh;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014020}
14021
14022/*
Denys Vlasenko2eb0a7e2016-10-27 11:28:59 +020014023 * Read /etc/profile, ~/.profile, $ENV.
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014024 */
14025static void
14026read_profile(const char *name)
14027{
Denys Vlasenko46999802017-07-29 21:12:29 +020014028 name = expandstr(name, DQSYNTAX);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014029 if (setinputfile(name, INPUT_PUSH_FILE | INPUT_NOFILE_OK) < 0)
14030 return;
Denys Vlasenko0840c912016-10-01 15:27:44 +020014031 cmdloop(0);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014032 popfile();
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014033}
14034
Denis Vlasenko0c032a42007-02-23 01:03:40 +000014035/*
14036 * This routine is called when an error or an interrupt occurs in an
14037 * interactive shell and control is returned to the main command loop.
Denys Vlasenko5ac04f22016-10-27 14:46:50 +020014038 * (In dash, this function is auto-generated by build machinery).
Denis Vlasenko0c032a42007-02-23 01:03:40 +000014039 */
14040static void
14041reset(void)
14042{
14043 /* from eval.c: */
14044 evalskip = 0;
14045 loopnest = 0;
Denys Vlasenko5ac04f22016-10-27 14:46:50 +020014046
14047 /* from expand.c: */
14048 ifsfree();
14049
Denis Vlasenko0c032a42007-02-23 01:03:40 +000014050 /* from input.c: */
Denis Vlasenko41eb3002008-11-28 03:42:31 +000014051 g_parsefile->left_in_buffer = 0;
14052 g_parsefile->left_in_line = 0; /* clear input buffer */
Denis Vlasenko0c032a42007-02-23 01:03:40 +000014053 popallfiles();
Denys Vlasenko5ac04f22016-10-27 14:46:50 +020014054
Denis Vlasenko0c032a42007-02-23 01:03:40 +000014055 /* from redir.c: */
Denys Vlasenko1c79aeb2017-07-29 22:51:52 +020014056 unwindredir(NULL);
Denys Vlasenkob8ab27b2017-07-26 19:22:34 +020014057
14058 /* from var.c: */
Denys Vlasenko484fc202017-07-26 19:55:31 +020014059 unwindlocalvars(NULL);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000014060}
14061
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014062#if PROFILE
14063static short profile_buf[16384];
14064extern int etext();
14065#endif
14066
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000014067/*
14068 * Main routine. We initialize things, parse the arguments, execute
14069 * profiles if we're a login shell, and then call cmdloop to execute
14070 * commands. The setjmp call sets up the location to jump to when an
14071 * exception occurs. When an exception occurs the variable "state"
14072 * is used to figure out how far we had gotten.
14073 */
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +000014074int ash_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000014075int ash_main(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014076{
Denis Vlasenko4e12b1a2008-12-23 23:36:47 +000014077 volatile smallint state;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014078 struct jmploc jmploc;
14079 struct stackmark smark;
Denys Vlasenkoec05df12017-07-31 19:43:47 +020014080 int login_sh;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014081
Denis Vlasenko01631112007-12-16 17:20:38 +000014082 /* Initialize global data */
14083 INIT_G_misc();
14084 INIT_G_memstack();
14085 INIT_G_var();
Denis Vlasenkoee87ebf2007-12-21 22:18:16 +000014086#if ENABLE_ASH_ALIAS
Denis Vlasenko01631112007-12-16 17:20:38 +000014087 INIT_G_alias();
Denis Vlasenkoee87ebf2007-12-21 22:18:16 +000014088#endif
Denis Vlasenko01631112007-12-16 17:20:38 +000014089 INIT_G_cmdtable();
14090
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014091#if PROFILE
14092 monitor(4, etext, profile_buf, sizeof(profile_buf), 50);
14093#endif
14094
14095#if ENABLE_FEATURE_EDITING
14096 line_input_state = new_line_input_t(FOR_SHELL | WITH_PATH_LOOKUP);
14097#endif
14098 state = 0;
14099 if (setjmp(jmploc.loc)) {
Denis Vlasenko7f88e342009-03-19 03:36:18 +000014100 smallint e;
Denis Vlasenko4e12b1a2008-12-23 23:36:47 +000014101 smallint s;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014102
14103 reset();
14104
Denis Vlasenko7f88e342009-03-19 03:36:18 +000014105 e = exception_type;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014106 s = state;
Denys Vlasenkob563f622010-09-25 17:15:13 +020014107 if (e == EXEXIT || s == 0 || iflag == 0 || shlvl) {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014108 exitshell();
Denys Vlasenkob563f622010-09-25 17:15:13 +020014109 }
14110 if (e == EXINT) {
Denys Vlasenko9c541002015-10-07 15:44:36 +020014111 newline_and_flush(stderr);
Denys Vlasenkob563f622010-09-25 17:15:13 +020014112 }
Denis Vlasenko7f88e342009-03-19 03:36:18 +000014113
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014114 popstackmark(&smark);
14115 FORCE_INT_ON; /* enable interrupts */
14116 if (s == 1)
14117 goto state1;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000014118 if (s == 2)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014119 goto state2;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000014120 if (s == 3)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014121 goto state3;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000014122 goto state4;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014123 }
14124 exception_handler = &jmploc;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014125 rootpid = getpid();
14126
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014127 init();
14128 setstackmark(&smark);
Denys Vlasenkoec05df12017-07-31 19:43:47 +020014129 login_sh = procargs(argv);
Denys Vlasenko474ed062016-10-30 18:30:29 +010014130#if DEBUG
14131 TRACE(("Shell args: "));
14132 trace_puts_args(argv);
14133#endif
Denis Vlasenko68404f12008-03-17 09:00:54 +000014134
Denys Vlasenkoec05df12017-07-31 19:43:47 +020014135 if (login_sh) {
Stefan Hellermann4ef14392013-03-15 02:45:50 +010014136 const char *hp;
14137
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014138 state = 1;
14139 read_profile("/etc/profile");
14140 state1:
14141 state = 2;
Stefan Hellermann4ef14392013-03-15 02:45:50 +010014142 hp = lookupvar("HOME");
Denys Vlasenko2eb0a7e2016-10-27 11:28:59 +020014143 if (hp)
14144 read_profile("$HOME/.profile");
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014145 }
14146 state2:
14147 state = 3;
14148 if (
14149#ifndef linux
Denis Vlasenko0c032a42007-02-23 01:03:40 +000014150 getuid() == geteuid() && getgid() == getegid() &&
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014151#endif
Denis Vlasenko0c032a42007-02-23 01:03:40 +000014152 iflag
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014153 ) {
Denys Vlasenko2eb0a7e2016-10-27 11:28:59 +020014154 const char *shinit = lookupvar("ENV");
14155 if (shinit != NULL && *shinit != '\0')
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014156 read_profile(shinit);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014157 }
Denys Vlasenko2eb0a7e2016-10-27 11:28:59 +020014158 popstackmark(&smark);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014159 state3:
14160 state = 4;
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000014161 if (minusc) {
14162 /* evalstring pushes parsefile stack.
14163 * Ensure we don't falsely claim that 0 (stdin)
Denis Vlasenko5368ad52009-03-20 10:20:08 +000014164 * is one of stacked source fds.
14165 * Testcase: ash -c 'exec 1>&0' must not complain. */
Denys Vlasenko79b3d422010-06-03 04:29:08 +020014166 // if (!sflag) g_parsefile->pf_fd = -1;
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +020014167 // ^^ not necessary since now we special-case fd 0
Denys Vlasenko035486c2017-07-31 04:09:19 +020014168 // in save_fd_on_redirect()
Denys Vlasenko1e3e2cc2017-07-25 20:31:14 +020014169 evalstring(minusc, sflag ? 0 : EV_EXIT);
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000014170 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014171
14172 if (sflag || minusc == NULL) {
Denys Vlasenko4840ae82011-09-04 15:28:03 +020014173#if MAX_HISTORY > 0 && ENABLE_FEATURE_EDITING_SAVEHISTORY
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +000014174 if (iflag) {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014175 const char *hp = lookupvar("HISTFILE");
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010014176 if (!hp) {
14177 hp = lookupvar("HOME");
Stefan Hellermann4ef14392013-03-15 02:45:50 +010014178 if (hp) {
Denys Vlasenko5f7c82b2017-02-03 13:00:06 +010014179 INT_OFF;
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010014180 hp = concat_path_file(hp, ".ash_history");
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020014181 setvar0("HISTFILE", hp);
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010014182 free((char*)hp);
Denys Vlasenko5f7c82b2017-02-03 13:00:06 +010014183 INT_ON;
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010014184 hp = lookupvar("HISTFILE");
14185 }
14186 }
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000014187 if (hp)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014188 line_input_state->hist_file = hp;
Denys Vlasenko2c4de5b2011-03-31 13:16:52 +020014189# if ENABLE_FEATURE_SH_HISTFILESIZE
14190 hp = lookupvar("HISTFILESIZE");
14191 line_input_state->max_history = size_from_HISTFILESIZE(hp);
14192# endif
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014193 }
14194#endif
14195 state4: /* XXX ??? - why isn't this before the "if" statement */
14196 cmdloop(1);
14197 }
14198#if PROFILE
14199 monitor(0);
14200#endif
14201#ifdef GPROF
14202 {
14203 extern void _mcleanup(void);
14204 _mcleanup();
14205 }
14206#endif
Denys Vlasenkob563f622010-09-25 17:15:13 +020014207 TRACE(("End of main reached\n"));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014208 exitshell();
14209 /* NOTREACHED */
14210}
14211
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014212
Eric Andersendf82f612001-06-28 07:46:40 +000014213/*-
14214 * Copyright (c) 1989, 1991, 1993, 1994
Eric Andersen2870d962001-07-02 17:27:21 +000014215 * The Regents of the University of California. All rights reserved.
Eric Andersendf82f612001-06-28 07:46:40 +000014216 *
14217 * This code is derived from software contributed to Berkeley by
14218 * Kenneth Almquist.
14219 *
14220 * Redistribution and use in source and binary forms, with or without
14221 * modification, are permitted provided that the following conditions
14222 * are met:
14223 * 1. Redistributions of source code must retain the above copyright
14224 * notice, this list of conditions and the following disclaimer.
14225 * 2. Redistributions in binary form must reproduce the above copyright
14226 * notice, this list of conditions and the following disclaimer in the
14227 * documentation and/or other materials provided with the distribution.
"Vladimir N. Oleynik"ddc280e2005-12-15 12:01:49 +000014228 * 3. Neither the name of the University nor the names of its contributors
Eric Andersendf82f612001-06-28 07:46:40 +000014229 * may be used to endorse or promote products derived from this software
14230 * without specific prior written permission.
14231 *
Denys Vlasenko95f79532017-08-02 14:26:33 +020014232 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND
Eric Andersendf82f612001-06-28 07:46:40 +000014233 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
14234 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
14235 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
14236 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
14237 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
14238 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
14239 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
14240 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
14241 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
14242 * SUCH DAMAGE.
14243 */