blob: a7767b4f84424640701c44149f40fcf718005d9f [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;
5394 if (fstat(f, &sb) < 0 && S_ISREG(sb.st_mode)) {
5395 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 */
Ron Yorston549deab2015-05-18 09:57:51 +02005891#define EXP_QPAT 0x20 /* pattern in quoted parameter expansion */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005892#define EXP_VARTILDE2 0x40 /* expand tildes after colons only */
5893#define EXP_WORD 0x80 /* expand word in parameter expansion */
Ron Yorston3df47f92015-05-18 09:53:26 +02005894#define EXP_QUOTED 0x100 /* expand word in double quotes */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005895/*
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005896 * rmescape() flags
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005897 */
5898#define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
5899#define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005900#define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */
5901#define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */
5902
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005903/* Add CTLESC when necessary. */
Denys Vlasenko2990aa42017-07-25 17:37:57 +02005904#define QUOTES_ESC (EXP_FULL | EXP_CASE | EXP_QPAT)
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005905/* Do not skip NUL characters. */
5906#define QUOTES_KEEPNUL EXP_TILDE
5907
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005908/*
5909 * Structure specifying which parts of the string should be searched
5910 * for IFS characters.
5911 */
5912struct ifsregion {
5913 struct ifsregion *next; /* next region in list */
5914 int begoff; /* offset of start of region */
5915 int endoff; /* offset of end of region */
5916 int nulonly; /* search for nul bytes only */
5917};
5918
5919struct arglist {
5920 struct strlist *list;
5921 struct strlist **lastp;
5922};
5923
5924/* output of current string */
5925static char *expdest;
5926/* list of back quote expressions */
5927static struct nodelist *argbackq;
5928/* first struct in list of ifs regions */
5929static struct ifsregion ifsfirst;
5930/* last struct in list */
5931static struct ifsregion *ifslastp;
5932/* holds expanded arg list */
5933static struct arglist exparg;
5934
5935/*
5936 * Our own itoa().
Denys Vlasenkocf3a7962017-07-26 14:38:19 +02005937 * cvtnum() is used even if math support is off (to prepare $? values and such).
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005938 */
5939static int
5940cvtnum(arith_t num)
5941{
5942 int len;
5943
Denys Vlasenkocf3a7962017-07-26 14:38:19 +02005944 /* 32-bit and wider ints require buffer size of bytes*3 (or less) */
5945 len = sizeof(arith_t) * 3;
5946 /* If narrower: worst case, 1-byte ints: need 5 bytes: "-127<NUL>" */
5947 if (sizeof(arith_t) < 4) len += 2;
5948
5949 expdest = makestrspace(len, expdest);
5950 len = fmtstr(expdest, len, ARITH_FMT, num);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005951 STADJUST(len, expdest);
5952 return len;
5953}
5954
Denys Vlasenko455e4222016-10-27 14:45:13 +02005955/*
5956 * Break the argument string into pieces based upon IFS and add the
5957 * strings to the argument list. The regions of the string to be
5958 * searched for IFS characters have been stored by recordregion.
5959 */
5960static void
5961ifsbreakup(char *string, struct arglist *arglist)
5962{
5963 struct ifsregion *ifsp;
5964 struct strlist *sp;
5965 char *start;
5966 char *p;
5967 char *q;
5968 const char *ifs, *realifs;
5969 int ifsspc;
5970 int nulonly;
5971
5972 start = string;
5973 if (ifslastp != NULL) {
5974 ifsspc = 0;
5975 nulonly = 0;
5976 realifs = ifsset() ? ifsval() : defifs;
5977 ifsp = &ifsfirst;
5978 do {
5979 p = string + ifsp->begoff;
5980 nulonly = ifsp->nulonly;
5981 ifs = nulonly ? nullstr : realifs;
5982 ifsspc = 0;
5983 while (p < string + ifsp->endoff) {
5984 q = p;
5985 if ((unsigned char)*p == CTLESC)
5986 p++;
5987 if (!strchr(ifs, *p)) {
5988 p++;
5989 continue;
5990 }
5991 if (!nulonly)
5992 ifsspc = (strchr(defifs, *p) != NULL);
5993 /* Ignore IFS whitespace at start */
5994 if (q == start && ifsspc) {
5995 p++;
5996 start = p;
5997 continue;
5998 }
5999 *q = '\0';
6000 sp = stzalloc(sizeof(*sp));
6001 sp->text = start;
6002 *arglist->lastp = sp;
6003 arglist->lastp = &sp->next;
6004 p++;
6005 if (!nulonly) {
6006 for (;;) {
6007 if (p >= string + ifsp->endoff) {
6008 break;
6009 }
6010 q = p;
6011 if ((unsigned char)*p == CTLESC)
6012 p++;
6013 if (strchr(ifs, *p) == NULL) {
6014 p = q;
6015 break;
6016 }
6017 if (strchr(defifs, *p) == NULL) {
6018 if (ifsspc) {
6019 p++;
6020 ifsspc = 0;
6021 } else {
6022 p = q;
6023 break;
6024 }
6025 } else
6026 p++;
6027 }
6028 }
6029 start = p;
6030 } /* while */
6031 ifsp = ifsp->next;
6032 } while (ifsp != NULL);
6033 if (nulonly)
6034 goto add;
6035 }
6036
6037 if (!*start)
6038 return;
6039
6040 add:
6041 sp = stzalloc(sizeof(*sp));
6042 sp->text = start;
6043 *arglist->lastp = sp;
6044 arglist->lastp = &sp->next;
6045}
6046
6047static void
6048ifsfree(void)
6049{
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02006050 struct ifsregion *p = ifsfirst.next;
6051
6052 if (!p)
6053 goto out;
Denys Vlasenko455e4222016-10-27 14:45:13 +02006054
6055 INT_OFF;
Denys Vlasenko455e4222016-10-27 14:45:13 +02006056 do {
6057 struct ifsregion *ifsp;
6058 ifsp = p->next;
6059 free(p);
6060 p = ifsp;
6061 } while (p);
Denys Vlasenko455e4222016-10-27 14:45:13 +02006062 ifsfirst.next = NULL;
6063 INT_ON;
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02006064 out:
6065 ifslastp = NULL;
Denys Vlasenko455e4222016-10-27 14:45:13 +02006066}
6067
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006068static size_t
6069esclen(const char *start, const char *p)
6070{
6071 size_t esc = 0;
6072
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006073 while (p > start && (unsigned char)*--p == CTLESC) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006074 esc++;
6075 }
6076 return esc;
6077}
6078
6079/*
6080 * Remove any CTLESC characters from a string.
6081 */
Denys Vlasenko740058b2018-01-09 17:01:00 +01006082#if !BASH_PATTERN_SUBST
6083#define rmescapes(str, flag, slash_position) \
6084 rmescapes(str, flag)
6085#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006086static char *
Denys Vlasenko740058b2018-01-09 17:01:00 +01006087rmescapes(char *str, int flag, int *slash_position)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006088{
Ron Yorston417622c2015-05-18 09:59:14 +02006089 static const char qchars[] ALIGN1 = {
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006090 IF_BASH_PATTERN_SUBST('/',) CTLESC, CTLQUOTEMARK, '\0' };
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00006091
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006092 char *p, *q, *r;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006093 unsigned inquotes;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006094 unsigned protect_against_glob;
6095 unsigned globbing;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006096
Denys Vlasenko740058b2018-01-09 17:01:00 +01006097 p = strpbrk(str, qchars IF_BASH_PATTERN_SUBST(+ !slash_position));
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006098 if (!p)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006099 return str;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006100
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006101 q = p;
6102 r = str;
6103 if (flag & RMESCAPE_ALLOC) {
6104 size_t len = p - str;
6105 size_t fulllen = len + strlen(p) + 1;
6106
6107 if (flag & RMESCAPE_GROW) {
Colin Watson3963d942010-04-26 14:21:27 +02006108 int strloc = str - (char *)stackblock();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006109 r = makestrspace(fulllen, expdest);
Colin Watson3963d942010-04-26 14:21:27 +02006110 /* p and str may be invalidated by makestrspace */
6111 str = (char *)stackblock() + strloc;
6112 p = str + len;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006113 } else if (flag & RMESCAPE_HEAP) {
6114 r = ckmalloc(fulllen);
6115 } else {
6116 r = stalloc(fulllen);
6117 }
6118 q = r;
6119 if (len > 0) {
Denys Vlasenko5ace96a2017-07-23 21:46:02 +02006120 q = (char *)mempcpy(q, str, len);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006121 }
6122 }
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006123
Ron Yorston549deab2015-05-18 09:57:51 +02006124 inquotes = 0;
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 Vlasenkob0d63382009-09-16 16:18:32 +02006129// Note: both inquotes and 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 inquotes = ~inquotes;
6132 p++;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006133 protect_against_glob = globbing;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006134 continue;
6135 }
Ron Yorston549deab2015-05-18 09:57:51 +02006136 if ((unsigned char)*p == CTLESC) {
6137 p++;
Denys Vlasenko13f20912016-09-25 20:54:25 +02006138#if DEBUG
6139 if (*p == '\0')
6140 ash_msg_and_raise_error("CTLESC at EOL (shouldn't happen)");
6141#endif
Ron Yorston549deab2015-05-18 09:57:51 +02006142 if (protect_against_glob) {
Denys Vlasenkofda9faf2017-07-05 19:10:21 +02006143 /*
6144 * We used to trust glob() and fnmatch() to eat
6145 * superfluous escapes (\z where z has no
6146 * special meaning anyway). But this causes
6147 * bugs such as string of one greek letter rho
Denys Vlasenkoed79a632017-07-05 19:20:43 +02006148 * (unicode-encoded as two bytes "cf,81")
Denys Vlasenkofda9faf2017-07-05 19:10:21 +02006149 * getting encoded as "cf,CTLESC,81"
6150 * and here, converted to "cf,\,81" -
6151 * which does not go well with some flavors
Denys Vlasenko92b8d9c2017-07-05 19:13:44 +02006152 * of fnmatch() in unicode locales
6153 * (for example, glibc <= 2.22).
Denys Vlasenkofda9faf2017-07-05 19:10:21 +02006154 *
6155 * Lets add "\" only on the chars which need it.
Denys Vlasenko4142f012017-07-05 22:19:28 +02006156 * Testcases for less obvious chars are shown.
Denys Vlasenkofda9faf2017-07-05 19:10:21 +02006157 */
6158 if (*p == '*'
6159 || *p == '?'
6160 || *p == '['
Denys Vlasenko8de5b9f2018-02-13 14:43:29 +01006161 || *p == '\\' /* case '\' in \\ ) echo ok;; *) echo WRONG;; esac */
6162 || *p == ']' /* case ']' in [a\]] ) echo ok;; *) echo WRONG;; esac */
6163 || *p == '-' /* case '-' in [a\-c]) echo ok;; *) echo WRONG;; esac */
6164 || *p == '!' /* case '!' in [\!] ) echo ok;; *) echo WRONG;; esac */
Denys Vlasenko4142f012017-07-05 22:19:28 +02006165 /* Some libc support [^negate], that's why "^" also needs love */
Denys Vlasenko8de5b9f2018-02-13 14:43:29 +01006166 || *p == '^' /* case '^' in [\^] ) echo ok;; *) echo WRONG;; esac */
Denys Vlasenkofda9faf2017-07-05 19:10:21 +02006167 ) {
6168 *q++ = '\\';
6169 }
Ron Yorston549deab2015-05-18 09:57:51 +02006170 }
6171 } else if (*p == '\\' && !inquotes) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006172 /* naked back slash */
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006173 protect_against_glob = 0;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006174 goto copy;
6175 }
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:
Ron Yorston549deab2015-05-18 09:57:51 +02006656 inquotes ^= EXP_QUOTED;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006657 /* "$@" syntax adherence hack */
Ron Yorston549deab2015-05-18 09:57:51 +02006658 if (inquotes && !memcmp(p, dolatstr + 1, DOLATSTRLEN - 1)) {
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02006659 p = evalvar(p + 1, flags | inquotes) + 1;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006660 goto start;
6661 }
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++;
Ron Yorston549deab2015-05-18 09:57:51 +02006672
6673 /*
6674 * Quoted parameter expansion pattern: remove quote
6675 * unless inside inner quotes or we have a literal
6676 * backslash.
6677 */
6678 if (((flags | inquotes) & (EXP_QPAT | EXP_QUOTED)) ==
6679 EXP_QPAT && *p != '\\')
6680 break;
6681
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006682 goto addquote;
6683 case CTLVAR:
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02006684 TRACE(("argstr: evalvar('%s')\n", p));
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02006685 p = evalvar(p, flags | inquotes);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02006686 TRACE(("argstr: evalvar:'%s'\n", (char *)stackblock()));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006687 goto start;
6688 case CTLBACKQ:
Ron Yorston549deab2015-05-18 09:57:51 +02006689 expbackq(argbackq->n, flags | inquotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006690 argbackq = argbackq->next;
6691 goto start;
Denys Vlasenko0b883582016-12-23 16:49:07 +01006692#if ENABLE_FEATURE_SH_MATH
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006693 case CTLENDARI:
6694 p--;
Ron Yorston549deab2015-05-18 09:57:51 +02006695 expari(flags | inquotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006696 goto start;
6697#endif
6698 }
6699 }
Denys Vlasenko958581a2010-09-12 15:04:27 +02006700 breakloop: ;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006701}
6702
6703static char *
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006704scanleft(char *startp, char *rmesc, char *rmescend UNUSED_PARAM,
6705 char *pattern, int quotes, int zero)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006706{
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006707 char *loc, *loc2;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006708 char c;
6709
6710 loc = startp;
6711 loc2 = rmesc;
6712 do {
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006713 int match;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006714 const char *s = loc2;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006715
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006716 c = *loc2;
6717 if (zero) {
6718 *loc2 = '\0';
6719 s = rmesc;
6720 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006721 match = pmatch(pattern, s);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006722
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006723 *loc2 = c;
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006724 if (match)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006725 return loc;
Denys Vlasenkocd716832009-11-28 22:14:02 +01006726 if (quotes && (unsigned char)*loc == CTLESC)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006727 loc++;
6728 loc++;
6729 loc2++;
6730 } while (c);
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006731 return NULL;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006732}
6733
6734static char *
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006735scanright(char *startp, char *rmesc, char *rmescend,
6736 char *pattern, int quotes, int match_at_start)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006737{
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006738#if !ENABLE_ASH_OPTIMIZE_FOR_SIZE
6739 int try2optimize = match_at_start;
6740#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006741 int esc = 0;
6742 char *loc;
6743 char *loc2;
6744
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006745 /* If we called by "${v/pattern/repl}" or "${v//pattern/repl}":
6746 * startp="escaped_value_of_v" rmesc="raw_value_of_v"
6747 * rmescend=""(ptr to NUL in rmesc) pattern="pattern" quotes=match_at_start=1
6748 * Logic:
6749 * loc starts at NUL at the end of startp, loc2 starts at the end of rmesc,
6750 * and on each iteration they go back two/one char until they reach the beginning.
6751 * We try to find a match in "raw_value_of_v", "raw_value_of_", "raw_value_of" etc.
6752 */
6753 /* TODO: document in what other circumstances we are called. */
6754
6755 for (loc = pattern - 1, loc2 = rmescend; loc >= startp; loc2--) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006756 int match;
6757 char c = *loc2;
6758 const char *s = loc2;
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006759 if (match_at_start) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006760 *loc2 = '\0';
6761 s = rmesc;
6762 }
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006763 match = pmatch(pattern, s);
6764 //bb_error_msg("pmatch(pattern:'%s',s:'%s'):%d", pattern, s, match);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006765 *loc2 = c;
6766 if (match)
6767 return loc;
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006768#if !ENABLE_ASH_OPTIMIZE_FOR_SIZE
6769 if (try2optimize) {
6770 /* Maybe we can optimize this:
6771 * if pattern ends with unescaped *, we can avoid checking
Denys Vlasenko10ad6222017-04-17 16:13:32 +02006772 * shorter strings: if "foo*" doesn't match "raw_value_of_v",
6773 * it won't match truncated "raw_value_of_" strings too.
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006774 */
6775 unsigned plen = strlen(pattern);
6776 /* Does it end with "*"? */
6777 if (plen != 0 && pattern[--plen] == '*') {
6778 /* "xxxx*" is not escaped */
6779 /* "xxx\*" is escaped */
6780 /* "xx\\*" is not escaped */
6781 /* "x\\\*" is escaped */
6782 int slashes = 0;
6783 while (plen != 0 && pattern[--plen] == '\\')
6784 slashes++;
6785 if (!(slashes & 1))
6786 break; /* ends with unescaped "*" */
6787 }
6788 try2optimize = 0;
6789 }
6790#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006791 loc--;
6792 if (quotes) {
6793 if (--esc < 0) {
6794 esc = esclen(startp, loc);
6795 }
6796 if (esc % 2) {
6797 esc--;
6798 loc--;
6799 }
6800 }
6801 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006802 return NULL;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006803}
6804
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00006805static void varunset(const char *, const char *, const char *, int) NORETURN;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006806static void
6807varunset(const char *end, const char *var, const char *umsg, int varflags)
6808{
6809 const char *msg;
6810 const char *tail;
6811
6812 tail = nullstr;
6813 msg = "parameter not set";
6814 if (umsg) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006815 if ((unsigned char)*end == CTLENDVAR) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006816 if (varflags & VSNUL)
6817 tail = " or null";
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006818 } else {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006819 msg = umsg;
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006820 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006821 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006822 ash_msg_and_raise_error("%.*s: %s%s", (int)(end - var - 1), var, msg, tail);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006823}
6824
6825static const char *
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006826subevalvar(char *p, char *varname, int strloc, int subtype,
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02006827 int startloc, int varflags, int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006828{
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006829 struct nodelist *saveargbackq = argbackq;
Ron Yorston549deab2015-05-18 09:57:51 +02006830 int quotes = flag & QUOTES_ESC;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006831 char *startp;
6832 char *loc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006833 char *rmesc, *rmescend;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006834 char *str;
Denys Vlasenko0b4980c2012-09-25 12:49:29 +02006835 int amount, resetloc;
Denys Vlasenko740058b2018-01-09 17:01:00 +01006836 int argstr_flags;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006837 IF_BASH_PATTERN_SUBST(int workloc;)
Denys Vlasenko740058b2018-01-09 17:01:00 +01006838 IF_BASH_PATTERN_SUBST(int slash_pos;)
6839 IF_BASH_PATTERN_SUBST(char *repl;)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006840 int zero;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006841 char *(*scan)(char*, char*, char*, char*, int, int);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006842
Denys Vlasenko6040fe82010-09-12 15:03:16 +02006843 //bb_error_msg("subevalvar(p:'%s',varname:'%s',strloc:%d,subtype:%d,startloc:%d,varflags:%x,quotes:%d)",
6844 // p, varname, strloc, subtype, startloc, varflags, quotes);
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006845
Denys Vlasenko740058b2018-01-09 17:01:00 +01006846#if BASH_PATTERN_SUBST
Denys Vlasenkod1df1a72018-01-09 17:25:58 +01006847 /* For "${v/pattern/repl}", we must find the delimiter _before_
6848 * argstr() call expands possible variable references in pattern:
6849 * think about "v=a; a=a/; echo ${v/$a/r}" case.
6850 */
Denys Vlasenko740058b2018-01-09 17:01:00 +01006851 repl = NULL;
6852 if (subtype == VSREPLACE || subtype == VSREPLACEALL) {
6853 /* Find '/' and replace with NUL */
6854 repl = p;
6855 for (;;) {
6856 /* Handle escaped slashes, e.g. "${v/\//_}" (they are CTLESC'ed by this point) */
6857 if (*repl == '\0') {
6858 repl = NULL;
6859 break;
6860 }
6861 if (*repl == '/') {
6862 *repl = '\0';
6863 break;
6864 }
Denys Vlasenkod1df1a72018-01-09 17:25:58 +01006865 if ((unsigned char)*repl == CTLESC && repl[1])
Denys Vlasenko740058b2018-01-09 17:01:00 +01006866 repl++;
Denys Vlasenko740058b2018-01-09 17:01:00 +01006867 repl++;
6868 }
6869 }
6870#endif
6871 argstr_flags = EXP_TILDE;
6872 if (subtype != VSASSIGN && subtype != VSQUESTION)
6873 argstr_flags |= (flag & (EXP_QUOTED | EXP_QPAT) ? EXP_QPAT : EXP_CASE);
6874 argstr(p, argstr_flags);
6875#if BASH_PATTERN_SUBST
6876 slash_pos = -1;
6877 if (repl) {
6878 slash_pos = expdest - ((char *)stackblock() + strloc);
6879 STPUTC('/', expdest);
6880 argstr(repl + 1, argstr_flags);
6881 *repl = '/';
6882 }
6883#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006884 STPUTC('\0', expdest);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006885 argbackq = saveargbackq;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006886 startp = (char *)stackblock() + startloc;
Denys Vlasenko740058b2018-01-09 17:01:00 +01006887 //bb_error_msg("str1:'%s'", (char *)stackblock() + strloc);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006888
6889 switch (subtype) {
6890 case VSASSIGN:
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02006891 setvar0(varname, startp);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006892 amount = startp - expdest;
6893 STADJUST(amount, expdest);
6894 return startp;
6895
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006896 case VSQUESTION:
6897 varunset(p, varname, startp, varflags);
6898 /* NOTREACHED */
6899
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006900#if BASH_SUBSTR
Denys Vlasenko826360f2017-07-17 17:49:11 +02006901 case VSSUBSTR: {
6902 int pos, len, orig_len;
6903 char *colon;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006904
Denys Vlasenko826360f2017-07-17 17:49:11 +02006905 loc = str = stackblock() + strloc;
6906
Denys Vlasenko826360f2017-07-17 17:49:11 +02006907 /* Read POS in ${var:POS:LEN} */
6908 colon = strchr(loc, ':');
6909 if (colon) *colon = '\0';
Denys Vlasenkobaa41c72018-01-10 13:22:25 +01006910 pos = substr_atoi(loc);
Denys Vlasenko826360f2017-07-17 17:49:11 +02006911 if (colon) *colon = ':';
6912
6913 /* Read LEN in ${var:POS:LEN} */
6914 len = str - startp - 1;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006915 /* *loc != '\0', guaranteed by parser */
6916 if (quotes) {
6917 char *ptr;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006918 /* Adjust the length by the number of escapes */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006919 for (ptr = startp; ptr < (str - 1); ptr++) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006920 if ((unsigned char)*ptr == CTLESC) {
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006921 len--;
6922 ptr++;
6923 }
6924 }
6925 }
6926 orig_len = len;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006927 if (*loc++ == ':') {
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006928 /* ${var::LEN} */
Denys Vlasenkobaa41c72018-01-10 13:22:25 +01006929 len = substr_atoi(loc);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006930 } else {
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006931 /* Skip POS in ${var:POS:LEN} */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006932 len = orig_len;
Denys Vlasenkobaa41c72018-01-10 13:22:25 +01006933 while (*loc && *loc != ':')
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006934 loc++;
Denys Vlasenkobaa41c72018-01-10 13:22:25 +01006935 if (*loc++ == ':')
6936 len = substr_atoi(loc);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006937 }
Denys Vlasenko08a5dab2014-11-17 20:27:18 +01006938 if (pos < 0) {
6939 /* ${VAR:$((-n)):l} starts n chars from the end */
6940 pos = orig_len + pos;
6941 }
6942 if ((unsigned)pos >= orig_len) {
6943 /* apart from obvious ${VAR:999999:l},
6944 * covers ${VAR:$((-9999999)):l} - result is ""
Denys Vlasenko826360f2017-07-17 17:49:11 +02006945 * (bash compat)
Denys Vlasenko08a5dab2014-11-17 20:27:18 +01006946 */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006947 pos = 0;
6948 len = 0;
6949 }
Denys Vlasenko826360f2017-07-17 17:49:11 +02006950 if (len < 0) {
6951 /* ${VAR:N:-M} sets LEN to strlen()-M */
6952 len = (orig_len - pos) + len;
6953 }
6954 if ((unsigned)len > (orig_len - pos))
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006955 len = orig_len - pos;
6956
6957 for (str = startp; pos; str++, pos--) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006958 if (quotes && (unsigned char)*str == CTLESC)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006959 str++;
6960 }
6961 for (loc = startp; len; len--) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006962 if (quotes && (unsigned char)*str == CTLESC)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006963 *loc++ = *str++;
6964 *loc++ = *str++;
6965 }
6966 *loc = '\0';
6967 amount = loc - expdest;
6968 STADJUST(amount, expdest);
6969 return loc;
Denys Vlasenko826360f2017-07-17 17:49:11 +02006970 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006971#endif /* BASH_SUBSTR */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006972 }
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006973
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006974 resetloc = expdest - (char *)stackblock();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006975
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006976#if BASH_PATTERN_SUBST
Denys Vlasenko740058b2018-01-09 17:01:00 +01006977 repl = NULL;
6978
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006979 /* We'll comeback here if we grow the stack while handling
6980 * a VSREPLACE or VSREPLACEALL, since our pointers into the
6981 * stack will need rebasing, and we'll need to remove our work
6982 * areas each time
6983 */
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006984 restart:
6985#endif
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006986
6987 amount = expdest - ((char *)stackblock() + resetloc);
6988 STADJUST(-amount, expdest);
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006989 startp = (char *)stackblock() + startloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006990
6991 rmesc = startp;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006992 rmescend = (char *)stackblock() + strloc;
Denys Vlasenko740058b2018-01-09 17:01:00 +01006993 //bb_error_msg("str7:'%s'", rmescend);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006994 if (quotes) {
Denys Vlasenko740058b2018-01-09 17:01:00 +01006995//TODO: how to handle slash_pos here if string changes (shortens?)
6996 rmesc = rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW, NULL);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006997 if (rmesc != startp) {
6998 rmescend = expdest;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006999 startp = (char *)stackblock() + startloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007000 }
7001 }
7002 rmescend--;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00007003 str = (char *)stackblock() + strloc;
Ron Yorston417622c2015-05-18 09:59:14 +02007004 /*
7005 * Example: v='a\bc'; echo ${v/\\b/_\\_\z_}
7006 * The result is a_\_z_c (not a\_\_z_c)!
7007 *
7008 * The search pattern and replace string treat backslashes differently!
Denys Vlasenko740058b2018-01-09 17:01:00 +01007009 * "&slash_pos" causes rmescapes() to work differently on the pattern
Ron Yorston417622c2015-05-18 09:59:14 +02007010 * and string. It's only used on the first call.
7011 */
Denys Vlasenko740058b2018-01-09 17:01:00 +01007012 //bb_error_msg("str8:'%s' slash_pos:%d", str, slash_pos);
7013 rmescapes(str, RMESCAPE_GLOB,
7014 repl ? NULL : (slash_pos < 0 ? NULL : &slash_pos)
7015 );
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007016
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01007017#if BASH_PATTERN_SUBST
Denys Vlasenko0b4980c2012-09-25 12:49:29 +02007018 workloc = expdest - (char *)stackblock();
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007019 if (subtype == VSREPLACE || subtype == VSREPLACEALL) {
Denys Vlasenko826360f2017-07-17 17:49:11 +02007020 int len;
Denys Vlasenkob76356b2010-03-13 16:19:04 +01007021 char *idx, *end;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007022
Denis Vlasenkod6855d12008-09-27 14:03:25 +00007023 if (!repl) {
Denys Vlasenko740058b2018-01-09 17:01:00 +01007024 //bb_error_msg("str9:'%s' slash_pos:%d", str, slash_pos);
Denys Vlasenkod1df1a72018-01-09 17:25:58 +01007025 repl = nullstr;
Denys Vlasenko740058b2018-01-09 17:01:00 +01007026 if (slash_pos >= 0) {
7027 repl = str + slash_pos;
Ron Yorston417622c2015-05-18 09:59:14 +02007028 *repl++ = '\0';
Denys Vlasenko740058b2018-01-09 17:01:00 +01007029 }
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007030 }
Ron Yorston417622c2015-05-18 09:59:14 +02007031 //bb_error_msg("str:'%s' repl:'%s'", str, repl);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007032
7033 /* If there's no pattern to match, return the expansion unmolested */
Denys Vlasenkob76356b2010-03-13 16:19:04 +01007034 if (str[0] == '\0')
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02007035 return NULL;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007036
7037 len = 0;
7038 idx = startp;
7039 end = str - 1;
7040 while (idx < end) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01007041 try_to_match:
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007042 loc = scanright(idx, rmesc, rmescend, str, quotes, 1);
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02007043 //bb_error_msg("scanright('%s'):'%s'", str, loc);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007044 if (!loc) {
7045 /* No match, advance */
Denys Vlasenkob76356b2010-03-13 16:19:04 +01007046 char *restart_detect = stackblock();
7047 skip_matching:
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007048 STPUTC(*idx, expdest);
Denys Vlasenkocd716832009-11-28 22:14:02 +01007049 if (quotes && (unsigned char)*idx == CTLESC) {
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007050 idx++;
7051 len++;
7052 STPUTC(*idx, expdest);
7053 }
7054 if (stackblock() != restart_detect)
7055 goto restart;
7056 idx++;
7057 len++;
7058 rmesc++;
Denys Vlasenkob76356b2010-03-13 16:19:04 +01007059 /* continue; - prone to quadratic behavior, smarter code: */
7060 if (idx >= end)
7061 break;
7062 if (str[0] == '*') {
7063 /* Pattern is "*foo". If "*foo" does not match "long_string",
7064 * it would never match "ong_string" etc, no point in trying.
7065 */
7066 goto skip_matching;
7067 }
7068 goto try_to_match;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007069 }
7070
7071 if (subtype == VSREPLACEALL) {
7072 while (idx < loc) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01007073 if (quotes && (unsigned char)*idx == CTLESC)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007074 idx++;
7075 idx++;
7076 rmesc++;
7077 }
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00007078 } else {
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007079 idx = loc;
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00007080 }
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007081
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02007082 //bb_error_msg("repl:'%s'", repl);
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007083 for (loc = (char*)repl; *loc; loc++) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01007084 char *restart_detect = stackblock();
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007085 if (quotes && *loc == '\\') {
7086 STPUTC(CTLESC, expdest);
7087 len++;
7088 }
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007089 STPUTC(*loc, expdest);
7090 if (stackblock() != restart_detect)
7091 goto restart;
7092 len++;
7093 }
7094
7095 if (subtype == VSREPLACE) {
Denys Vlasenkof02c82f2010-08-06 19:14:47 +02007096 //bb_error_msg("tail:'%s', quotes:%x", idx, quotes);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007097 while (*idx) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01007098 char *restart_detect = stackblock();
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007099 STPUTC(*idx, expdest);
7100 if (stackblock() != restart_detect)
7101 goto restart;
7102 len++;
7103 idx++;
7104 }
7105 break;
7106 }
7107 }
7108
7109 /* We've put the replaced text into a buffer at workloc, now
7110 * move it to the right place and adjust the stack.
7111 */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007112 STPUTC('\0', expdest);
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007113 startp = (char *)stackblock() + startloc;
7114 memmove(startp, (char *)stackblock() + workloc, len + 1);
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02007115 //bb_error_msg("startp:'%s'", startp);
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007116 amount = expdest - (startp + len);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007117 STADJUST(-amount, expdest);
7118 return startp;
7119 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01007120#endif /* BASH_PATTERN_SUBST */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007121
7122 subtype -= VSTRIMRIGHT;
7123#if DEBUG
7124 if (subtype < 0 || subtype > 7)
7125 abort();
7126#endif
Denys Vlasenkob76356b2010-03-13 16:19:04 +01007127 /* zero = (subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX) */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007128 zero = subtype >> 1;
7129 /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */
7130 scan = (subtype & 1) ^ zero ? scanleft : scanright;
7131
7132 loc = scan(startp, rmesc, rmescend, str, quotes, zero);
7133 if (loc) {
7134 if (zero) {
7135 memmove(startp, loc, str - loc);
7136 loc = startp + (str - loc) - 1;
7137 }
7138 *loc = '\0';
7139 amount = loc - expdest;
7140 STADJUST(amount, expdest);
7141 }
7142 return loc;
7143}
7144
7145/*
7146 * Add the value of a specialized variable to the stack string.
Denys Vlasenko4d8873f2009-10-04 03:14:41 +02007147 * name parameter (examples):
7148 * ash -c 'echo $1' name:'1='
7149 * ash -c 'echo $qwe' name:'qwe='
7150 * ash -c 'echo $$' name:'$='
7151 * ash -c 'echo ${$}' name:'$='
7152 * ash -c 'echo ${$##q}' name:'$=q'
7153 * ash -c 'echo ${#$}' name:'$='
7154 * note: examples with bad shell syntax:
7155 * ash -c 'echo ${#$1}' name:'$=1'
7156 * ash -c 'echo ${#1#}' name:'1=#'
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007157 */
Denys Vlasenkoadf922e2009-10-08 14:35:37 +02007158static NOINLINE ssize_t
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02007159varvalue(char *name, int varflags, int flags, int *quotedp)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007160{
Mike Frysinger98c52642009-04-02 10:02:37 +00007161 const char *p;
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01007162 int num;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007163 int i;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007164 ssize_t len = 0;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007165 int sep;
Denys Vlasenko0dd8e452016-10-01 21:02:06 +02007166 int quoted = *quotedp;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007167 int subtype = varflags & VSTYPE;
7168 int discard = subtype == VSPLUS || subtype == VSLENGTH;
7169 int quotes = (discard ? 0 : (flags & QUOTES_ESC)) | QUOTES_KEEPNUL;
Denys Vlasenko0aaaa502016-10-02 02:46:56 +02007170 int syntax;
7171
7172 sep = (flags & EXP_FULL) << CHAR_BIT;
7173 syntax = quoted ? DQSYNTAX : BASESYNTAX;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007174
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007175 switch (*name) {
7176 case '$':
7177 num = rootpid;
7178 goto numvar;
7179 case '?':
7180 num = exitstatus;
7181 goto numvar;
7182 case '#':
7183 num = shellparam.nparam;
7184 goto numvar;
7185 case '!':
7186 num = backgndpid;
7187 if (num == 0)
7188 return -1;
7189 numvar:
7190 len = cvtnum(num);
Denys Vlasenko4d8873f2009-10-04 03:14:41 +02007191 goto check_1char_name;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007192 case '-':
Mike Frysinger98c52642009-04-02 10:02:37 +00007193 expdest = makestrspace(NOPTS, expdest);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007194 for (i = NOPTS - 1; i >= 0; i--) {
Martijn Dekkerad4e9612018-03-31 18:15:59 +02007195 if (optlist[i] && optletters(i)) {
Mike Frysinger98c52642009-04-02 10:02:37 +00007196 USTPUTC(optletters(i), expdest);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007197 len++;
7198 }
7199 }
Denys Vlasenko4d8873f2009-10-04 03:14:41 +02007200 check_1char_name:
7201#if 0
7202 /* handles cases similar to ${#$1} */
7203 if (name[2] != '\0')
7204 raise_error_syntax("bad substitution");
7205#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007206 break;
Denys Vlasenko0aaaa502016-10-02 02:46:56 +02007207 case '@':
7208 if (quoted && sep)
7209 goto param;
7210 /* fall through */
7211 case '*': {
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01007212 char **ap;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007213 char sepc;
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01007214
Denys Vlasenko0aaaa502016-10-02 02:46:56 +02007215 if (quoted)
7216 sep = 0;
7217 sep |= ifsset() ? ifsval()[0] : ' ';
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007218 param:
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007219 sepc = sep;
Denys Vlasenko0dd8e452016-10-01 21:02:06 +02007220 *quotedp = !sepc;
7221 ap = shellparam.p;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007222 if (!ap)
7223 return -1;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02007224 while ((p = *ap++) != NULL) {
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007225 len += strtodest(p, syntax, quotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007226
7227 if (*ap && sep) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007228 len++;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007229 memtodest(&sepc, 1, syntax, quotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007230 }
7231 }
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007232 break;
Denys Vlasenko0aaaa502016-10-02 02:46:56 +02007233 } /* case '*' */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007234 case '0':
7235 case '1':
7236 case '2':
7237 case '3':
7238 case '4':
7239 case '5':
7240 case '6':
7241 case '7':
7242 case '8':
7243 case '9':
Denys Vlasenkoa00329c2009-08-30 20:05:10 +02007244 num = atoi(name); /* number(name) fails on ${N#str} etc */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007245 if (num < 0 || num > shellparam.nparam)
7246 return -1;
7247 p = num ? shellparam.p[num - 1] : arg0;
7248 goto value;
7249 default:
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00007250 /* NB: name has form "VAR=..." */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007251 p = lookupvar(name);
7252 value:
7253 if (!p)
7254 return -1;
7255
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007256 len = strtodest(p, syntax, quotes);
Denys Vlasenkoc76236f2014-12-29 00:04:18 +01007257#if ENABLE_UNICODE_SUPPORT
7258 if (subtype == VSLENGTH && len > 0) {
7259 reinit_unicode_for_ash();
7260 if (unicode_status == UNICODE_ON) {
Ron Yorston3e3bfb82016-03-18 11:29:19 +00007261 STADJUST(-len, expdest);
7262 discard = 0;
Denys Vlasenkoc76236f2014-12-29 00:04:18 +01007263 len = unicode_strlen(p);
7264 }
7265 }
7266#endif
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007267 break;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007268 }
7269
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007270 if (discard)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007271 STADJUST(-len, expdest);
7272 return len;
7273}
7274
7275/*
7276 * Expand a variable, and return a pointer to the next character in the
7277 * input string.
7278 */
7279static char *
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02007280evalvar(char *p, int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007281{
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00007282 char varflags;
7283 char subtype;
Ron Yorston549deab2015-05-18 09:57:51 +02007284 int quoted;
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00007285 char easy;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007286 char *var;
7287 int patloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007288 int startloc;
7289 ssize_t varlen;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007290
Denys Vlasenkob0d63382009-09-16 16:18:32 +02007291 varflags = (unsigned char) *p++;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007292 subtype = varflags & VSTYPE;
Denys Vlasenko88e15702016-10-26 01:55:56 +02007293
7294 if (!subtype)
7295 raise_error_syntax("bad substitution");
7296
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007297 quoted = flag & EXP_QUOTED;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007298 var = p;
7299 easy = (!quoted || (*var == '@' && shellparam.nparam));
7300 startloc = expdest - (char *)stackblock();
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02007301 p = strchr(p, '=') + 1; //TODO: use var_end(p)?
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007302
7303 again:
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02007304 varlen = varvalue(var, varflags, flag, &quoted);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007305 if (varflags & VSNUL)
7306 varlen--;
7307
7308 if (subtype == VSPLUS) {
7309 varlen = -1 - varlen;
7310 goto vsplus;
7311 }
7312
7313 if (subtype == VSMINUS) {
7314 vsplus:
7315 if (varlen < 0) {
7316 argstr(
Denys Vlasenko6040fe82010-09-12 15:03:16 +02007317 p,
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02007318 flag | EXP_TILDE | EXP_WORD
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007319 );
7320 goto end;
7321 }
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007322 goto record;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007323 }
7324
7325 if (subtype == VSASSIGN || subtype == VSQUESTION) {
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007326 if (varlen >= 0)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007327 goto record;
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007328
7329 subevalvar(p, var, 0, subtype, startloc, varflags,
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02007330 flag & ~QUOTES_ESC);
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007331 varflags &= ~VSNUL;
7332 /*
7333 * Remove any recorded regions beyond
7334 * start of variable
7335 */
7336 removerecordregions(startloc);
7337 goto again;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007338 }
7339
7340 if (varlen < 0 && uflag)
7341 varunset(p, var, 0, 0);
7342
7343 if (subtype == VSLENGTH) {
Denys Vlasenkoc76236f2014-12-29 00:04:18 +01007344 cvtnum(varlen > 0 ? varlen : 0);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007345 goto record;
7346 }
7347
7348 if (subtype == VSNORMAL) {
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007349 record:
7350 if (!easy)
7351 goto end;
Denys Vlasenko0dd8e452016-10-01 21:02:06 +02007352 recordregion(startloc, expdest - (char *)stackblock(), quoted);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007353 goto end;
7354 }
7355
7356#if DEBUG
7357 switch (subtype) {
7358 case VSTRIMLEFT:
7359 case VSTRIMLEFTMAX:
7360 case VSTRIMRIGHT:
7361 case VSTRIMRIGHTMAX:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01007362#if BASH_SUBSTR
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007363 case VSSUBSTR:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01007364#endif
7365#if BASH_PATTERN_SUBST
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007366 case VSREPLACE:
7367 case VSREPLACEALL:
7368#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007369 break;
7370 default:
7371 abort();
7372 }
7373#endif
7374
7375 if (varlen >= 0) {
7376 /*
7377 * Terminate the string and start recording the pattern
7378 * right after it
7379 */
7380 STPUTC('\0', expdest);
7381 patloc = expdest - (char *)stackblock();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02007382 if (NULL == subevalvar(p, /* varname: */ NULL, patloc, subtype,
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02007383 startloc, varflags, flag)) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007384 int amount = expdest - (
7385 (char *)stackblock() + patloc - 1
7386 );
7387 STADJUST(-amount, expdest);
7388 }
7389 /* Remove any recorded regions beyond start of variable */
7390 removerecordregions(startloc);
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007391 goto record;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007392 }
7393
7394 end:
7395 if (subtype != VSNORMAL) { /* skip to end of alternative */
7396 int nesting = 1;
7397 for (;;) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01007398 unsigned char c = *p++;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007399 if (c == CTLESC)
7400 p++;
Ron Yorston549deab2015-05-18 09:57:51 +02007401 else if (c == CTLBACKQ) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007402 if (varlen >= 0)
7403 argbackq = argbackq->next;
7404 } else if (c == CTLVAR) {
7405 if ((*p++ & VSTYPE) != VSNORMAL)
7406 nesting++;
7407 } else if (c == CTLENDVAR) {
7408 if (--nesting == 0)
7409 break;
7410 }
7411 }
7412 }
7413 return p;
7414}
7415
7416/*
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007417 * Add a file name to the list.
7418 */
7419static void
7420addfname(const char *name)
7421{
7422 struct strlist *sp;
7423
Denis Vlasenko597906c2008-02-20 16:38:54 +00007424 sp = stzalloc(sizeof(*sp));
Denys Vlasenko8e2bc472016-09-28 23:02:57 +02007425 sp->text = sstrdup(name);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007426 *exparg.lastp = sp;
7427 exparg.lastp = &sp->next;
7428}
7429
Felix Fietkaub5b21122017-01-31 21:58:55 +01007430/* Avoid glob() (and thus, stat() et al) for words like "echo" */
7431static int
7432hasmeta(const char *p)
7433{
7434 static const char chars[] ALIGN1 = {
7435 '*', '?', '[', '\\', CTLQUOTEMARK, CTLESC, 0
7436 };
7437
7438 for (;;) {
7439 p = strpbrk(p, chars);
7440 if (!p)
7441 break;
Denys Vlasenkoac61f442018-03-30 23:03:29 +02007442 switch ((unsigned char)*p) {
Felix Fietkaub5b21122017-01-31 21:58:55 +01007443 case CTLQUOTEMARK:
7444 for (;;) {
7445 p++;
Denys Vlasenkoac61f442018-03-30 23:03:29 +02007446 if ((unsigned char)*p == CTLQUOTEMARK)
Felix Fietkaub5b21122017-01-31 21:58:55 +01007447 break;
Denys Vlasenkoac61f442018-03-30 23:03:29 +02007448 if ((unsigned char)*p == CTLESC)
Felix Fietkaub5b21122017-01-31 21:58:55 +01007449 p++;
7450 if (*p == '\0') /* huh? */
7451 return 0;
7452 }
7453 break;
7454 case '\\':
7455 case CTLESC:
7456 p++;
7457 if (*p == '\0')
7458 return 0;
7459 break;
7460 case '[':
7461 if (!strchr(p + 1, ']')) {
7462 /* It's not a properly closed [] pattern,
7463 * but other metas may follow. Continue checking.
7464 * my[file* _is_ globbed by bash
7465 * and matches filenames like "my[file1".
7466 */
7467 break;
7468 }
7469 /* fallthrough */
7470 default:
7471 /* case '*': */
7472 /* case '?': */
7473 return 1;
7474 }
7475 p++;
7476 }
7477
7478 return 0;
7479}
7480
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007481/* If we want to use glob() from libc... */
Denys Vlasenko514b51d2016-10-01 14:33:08 +02007482#if !ENABLE_ASH_INTERNAL_GLOB
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007483
7484/* Add the result of glob() to the list */
7485static void
7486addglob(const glob_t *pglob)
7487{
7488 char **p = pglob->gl_pathv;
7489
7490 do {
7491 addfname(*p);
7492 } while (*++p);
7493}
7494static void
7495expandmeta(struct strlist *str /*, int flag*/)
7496{
7497 /* TODO - EXP_REDIR */
7498
7499 while (str) {
7500 char *p;
7501 glob_t pglob;
7502 int i;
7503
7504 if (fflag)
7505 goto nometa;
Denys Vlasenkod4f3db92016-10-30 18:41:01 +01007506
Felix Fietkaub5b21122017-01-31 21:58:55 +01007507 if (!hasmeta(str->text))
7508 goto nometa;
Denys Vlasenkod4f3db92016-10-30 18:41:01 +01007509
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007510 INT_OFF;
7511 p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP);
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007512// GLOB_NOMAGIC (GNU): if no *?[ chars in pattern, return it even if no match
7513// GLOB_NOCHECK: if no match, return unchanged pattern (sans \* escapes?)
7514//
7515// glibc 2.24.90 glob(GLOB_NOMAGIC) does not remove backslashes used for escaping:
7516// if you pass it "file\?", it returns "file\?", not "file?", if no match.
7517// Which means you need to unescape the string, right? Not so fast:
7518// if there _is_ a file named "file\?" (with backslash), it is returned
7519// as "file\?" too (whichever pattern you used to find it, say, "file*").
Denys Vlasenko10ad6222017-04-17 16:13:32 +02007520// You DON'T KNOW by looking at the result whether you need to unescape it.
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007521//
7522// Worse, globbing of "file\?" in a directory with two files, "file?" and "file\?",
7523// returns "file\?" - which is WRONG: "file\?" pattern matches "file?" file.
7524// Without GLOB_NOMAGIC, this works correctly ("file?" is returned as a match).
7525// With GLOB_NOMAGIC | GLOB_NOCHECK, this also works correctly.
7526// i = glob(p, GLOB_NOMAGIC | GLOB_NOCHECK, NULL, &pglob);
7527// i = glob(p, GLOB_NOMAGIC, NULL, &pglob);
7528 i = glob(p, 0, NULL, &pglob);
7529 //bb_error_msg("glob('%s'):%d '%s'...", p, i, pglob.gl_pathv ? pglob.gl_pathv[0] : "-");
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007530 if (p != str->text)
7531 free(p);
7532 switch (i) {
7533 case 0:
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007534#if 0 // glibc 2.24.90 bug? Patterns like "*/file", when match, don't set GLOB_MAGCHAR
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007535 /* GLOB_MAGCHAR is set if *?[ chars were seen (GNU) */
7536 if (!(pglob.gl_flags & GLOB_MAGCHAR))
7537 goto nometa2;
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007538#endif
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007539 addglob(&pglob);
7540 globfree(&pglob);
7541 INT_ON;
7542 break;
7543 case GLOB_NOMATCH:
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007544 //nometa2:
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007545 globfree(&pglob);
7546 INT_ON;
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007547 nometa:
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007548 *exparg.lastp = str;
Denys Vlasenko740058b2018-01-09 17:01:00 +01007549 rmescapes(str->text, 0, NULL);
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007550 exparg.lastp = &str->next;
7551 break;
7552 default: /* GLOB_NOSPACE */
7553 globfree(&pglob);
7554 INT_ON;
7555 ash_msg_and_raise_error(bb_msg_memory_exhausted);
7556 }
7557 str = str->next;
7558 }
7559}
7560
7561#else
Denys Vlasenko514b51d2016-10-01 14:33:08 +02007562/* ENABLE_ASH_INTERNAL_GLOB: Homegrown globbing code. (dash also has both, uses homegrown one.) */
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007563
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007564/*
7565 * Do metacharacter (i.e. *, ?, [...]) expansion.
7566 */
7567static void
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007568expmeta(char *expdir, char *enddir, char *name)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007569{
7570 char *p;
7571 const char *cp;
7572 char *start;
7573 char *endname;
7574 int metaflag;
7575 struct stat statb;
7576 DIR *dirp;
7577 struct dirent *dp;
7578 int atend;
7579 int matchdot;
Ron Yorstonca25af92015-09-04 10:32:41 +01007580 int esc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007581
7582 metaflag = 0;
7583 start = name;
Ron Yorstonca25af92015-09-04 10:32:41 +01007584 for (p = name; esc = 0, *p; p += esc + 1) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007585 if (*p == '*' || *p == '?')
7586 metaflag = 1;
7587 else if (*p == '[') {
7588 char *q = p + 1;
7589 if (*q == '!')
7590 q++;
7591 for (;;) {
7592 if (*q == '\\')
7593 q++;
7594 if (*q == '/' || *q == '\0')
7595 break;
7596 if (*++q == ']') {
7597 metaflag = 1;
7598 break;
7599 }
7600 }
Ron Yorstonca25af92015-09-04 10:32:41 +01007601 } else {
7602 if (*p == '\\')
7603 esc++;
7604 if (p[esc] == '/') {
7605 if (metaflag)
7606 break;
7607 start = p + esc + 1;
7608 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007609 }
7610 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007611 if (metaflag == 0) { /* we've reached the end of the file name */
7612 if (enddir != expdir)
7613 metaflag++;
7614 p = name;
7615 do {
7616 if (*p == '\\')
7617 p++;
7618 *enddir++ = *p;
7619 } while (*p++);
7620 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
7621 addfname(expdir);
7622 return;
7623 }
7624 endname = p;
7625 if (name < start) {
7626 p = name;
7627 do {
7628 if (*p == '\\')
7629 p++;
7630 *enddir++ = *p++;
7631 } while (p < start);
7632 }
7633 if (enddir == expdir) {
7634 cp = ".";
7635 } else if (enddir == expdir + 1 && *expdir == '/') {
7636 cp = "/";
7637 } else {
7638 cp = expdir;
7639 enddir[-1] = '\0';
7640 }
7641 dirp = opendir(cp);
7642 if (dirp == NULL)
7643 return;
7644 if (enddir != expdir)
7645 enddir[-1] = '/';
7646 if (*endname == 0) {
7647 atend = 1;
7648 } else {
7649 atend = 0;
Ron Yorstonca25af92015-09-04 10:32:41 +01007650 *endname = '\0';
7651 endname += esc + 1;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007652 }
7653 matchdot = 0;
7654 p = start;
7655 if (*p == '\\')
7656 p++;
7657 if (*p == '.')
7658 matchdot++;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02007659 while (!pending_int && (dp = readdir(dirp)) != NULL) {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00007660 if (dp->d_name[0] == '.' && !matchdot)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007661 continue;
7662 if (pmatch(start, dp->d_name)) {
7663 if (atend) {
7664 strcpy(enddir, dp->d_name);
7665 addfname(expdir);
7666 } else {
7667 for (p = enddir, cp = dp->d_name; (*p++ = *cp++) != '\0';)
7668 continue;
7669 p[-1] = '/';
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007670 expmeta(expdir, p, endname);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007671 }
7672 }
7673 }
7674 closedir(dirp);
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00007675 if (!atend)
Ron Yorstonca25af92015-09-04 10:32:41 +01007676 endname[-esc - 1] = esc ? '\\' : '/';
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007677}
7678
7679static struct strlist *
7680msort(struct strlist *list, int len)
7681{
7682 struct strlist *p, *q = NULL;
7683 struct strlist **lpp;
7684 int half;
7685 int n;
7686
7687 if (len <= 1)
7688 return list;
7689 half = len >> 1;
7690 p = list;
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +00007691 for (n = half; --n >= 0;) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007692 q = p;
7693 p = p->next;
7694 }
7695 q->next = NULL; /* terminate first half of list */
7696 q = msort(list, half); /* sort first half of list */
7697 p = msort(p, len - half); /* sort second half */
7698 lpp = &list;
7699 for (;;) {
7700#if ENABLE_LOCALE_SUPPORT
7701 if (strcoll(p->text, q->text) < 0)
7702#else
7703 if (strcmp(p->text, q->text) < 0)
7704#endif
7705 {
7706 *lpp = p;
7707 lpp = &p->next;
7708 p = *lpp;
7709 if (p == NULL) {
7710 *lpp = q;
7711 break;
7712 }
7713 } else {
7714 *lpp = q;
7715 lpp = &q->next;
7716 q = *lpp;
7717 if (q == NULL) {
7718 *lpp = p;
7719 break;
7720 }
7721 }
7722 }
7723 return list;
7724}
7725
7726/*
7727 * Sort the results of file name expansion. It calculates the number of
7728 * strings to sort and then calls msort (short for merge sort) to do the
7729 * work.
7730 */
7731static struct strlist *
7732expsort(struct strlist *str)
7733{
7734 int len;
7735 struct strlist *sp;
7736
7737 len = 0;
7738 for (sp = str; sp; sp = sp->next)
7739 len++;
7740 return msort(str, len);
7741}
7742
7743static void
Denis Vlasenko68404f12008-03-17 09:00:54 +00007744expandmeta(struct strlist *str /*, int flag*/)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007745{
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007746 /* TODO - EXP_REDIR */
7747
7748 while (str) {
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007749 char *expdir;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007750 struct strlist **savelastp;
7751 struct strlist *sp;
7752 char *p;
7753
7754 if (fflag)
7755 goto nometa;
Felix Fietkaub5b21122017-01-31 21:58:55 +01007756 if (!hasmeta(str->text))
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007757 goto nometa;
7758 savelastp = exparg.lastp;
7759
7760 INT_OFF;
Ron Yorston549deab2015-05-18 09:57:51 +02007761 p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007762 {
7763 int i = strlen(str->text);
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007764//BUGGY estimation of how long expanded name can be
7765 expdir = ckmalloc(i < 2048 ? 2048 : i+1);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007766 }
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007767 expmeta(expdir, expdir, p);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007768 free(expdir);
7769 if (p != str->text)
7770 free(p);
7771 INT_ON;
7772 if (exparg.lastp == savelastp) {
7773 /*
7774 * no matches
7775 */
7776 nometa:
7777 *exparg.lastp = str;
Denys Vlasenko740058b2018-01-09 17:01:00 +01007778 rmescapes(str->text, 0, NULL);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007779 exparg.lastp = &str->next;
7780 } else {
7781 *exparg.lastp = NULL;
7782 *savelastp = sp = expsort(*savelastp);
7783 while (sp->next != NULL)
7784 sp = sp->next;
7785 exparg.lastp = &sp->next;
7786 }
7787 str = str->next;
7788 }
7789}
Denys Vlasenko514b51d2016-10-01 14:33:08 +02007790#endif /* ENABLE_ASH_INTERNAL_GLOB */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007791
7792/*
7793 * Perform variable substitution and command substitution on an argument,
7794 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
7795 * perform splitting and file name expansion. When arglist is NULL, perform
7796 * here document expansion.
7797 */
7798static void
7799expandarg(union node *arg, struct arglist *arglist, int flag)
7800{
7801 struct strlist *sp;
7802 char *p;
7803
7804 argbackq = arg->narg.backquote;
7805 STARTSTACKSTR(expdest);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02007806 TRACE(("expandarg: argstr('%s',flags:%x)\n", arg->narg.text, flag));
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02007807 argstr(arg->narg.text, flag);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007808 p = _STPUTC('\0', expdest);
7809 expdest = p - 1;
7810 if (arglist == NULL) {
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02007811 /* here document expanded */
7812 goto out;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007813 }
7814 p = grabstackstr(p);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02007815 TRACE(("expandarg: p:'%s'\n", p));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007816 exparg.lastp = &exparg.list;
7817 /*
7818 * TODO - EXP_REDIR
7819 */
7820 if (flag & EXP_FULL) {
7821 ifsbreakup(p, &exparg);
7822 *exparg.lastp = NULL;
7823 exparg.lastp = &exparg.list;
Denis Vlasenko68404f12008-03-17 09:00:54 +00007824 expandmeta(exparg.list /*, flag*/);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007825 } else {
Denis Vlasenko597906c2008-02-20 16:38:54 +00007826 sp = stzalloc(sizeof(*sp));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007827 sp->text = p;
7828 *exparg.lastp = sp;
7829 exparg.lastp = &sp->next;
7830 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007831 *exparg.lastp = NULL;
7832 if (exparg.list) {
7833 *arglist->lastp = exparg.list;
7834 arglist->lastp = exparg.lastp;
7835 }
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02007836
7837 out:
7838 ifsfree();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007839}
7840
7841/*
7842 * Expand shell variables and backquotes inside a here document.
7843 */
7844static void
7845expandhere(union node *arg, int fd)
7846{
Ron Yorston549deab2015-05-18 09:57:51 +02007847 expandarg(arg, (struct arglist *)NULL, EXP_QUOTED);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007848 full_write(fd, stackblock(), expdest - (char *)stackblock());
7849}
7850
7851/*
7852 * Returns true if the pattern matches the string.
7853 */
7854static int
7855patmatch(char *pattern, const char *string)
7856{
Denys Vlasenkobd43c672017-07-05 23:12:15 +02007857 char *p = preglob(pattern, 0);
Denys Vlasenko4476c702017-08-15 15:27:41 +02007858 int r = pmatch(p, string);
7859 //bb_error_msg("!fnmatch(pattern:'%s',str:'%s',0):%d", p, string, r);
7860 return r;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007861}
7862
7863/*
7864 * See if a pattern matches in a case statement.
7865 */
7866static int
7867casematch(union node *pattern, char *val)
7868{
7869 struct stackmark smark;
7870 int result;
7871
7872 setstackmark(&smark);
7873 argbackq = pattern->narg.backquote;
7874 STARTSTACKSTR(expdest);
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02007875 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007876 STACKSTRNUL(expdest);
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02007877 ifsfree();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007878 result = patmatch(stackblock(), val);
7879 popstackmark(&smark);
7880 return result;
7881}
7882
7883
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007884/* ============ find_command */
7885
7886struct builtincmd {
7887 const char *name;
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02007888 int (*builtin)(int, char **) FAST_FUNC;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007889 /* unsigned flags; */
7890};
7891#define IS_BUILTIN_SPECIAL(b) ((b)->name[0] & 1)
Denis Vlasenkoe26b2782008-02-12 07:40:29 +00007892/* "regular" builtins always take precedence over commands,
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007893 * regardless of PATH=....%builtin... position */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007894#define IS_BUILTIN_REGULAR(b) ((b)->name[0] & 2)
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007895#define IS_BUILTIN_ASSIGN(b) ((b)->name[0] & 4)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007896
7897struct cmdentry {
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00007898 smallint cmdtype; /* CMDxxx */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007899 union param {
7900 int index;
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00007901 /* index >= 0 for commands without path (slashes) */
7902 /* (TODO: what exactly does the value mean? PATH position?) */
7903 /* index == -1 for commands with slashes */
7904 /* index == (-2 - applet_no) for NOFORK applets */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007905 const struct builtincmd *cmd;
7906 struct funcnode *func;
7907 } u;
7908};
7909/* values of cmdtype */
7910#define CMDUNKNOWN -1 /* no entry in table for command */
7911#define CMDNORMAL 0 /* command is an executable program */
7912#define CMDFUNCTION 1 /* command is a shell function */
7913#define CMDBUILTIN 2 /* command is a shell builtin */
7914
7915/* action to find_command() */
7916#define DO_ERR 0x01 /* prints errors */
7917#define DO_ABS 0x02 /* checks absolute paths */
7918#define DO_NOFUNC 0x04 /* don't return shell functions, for command */
7919#define DO_ALTPATH 0x08 /* using alternate path */
7920#define DO_ALTBLTIN 0x20 /* %builtin in alt. path */
7921
7922static void find_command(char *, struct cmdentry *, int, const char *);
7923
7924
7925/* ============ Hashing commands */
7926
7927/*
7928 * When commands are first encountered, they are entered in a hash table.
7929 * This ensures that a full path search will not have to be done for them
7930 * on each invocation.
7931 *
7932 * We should investigate converting to a linear search, even though that
7933 * would make the command name "hash" a misnomer.
7934 */
7935
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007936struct tblentry {
7937 struct tblentry *next; /* next entry in hash chain */
7938 union param param; /* definition of builtin function */
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00007939 smallint cmdtype; /* CMDxxx */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007940 char rehash; /* if set, cd done since entry created */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00007941 char cmdname[1]; /* name of command */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007942};
7943
Denis Vlasenko01631112007-12-16 17:20:38 +00007944static struct tblentry **cmdtable;
7945#define INIT_G_cmdtable() do { \
7946 cmdtable = xzalloc(CMDTABLESIZE * sizeof(cmdtable[0])); \
7947} while (0)
7948
7949static int builtinloc = -1; /* index in path of %builtin, or -1 */
7950
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007951
7952static void
Denys Vlasenko00a1dbd2017-07-29 01:20:53 +02007953tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) const char *cmd, char **argv, char **envp)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007954{
Denis Vlasenko80d14be2007-04-10 23:03:30 +00007955#if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007956 if (applet_no >= 0) {
Denis Vlasenkob7304742008-10-20 08:15:51 +00007957 if (APPLET_IS_NOEXEC(applet_no)) {
Denys Vlasenko7df28bb2010-06-18 14:23:47 +02007958 clearenv();
Denis Vlasenkob7304742008-10-20 08:15:51 +00007959 while (*envp)
7960 putenv(*envp++);
Denys Vlasenko035486c2017-07-31 04:09:19 +02007961 popredir(/*drop:*/ 1);
Denys Vlasenko80e8e3c2017-08-07 19:24:57 +02007962 run_noexec_applet_and_exit(applet_no, cmd, argv);
Denis Vlasenkob7304742008-10-20 08:15:51 +00007963 }
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007964 /* re-exec ourselves with the new arguments */
7965 execve(bb_busybox_exec_path, argv, envp);
7966 /* If they called chroot or otherwise made the binary no longer
7967 * executable, fall through */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007968 }
7969#endif
7970
7971 repeat:
7972#ifdef SYSV
7973 do {
7974 execve(cmd, argv, envp);
7975 } while (errno == EINTR);
7976#else
7977 execve(cmd, argv, envp);
7978#endif
Denys Vlasenko00a1dbd2017-07-29 01:20:53 +02007979 if (cmd != bb_busybox_exec_path && errno == ENOEXEC) {
Denys Vlasenkoaefe1c22011-03-07 12:02:40 +01007980 /* Run "cmd" as a shell script:
7981 * http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html
7982 * "If the execve() function fails with ENOEXEC, the shell
7983 * shall execute a command equivalent to having a shell invoked
7984 * with the command name as its first operand,
7985 * with any remaining arguments passed to the new shell"
7986 *
7987 * That is, do not use $SHELL, user's shell, or /bin/sh;
7988 * just call ourselves.
Denys Vlasenko2bef5262011-12-16 00:25:17 +01007989 *
7990 * Note that bash reads ~80 chars of the file, and if it sees
7991 * a zero byte before it sees newline, it doesn't try to
7992 * interpret it, but fails with "cannot execute binary file"
Denys Vlasenkocda6ea92011-12-16 00:44:36 +01007993 * message and exit code 126. For one, this prevents attempts
7994 * to interpret foreign ELF binaries as shell scripts.
Denys Vlasenkoaefe1c22011-03-07 12:02:40 +01007995 */
Denys Vlasenko00a1dbd2017-07-29 01:20:53 +02007996 argv[0] = (char*) cmd;
7997 cmd = bb_busybox_exec_path;
Denys Vlasenko65a8b852016-10-26 22:29:11 +02007998 /* NB: this is only possible because all callers of shellexec()
7999 * ensure that the argv[-1] slot exists!
8000 */
8001 argv--;
8002 argv[0] = (char*) "ash";
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008003 goto repeat;
8004 }
8005}
8006
8007/*
8008 * Exec a program. Never returns. If you change this routine, you may
8009 * have to change the find_command routine as well.
Denys Vlasenko65a8b852016-10-26 22:29:11 +02008010 * argv[-1] must exist and be writable! See tryexec() for why.
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008011 */
Denys Vlasenkoe139ae32017-04-12 21:02:33 +02008012static void shellexec(char *prog, char **argv, const char *path, int idx) NORETURN;
8013static void shellexec(char *prog, char **argv, const char *path, int idx)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008014{
8015 char *cmdname;
8016 int e;
8017 char **envp;
8018 int exerrno;
Denys Vlasenko83f103b2011-12-20 06:10:35 +01008019 int applet_no = -1; /* used only by FEATURE_SH_STANDALONE */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008020
Denys Vlasenkoa5060b82017-11-03 14:16:25 +01008021 envp = listvars(VEXPORT, VUNSET, /*strlist:*/ NULL, /*end:*/ NULL);
Denys Vlasenkoe139ae32017-04-12 21:02:33 +02008022 if (strchr(prog, '/') != NULL
Denis Vlasenko80d14be2007-04-10 23:03:30 +00008023#if ENABLE_FEATURE_SH_STANDALONE
Denys Vlasenkoe139ae32017-04-12 21:02:33 +02008024 || (applet_no = find_applet_by_name(prog)) >= 0
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008025#endif
8026 ) {
Denys Vlasenkoe139ae32017-04-12 21:02:33 +02008027 tryexec(IF_FEATURE_SH_STANDALONE(applet_no,) prog, argv, envp);
Denys Vlasenko83f103b2011-12-20 06:10:35 +01008028 if (applet_no >= 0) {
8029 /* We tried execing ourself, but it didn't work.
8030 * Maybe /proc/self/exe doesn't exist?
8031 * Try $PATH search.
8032 */
8033 goto try_PATH;
8034 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008035 e = errno;
8036 } else {
Denys Vlasenko83f103b2011-12-20 06:10:35 +01008037 try_PATH:
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008038 e = ENOENT;
Denys Vlasenkoe139ae32017-04-12 21:02:33 +02008039 while ((cmdname = path_advance(&path, prog)) != NULL) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008040 if (--idx < 0 && pathopt == NULL) {
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00008041 tryexec(IF_FEATURE_SH_STANDALONE(-1,) cmdname, argv, envp);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008042 if (errno != ENOENT && errno != ENOTDIR)
8043 e = errno;
8044 }
8045 stunalloc(cmdname);
8046 }
8047 }
8048
8049 /* Map to POSIX errors */
8050 switch (e) {
8051 case EACCES:
8052 exerrno = 126;
8053 break;
8054 case ENOENT:
8055 exerrno = 127;
8056 break;
8057 default:
8058 exerrno = 2;
8059 break;
8060 }
8061 exitstatus = exerrno;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02008062 TRACE(("shellexec failed for %s, errno %d, suppress_int %d\n",
Denys Vlasenkoe139ae32017-04-12 21:02:33 +02008063 prog, e, suppress_int));
8064 ash_msg_and_raise(EXEXIT, "%s: %s", prog, errmsg(e, "not found"));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008065 /* NOTREACHED */
8066}
8067
8068static void
8069printentry(struct tblentry *cmdp)
8070{
8071 int idx;
8072 const char *path;
8073 char *name;
8074
8075 idx = cmdp->param.index;
8076 path = pathval();
8077 do {
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02008078 name = path_advance(&path, cmdp->cmdname);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008079 stunalloc(name);
8080 } while (--idx >= 0);
8081 out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr));
8082}
8083
8084/*
8085 * Clear out command entries. The argument specifies the first entry in
8086 * PATH which has changed.
8087 */
8088static void
8089clearcmdentry(int firstchange)
8090{
8091 struct tblentry **tblp;
8092 struct tblentry **pp;
8093 struct tblentry *cmdp;
8094
8095 INT_OFF;
8096 for (tblp = cmdtable; tblp < &cmdtable[CMDTABLESIZE]; tblp++) {
8097 pp = tblp;
8098 while ((cmdp = *pp) != NULL) {
8099 if ((cmdp->cmdtype == CMDNORMAL &&
8100 cmdp->param.index >= firstchange)
8101 || (cmdp->cmdtype == CMDBUILTIN &&
8102 builtinloc >= firstchange)
8103 ) {
8104 *pp = cmdp->next;
8105 free(cmdp);
8106 } else {
8107 pp = &cmdp->next;
8108 }
8109 }
8110 }
8111 INT_ON;
8112}
8113
8114/*
8115 * Locate a command in the command hash table. If "add" is nonzero,
8116 * add the command to the table if it is not already present. The
8117 * variable "lastcmdentry" is set to point to the address of the link
8118 * pointing to the entry, so that delete_cmd_entry can delete the
8119 * entry.
8120 *
8121 * Interrupts must be off if called with add != 0.
8122 */
8123static struct tblentry **lastcmdentry;
8124
8125static struct tblentry *
8126cmdlookup(const char *name, int add)
8127{
8128 unsigned int hashval;
8129 const char *p;
8130 struct tblentry *cmdp;
8131 struct tblentry **pp;
8132
8133 p = name;
8134 hashval = (unsigned char)*p << 4;
8135 while (*p)
8136 hashval += (unsigned char)*p++;
8137 hashval &= 0x7FFF;
8138 pp = &cmdtable[hashval % CMDTABLESIZE];
8139 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
8140 if (strcmp(cmdp->cmdname, name) == 0)
8141 break;
8142 pp = &cmdp->next;
8143 }
8144 if (add && cmdp == NULL) {
Denis Vlasenkob07a4962008-06-22 13:16:23 +00008145 cmdp = *pp = ckzalloc(sizeof(struct tblentry)
8146 + strlen(name)
8147 /* + 1 - already done because
8148 * tblentry::cmdname is char[1] */);
Denis Vlasenko597906c2008-02-20 16:38:54 +00008149 /*cmdp->next = NULL; - ckzalloc did it */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008150 cmdp->cmdtype = CMDUNKNOWN;
8151 strcpy(cmdp->cmdname, name);
8152 }
8153 lastcmdentry = pp;
8154 return cmdp;
8155}
8156
8157/*
8158 * Delete the command entry returned on the last lookup.
8159 */
8160static void
8161delete_cmd_entry(void)
8162{
8163 struct tblentry *cmdp;
8164
8165 INT_OFF;
8166 cmdp = *lastcmdentry;
8167 *lastcmdentry = cmdp->next;
8168 if (cmdp->cmdtype == CMDFUNCTION)
8169 freefunc(cmdp->param.func);
8170 free(cmdp);
8171 INT_ON;
8172}
8173
8174/*
8175 * Add a new command entry, replacing any existing command entry for
8176 * the same name - except special builtins.
8177 */
8178static void
8179addcmdentry(char *name, struct cmdentry *entry)
8180{
8181 struct tblentry *cmdp;
8182
8183 cmdp = cmdlookup(name, 1);
8184 if (cmdp->cmdtype == CMDFUNCTION) {
8185 freefunc(cmdp->param.func);
8186 }
8187 cmdp->cmdtype = entry->cmdtype;
8188 cmdp->param = entry->u;
8189 cmdp->rehash = 0;
8190}
8191
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02008192static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00008193hashcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008194{
8195 struct tblentry **pp;
8196 struct tblentry *cmdp;
8197 int c;
8198 struct cmdentry entry;
8199 char *name;
8200
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008201 if (nextopt("r") != '\0') {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008202 clearcmdentry(0);
8203 return 0;
8204 }
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008205
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008206 if (*argptr == NULL) {
8207 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
8208 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
8209 if (cmdp->cmdtype == CMDNORMAL)
8210 printentry(cmdp);
8211 }
8212 }
8213 return 0;
8214 }
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008215
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008216 c = 0;
8217 while ((name = *argptr) != NULL) {
8218 cmdp = cmdlookup(name, 0);
8219 if (cmdp != NULL
8220 && (cmdp->cmdtype == CMDNORMAL
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008221 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))
8222 ) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008223 delete_cmd_entry();
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008224 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008225 find_command(name, &entry, DO_ERR, pathval());
8226 if (entry.cmdtype == CMDUNKNOWN)
8227 c = 1;
8228 argptr++;
8229 }
8230 return c;
8231}
8232
8233/*
8234 * Called when a cd is done. Marks all commands so the next time they
8235 * are executed they will be rehashed.
8236 */
8237static void
8238hashcd(void)
8239{
8240 struct tblentry **pp;
8241 struct tblentry *cmdp;
8242
8243 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
8244 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008245 if (cmdp->cmdtype == CMDNORMAL
8246 || (cmdp->cmdtype == CMDBUILTIN
Denys Vlasenkoe4dcba12010-10-28 18:57:19 +02008247 && !IS_BUILTIN_REGULAR(cmdp->param.cmd)
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008248 && builtinloc > 0)
8249 ) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008250 cmdp->rehash = 1;
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008251 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008252 }
8253 }
8254}
8255
8256/*
8257 * Fix command hash table when PATH changed.
8258 * Called before PATH is changed. The argument is the new value of PATH;
8259 * pathval() still returns the old value at this point.
8260 * Called with interrupts off.
8261 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02008262static void FAST_FUNC
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008263changepath(const char *new)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008264{
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008265 const char *old;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008266 int firstchange;
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008267 int idx;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008268 int idx_bltin;
8269
8270 old = pathval();
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008271 firstchange = 9999; /* assume no change */
8272 idx = 0;
8273 idx_bltin = -1;
8274 for (;;) {
8275 if (*old != *new) {
8276 firstchange = idx;
8277 if ((*old == '\0' && *new == ':')
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +02008278 || (*old == ':' && *new == '\0')
8279 ) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008280 firstchange++;
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +02008281 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008282 old = new; /* ignore subsequent differences */
8283 }
8284 if (*new == '\0')
8285 break;
8286 if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin"))
8287 idx_bltin = idx;
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008288 if (*new == ':')
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008289 idx++;
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +02008290 new++;
8291 old++;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008292 }
8293 if (builtinloc < 0 && idx_bltin >= 0)
8294 builtinloc = idx_bltin; /* zap builtins */
8295 if (builtinloc >= 0 && idx_bltin < 0)
8296 firstchange = 0;
8297 clearcmdentry(firstchange);
8298 builtinloc = idx_bltin;
8299}
Ron Yorston95ebcf72015-11-03 09:42:23 +00008300enum {
8301 TEOF,
8302 TNL,
8303 TREDIR,
8304 TWORD,
8305 TSEMI,
8306 TBACKGND,
8307 TAND,
8308 TOR,
8309 TPIPE,
8310 TLP,
8311 TRP,
8312 TENDCASE,
8313 TENDBQUOTE,
8314 TNOT,
8315 TCASE,
8316 TDO,
8317 TDONE,
8318 TELIF,
8319 TELSE,
8320 TESAC,
8321 TFI,
8322 TFOR,
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01008323#if BASH_FUNCTION
Ron Yorston95ebcf72015-11-03 09:42:23 +00008324 TFUNCTION,
8325#endif
8326 TIF,
8327 TIN,
8328 TTHEN,
8329 TUNTIL,
8330 TWHILE,
8331 TBEGIN,
8332 TEND
8333};
Denis Vlasenkob07a4962008-06-22 13:16:23 +00008334typedef smallint token_id_t;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008335
Denys Vlasenko888527c2016-10-02 16:54:17 +02008336/* Nth bit indicates if token marks the end of a list */
8337enum {
8338 tokendlist = 0
8339 /* 0 */ | (1u << TEOF)
8340 /* 1 */ | (0u << TNL)
8341 /* 2 */ | (0u << TREDIR)
8342 /* 3 */ | (0u << TWORD)
8343 /* 4 */ | (0u << TSEMI)
8344 /* 5 */ | (0u << TBACKGND)
8345 /* 6 */ | (0u << TAND)
8346 /* 7 */ | (0u << TOR)
8347 /* 8 */ | (0u << TPIPE)
8348 /* 9 */ | (0u << TLP)
8349 /* 10 */ | (1u << TRP)
8350 /* 11 */ | (1u << TENDCASE)
8351 /* 12 */ | (1u << TENDBQUOTE)
8352 /* 13 */ | (0u << TNOT)
8353 /* 14 */ | (0u << TCASE)
8354 /* 15 */ | (1u << TDO)
8355 /* 16 */ | (1u << TDONE)
8356 /* 17 */ | (1u << TELIF)
8357 /* 18 */ | (1u << TELSE)
8358 /* 19 */ | (1u << TESAC)
8359 /* 20 */ | (1u << TFI)
8360 /* 21 */ | (0u << TFOR)
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01008361#if BASH_FUNCTION
Denys Vlasenko888527c2016-10-02 16:54:17 +02008362 /* 22 */ | (0u << TFUNCTION)
Denys Vlasenko80729a42016-10-02 22:33:15 +02008363#endif
Denys Vlasenko888527c2016-10-02 16:54:17 +02008364 /* 23 */ | (0u << TIF)
8365 /* 24 */ | (0u << TIN)
8366 /* 25 */ | (1u << TTHEN)
8367 /* 26 */ | (0u << TUNTIL)
8368 /* 27 */ | (0u << TWHILE)
8369 /* 28 */ | (0u << TBEGIN)
8370 /* 29 */ | (1u << TEND)
8371 , /* thus far 29 bits used */
8372};
8373
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008374static const char *const tokname_array[] = {
Denys Vlasenko888527c2016-10-02 16:54:17 +02008375 "end of file",
8376 "newline",
8377 "redirection",
8378 "word",
8379 ";",
8380 "&",
8381 "&&",
8382 "||",
8383 "|",
8384 "(",
8385 ")",
8386 ";;",
8387 "`",
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008388#define KWDOFFSET 13
8389 /* the following are keywords */
Denys Vlasenko888527c2016-10-02 16:54:17 +02008390 "!",
8391 "case",
8392 "do",
8393 "done",
8394 "elif",
8395 "else",
8396 "esac",
8397 "fi",
8398 "for",
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01008399#if BASH_FUNCTION
Denys Vlasenko888527c2016-10-02 16:54:17 +02008400 "function",
Ron Yorston95ebcf72015-11-03 09:42:23 +00008401#endif
Denys Vlasenko888527c2016-10-02 16:54:17 +02008402 "if",
8403 "in",
8404 "then",
8405 "until",
8406 "while",
8407 "{",
8408 "}",
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008409};
8410
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008411/* Wrapper around strcmp for qsort/bsearch/... */
8412static int
8413pstrcmp(const void *a, const void *b)
8414{
Denys Vlasenko888527c2016-10-02 16:54:17 +02008415 return strcmp((char*)a, *(char**)b);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008416}
8417
8418static const char *const *
8419findkwd(const char *s)
8420{
8421 return bsearch(s, tokname_array + KWDOFFSET,
Denis Vlasenko80b8b392007-06-25 10:55:35 +00008422 ARRAY_SIZE(tokname_array) - KWDOFFSET,
8423 sizeof(tokname_array[0]), pstrcmp);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008424}
8425
8426/*
8427 * Locate and print what a word is...
8428 */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008429static int
Ron Yorston3f221112015-08-03 13:47:33 +01008430describe_command(char *command, const char *path, int describe_command_verbose)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008431{
8432 struct cmdentry entry;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008433#if ENABLE_ASH_ALIAS
8434 const struct alias *ap;
8435#endif
Ron Yorston3f221112015-08-03 13:47:33 +01008436
8437 path = path ? path : pathval();
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008438
8439 if (describe_command_verbose) {
8440 out1str(command);
8441 }
8442
8443 /* First look at the keywords */
8444 if (findkwd(command)) {
8445 out1str(describe_command_verbose ? " is a shell keyword" : command);
8446 goto out;
8447 }
8448
8449#if ENABLE_ASH_ALIAS
8450 /* Then look at the aliases */
8451 ap = lookupalias(command, 0);
8452 if (ap != NULL) {
Denis Vlasenko46846e22007-05-20 13:08:31 +00008453 if (!describe_command_verbose) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008454 out1str("alias ");
8455 printalias(ap);
8456 return 0;
8457 }
Denis Vlasenko46846e22007-05-20 13:08:31 +00008458 out1fmt(" is an alias for %s", ap->val);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008459 goto out;
8460 }
8461#endif
Youfu Zhang6683d1c2017-05-26 15:31:29 +08008462 /* Brute force */
8463 find_command(command, &entry, DO_ABS, path);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008464
8465 switch (entry.cmdtype) {
8466 case CMDNORMAL: {
8467 int j = entry.u.index;
8468 char *p;
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00008469 if (j < 0) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008470 p = command;
8471 } else {
8472 do {
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02008473 p = path_advance(&path, command);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008474 stunalloc(p);
8475 } while (--j >= 0);
8476 }
8477 if (describe_command_verbose) {
Youfu Zhang6683d1c2017-05-26 15:31:29 +08008478 out1fmt(" is %s", p);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008479 } else {
8480 out1str(p);
8481 }
8482 break;
8483 }
8484
8485 case CMDFUNCTION:
8486 if (describe_command_verbose) {
8487 out1str(" is a shell function");
8488 } else {
8489 out1str(command);
8490 }
8491 break;
8492
8493 case CMDBUILTIN:
8494 if (describe_command_verbose) {
8495 out1fmt(" is a %sshell builtin",
8496 IS_BUILTIN_SPECIAL(entry.u.cmd) ?
8497 "special " : nullstr
8498 );
8499 } else {
8500 out1str(command);
8501 }
8502 break;
8503
8504 default:
8505 if (describe_command_verbose) {
8506 out1str(": not found\n");
8507 }
8508 return 127;
8509 }
8510 out:
Denys Vlasenko285ad152009-12-04 23:02:27 +01008511 out1str("\n");
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008512 return 0;
8513}
8514
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02008515static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00008516typecmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008517{
Denis Vlasenko46846e22007-05-20 13:08:31 +00008518 int i = 1;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008519 int err = 0;
Denis Vlasenko46846e22007-05-20 13:08:31 +00008520 int verbose = 1;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008521
Denis Vlasenko46846e22007-05-20 13:08:31 +00008522 /* type -p ... ? (we don't bother checking for 'p') */
Denis Vlasenko1fc62382007-06-25 22:55:34 +00008523 if (argv[1] && argv[1][0] == '-') {
Denis Vlasenko46846e22007-05-20 13:08:31 +00008524 i++;
8525 verbose = 0;
8526 }
Denis Vlasenko68404f12008-03-17 09:00:54 +00008527 while (argv[i]) {
Ron Yorston3f221112015-08-03 13:47:33 +01008528 err |= describe_command(argv[i++], NULL, verbose);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008529 }
8530 return err;
8531}
8532
8533#if ENABLE_ASH_CMDCMD
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008534/* Is it "command [-p] PROG ARGS" bltin, no other opts? Return ptr to "PROG" if yes */
8535static char **
8536parse_command_args(char **argv, const char **path)
8537{
8538 char *cp, c;
8539
8540 for (;;) {
8541 cp = *++argv;
8542 if (!cp)
8543 return NULL;
8544 if (*cp++ != '-')
8545 break;
8546 c = *cp++;
8547 if (!c)
8548 break;
8549 if (c == '-' && !*cp) {
8550 if (!*++argv)
8551 return NULL;
8552 break;
8553 }
8554 do {
8555 switch (c) {
8556 case 'p':
8557 *path = bb_default_path;
8558 break;
8559 default:
8560 /* run 'typecmd' for other options */
8561 return NULL;
8562 }
8563 c = *cp++;
8564 } while (c);
8565 }
8566 return argv;
8567}
8568
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02008569static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00008570commandcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008571{
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008572 char *cmd;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008573 int c;
8574 enum {
8575 VERIFY_BRIEF = 1,
8576 VERIFY_VERBOSE = 2,
8577 } verify = 0;
Ron Yorston3f221112015-08-03 13:47:33 +01008578 const char *path = NULL;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008579
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008580 /* "command [-p] PROG ARGS" (that is, without -V or -v)
8581 * never reaches this function.
8582 */
8583
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008584 while ((c = nextopt("pvV")) != '\0')
8585 if (c == 'V')
8586 verify |= VERIFY_VERBOSE;
8587 else if (c == 'v')
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008588 /*verify |= VERIFY_BRIEF*/;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008589#if DEBUG
8590 else if (c != 'p')
8591 abort();
8592#endif
Ron Yorston3f221112015-08-03 13:47:33 +01008593 else
8594 path = bb_default_path;
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008595
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00008596 /* Mimic bash: just "command -v" doesn't complain, it's a nop */
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008597 cmd = *argptr;
8598 if (/*verify && */ cmd)
8599 return describe_command(cmd, path, verify /* - VERIFY_BRIEF*/);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008600
8601 return 0;
8602}
8603#endif
8604
8605
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008606/*static int funcblocksize; // size of structures in function */
8607/*static int funcstringsize; // size of strings in node */
Denis Vlasenko340299a2008-11-21 10:36:36 +00008608static void *funcblock; /* block to allocate function from */
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008609static char *funcstring_end; /* end of block to allocate strings from */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008610
Denys Vlasenko3e134eb2016-04-22 18:09:21 +02008611static const uint8_t nodesize[N_NUMBER] ALIGN1 = {
Denis Vlasenko340299a2008-11-21 10:36:36 +00008612 [NCMD ] = SHELL_ALIGN(sizeof(struct ncmd)),
8613 [NPIPE ] = SHELL_ALIGN(sizeof(struct npipe)),
8614 [NREDIR ] = SHELL_ALIGN(sizeof(struct nredir)),
8615 [NBACKGND ] = SHELL_ALIGN(sizeof(struct nredir)),
8616 [NSUBSHELL] = SHELL_ALIGN(sizeof(struct nredir)),
8617 [NAND ] = SHELL_ALIGN(sizeof(struct nbinary)),
8618 [NOR ] = SHELL_ALIGN(sizeof(struct nbinary)),
8619 [NSEMI ] = SHELL_ALIGN(sizeof(struct nbinary)),
8620 [NIF ] = SHELL_ALIGN(sizeof(struct nif)),
8621 [NWHILE ] = SHELL_ALIGN(sizeof(struct nbinary)),
8622 [NUNTIL ] = SHELL_ALIGN(sizeof(struct nbinary)),
8623 [NFOR ] = SHELL_ALIGN(sizeof(struct nfor)),
8624 [NCASE ] = SHELL_ALIGN(sizeof(struct ncase)),
8625 [NCLIST ] = SHELL_ALIGN(sizeof(struct nclist)),
8626 [NDEFUN ] = SHELL_ALIGN(sizeof(struct narg)),
8627 [NARG ] = SHELL_ALIGN(sizeof(struct narg)),
8628 [NTO ] = SHELL_ALIGN(sizeof(struct nfile)),
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01008629#if BASH_REDIR_OUTPUT
Denis Vlasenko340299a2008-11-21 10:36:36 +00008630 [NTO2 ] = SHELL_ALIGN(sizeof(struct nfile)),
Denis Vlasenkocc5feab2008-11-22 01:32:40 +00008631#endif
Denis Vlasenko340299a2008-11-21 10:36:36 +00008632 [NCLOBBER ] = SHELL_ALIGN(sizeof(struct nfile)),
8633 [NFROM ] = SHELL_ALIGN(sizeof(struct nfile)),
8634 [NFROMTO ] = SHELL_ALIGN(sizeof(struct nfile)),
8635 [NAPPEND ] = SHELL_ALIGN(sizeof(struct nfile)),
8636 [NTOFD ] = SHELL_ALIGN(sizeof(struct ndup)),
8637 [NFROMFD ] = SHELL_ALIGN(sizeof(struct ndup)),
8638 [NHERE ] = SHELL_ALIGN(sizeof(struct nhere)),
8639 [NXHERE ] = SHELL_ALIGN(sizeof(struct nhere)),
8640 [NNOT ] = SHELL_ALIGN(sizeof(struct nnot)),
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008641};
8642
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008643static int calcsize(int funcblocksize, union node *n);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008644
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008645static int
8646sizenodelist(int funcblocksize, struct nodelist *lp)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008647{
8648 while (lp) {
8649 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008650 funcblocksize = calcsize(funcblocksize, lp->n);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008651 lp = lp->next;
8652 }
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008653 return funcblocksize;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008654}
8655
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008656static int
8657calcsize(int funcblocksize, union node *n)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008658{
8659 if (n == NULL)
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008660 return funcblocksize;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008661 funcblocksize += nodesize[n->type];
8662 switch (n->type) {
8663 case NCMD:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008664 funcblocksize = calcsize(funcblocksize, n->ncmd.redirect);
8665 funcblocksize = calcsize(funcblocksize, n->ncmd.args);
8666 funcblocksize = calcsize(funcblocksize, n->ncmd.assign);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008667 break;
8668 case NPIPE:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008669 funcblocksize = sizenodelist(funcblocksize, n->npipe.cmdlist);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008670 break;
8671 case NREDIR:
8672 case NBACKGND:
8673 case NSUBSHELL:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008674 funcblocksize = calcsize(funcblocksize, n->nredir.redirect);
8675 funcblocksize = calcsize(funcblocksize, n->nredir.n);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008676 break;
8677 case NAND:
8678 case NOR:
8679 case NSEMI:
8680 case NWHILE:
8681 case NUNTIL:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008682 funcblocksize = calcsize(funcblocksize, n->nbinary.ch2);
8683 funcblocksize = calcsize(funcblocksize, n->nbinary.ch1);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008684 break;
8685 case NIF:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008686 funcblocksize = calcsize(funcblocksize, n->nif.elsepart);
8687 funcblocksize = calcsize(funcblocksize, n->nif.ifpart);
8688 funcblocksize = calcsize(funcblocksize, n->nif.test);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008689 break;
8690 case NFOR:
Denys Vlasenko561639a2016-10-07 04:28:33 +02008691 funcblocksize += SHELL_ALIGN(strlen(n->nfor.var) + 1); /* was funcstringsize += ... */
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008692 funcblocksize = calcsize(funcblocksize, n->nfor.body);
8693 funcblocksize = calcsize(funcblocksize, n->nfor.args);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008694 break;
8695 case NCASE:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008696 funcblocksize = calcsize(funcblocksize, n->ncase.cases);
8697 funcblocksize = calcsize(funcblocksize, n->ncase.expr);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008698 break;
8699 case NCLIST:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008700 funcblocksize = calcsize(funcblocksize, n->nclist.body);
8701 funcblocksize = calcsize(funcblocksize, n->nclist.pattern);
8702 funcblocksize = calcsize(funcblocksize, n->nclist.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008703 break;
8704 case NDEFUN:
Denys Vlasenko675d24a2018-01-27 22:02:05 +01008705 funcblocksize = calcsize(funcblocksize, n->ndefun.body);
8706 funcblocksize += SHELL_ALIGN(strlen(n->ndefun.text) + 1);
8707 break;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008708 case NARG:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008709 funcblocksize = sizenodelist(funcblocksize, n->narg.backquote);
Denys Vlasenko561639a2016-10-07 04:28:33 +02008710 funcblocksize += SHELL_ALIGN(strlen(n->narg.text) + 1); /* was funcstringsize += ... */
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008711 funcblocksize = calcsize(funcblocksize, n->narg.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008712 break;
8713 case NTO:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01008714#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00008715 case NTO2:
8716#endif
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008717 case NCLOBBER:
8718 case NFROM:
8719 case NFROMTO:
8720 case NAPPEND:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008721 funcblocksize = calcsize(funcblocksize, n->nfile.fname);
8722 funcblocksize = calcsize(funcblocksize, n->nfile.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008723 break;
8724 case NTOFD:
8725 case NFROMFD:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008726 funcblocksize = calcsize(funcblocksize, n->ndup.vname);
8727 funcblocksize = calcsize(funcblocksize, n->ndup.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008728 break;
8729 case NHERE:
8730 case NXHERE:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008731 funcblocksize = calcsize(funcblocksize, n->nhere.doc);
8732 funcblocksize = calcsize(funcblocksize, n->nhere.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008733 break;
8734 case NNOT:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008735 funcblocksize = calcsize(funcblocksize, n->nnot.com);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008736 break;
8737 };
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008738 return funcblocksize;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008739}
8740
8741static char *
8742nodeckstrdup(char *s)
8743{
Denys Vlasenko561639a2016-10-07 04:28:33 +02008744 funcstring_end -= SHELL_ALIGN(strlen(s) + 1);
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008745 return strcpy(funcstring_end, s);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008746}
8747
8748static union node *copynode(union node *);
8749
8750static struct nodelist *
8751copynodelist(struct nodelist *lp)
8752{
8753 struct nodelist *start;
8754 struct nodelist **lpp;
8755
8756 lpp = &start;
8757 while (lp) {
8758 *lpp = funcblock;
8759 funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist));
8760 (*lpp)->n = copynode(lp->n);
8761 lp = lp->next;
8762 lpp = &(*lpp)->next;
8763 }
8764 *lpp = NULL;
8765 return start;
8766}
8767
8768static union node *
8769copynode(union node *n)
8770{
8771 union node *new;
8772
8773 if (n == NULL)
8774 return NULL;
8775 new = funcblock;
8776 funcblock = (char *) funcblock + nodesize[n->type];
8777
8778 switch (n->type) {
8779 case NCMD:
8780 new->ncmd.redirect = copynode(n->ncmd.redirect);
8781 new->ncmd.args = copynode(n->ncmd.args);
8782 new->ncmd.assign = copynode(n->ncmd.assign);
Denys Vlasenko675d24a2018-01-27 22:02:05 +01008783 new->ncmd.linno = n->ncmd.linno;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008784 break;
8785 case NPIPE:
8786 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00008787 new->npipe.pipe_backgnd = n->npipe.pipe_backgnd;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008788 break;
8789 case NREDIR:
8790 case NBACKGND:
8791 case NSUBSHELL:
8792 new->nredir.redirect = copynode(n->nredir.redirect);
8793 new->nredir.n = copynode(n->nredir.n);
Denys Vlasenko675d24a2018-01-27 22:02:05 +01008794 new->nredir.linno = n->nredir.linno;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008795 break;
8796 case NAND:
8797 case NOR:
8798 case NSEMI:
8799 case NWHILE:
8800 case NUNTIL:
8801 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8802 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8803 break;
8804 case NIF:
8805 new->nif.elsepart = copynode(n->nif.elsepart);
8806 new->nif.ifpart = copynode(n->nif.ifpart);
8807 new->nif.test = copynode(n->nif.test);
8808 break;
8809 case NFOR:
8810 new->nfor.var = nodeckstrdup(n->nfor.var);
8811 new->nfor.body = copynode(n->nfor.body);
8812 new->nfor.args = copynode(n->nfor.args);
Denys Vlasenko675d24a2018-01-27 22:02:05 +01008813 new->nfor.linno = n->nfor.linno;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008814 break;
8815 case NCASE:
8816 new->ncase.cases = copynode(n->ncase.cases);
8817 new->ncase.expr = copynode(n->ncase.expr);
Denys Vlasenko675d24a2018-01-27 22:02:05 +01008818 new->ncase.linno = n->ncase.linno;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008819 break;
8820 case NCLIST:
8821 new->nclist.body = copynode(n->nclist.body);
8822 new->nclist.pattern = copynode(n->nclist.pattern);
8823 new->nclist.next = copynode(n->nclist.next);
8824 break;
8825 case NDEFUN:
Denys Vlasenko675d24a2018-01-27 22:02:05 +01008826 new->ndefun.body = copynode(n->ndefun.body);
8827 new->ndefun.text = nodeckstrdup(n->ndefun.text);
8828 new->ndefun.linno = n->ndefun.linno;
8829 break;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008830 case NARG:
8831 new->narg.backquote = copynodelist(n->narg.backquote);
8832 new->narg.text = nodeckstrdup(n->narg.text);
8833 new->narg.next = copynode(n->narg.next);
8834 break;
8835 case NTO:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01008836#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00008837 case NTO2:
8838#endif
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008839 case NCLOBBER:
8840 case NFROM:
8841 case NFROMTO:
8842 case NAPPEND:
8843 new->nfile.fname = copynode(n->nfile.fname);
8844 new->nfile.fd = n->nfile.fd;
8845 new->nfile.next = copynode(n->nfile.next);
8846 break;
8847 case NTOFD:
8848 case NFROMFD:
8849 new->ndup.vname = copynode(n->ndup.vname);
8850 new->ndup.dupfd = n->ndup.dupfd;
8851 new->ndup.fd = n->ndup.fd;
8852 new->ndup.next = copynode(n->ndup.next);
8853 break;
8854 case NHERE:
8855 case NXHERE:
8856 new->nhere.doc = copynode(n->nhere.doc);
8857 new->nhere.fd = n->nhere.fd;
8858 new->nhere.next = copynode(n->nhere.next);
8859 break;
8860 case NNOT:
8861 new->nnot.com = copynode(n->nnot.com);
8862 break;
8863 };
8864 new->type = n->type;
8865 return new;
8866}
8867
8868/*
8869 * Make a copy of a parse tree.
8870 */
8871static struct funcnode *
8872copyfunc(union node *n)
8873{
8874 struct funcnode *f;
8875 size_t blocksize;
8876
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008877 /*funcstringsize = 0;*/
8878 blocksize = offsetof(struct funcnode, n) + calcsize(0, n);
8879 f = ckzalloc(blocksize /* + funcstringsize */);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008880 funcblock = (char *) f + offsetof(struct funcnode, n);
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008881 funcstring_end = (char *) f + blocksize;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008882 copynode(n);
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008883 /* f->count = 0; - ckzalloc did it */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008884 return f;
8885}
8886
8887/*
8888 * Define a shell function.
8889 */
8890static void
Denys Vlasenko7aec8682016-10-25 20:26:02 +02008891defun(union node *func)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008892{
8893 struct cmdentry entry;
8894
8895 INT_OFF;
8896 entry.cmdtype = CMDFUNCTION;
8897 entry.u.func = copyfunc(func);
Denys Vlasenko675d24a2018-01-27 22:02:05 +01008898 addcmdentry(func->ndefun.text, &entry);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008899 INT_ON;
8900}
8901
Denis Vlasenko4b875702009-03-19 13:30:04 +00008902/* Reasons for skipping commands (see comment on breakcmd routine) */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008903#define SKIPBREAK (1 << 0)
8904#define SKIPCONT (1 << 1)
8905#define SKIPFUNC (1 << 2)
Denis Vlasenko4b875702009-03-19 13:30:04 +00008906static smallint evalskip; /* set to SKIPxxx if we are skipping commands */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008907static int skipcount; /* number of levels to skip */
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +00008908static int loopnest; /* current loop nesting level */
Denys Vlasenko675d24a2018-01-27 22:02:05 +01008909static int funcline; /* starting line number of current function, or 0 if not in a function */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008910
Denis Vlasenko4b875702009-03-19 13:30:04 +00008911/* Forward decl way out to parsing code - dotrap needs it */
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02008912static int evalstring(char *s, int flags);
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008913
Denis Vlasenko4b875702009-03-19 13:30:04 +00008914/* Called to execute a trap.
8915 * Single callsite - at the end of evaltree().
Denys Vlasenkob563f622010-09-25 17:15:13 +02008916 * If we return non-zero, evaltree raises EXEXIT exception.
Denis Vlasenko4b875702009-03-19 13:30:04 +00008917 *
8918 * Perhaps we should avoid entering new trap handlers
8919 * while we are executing a trap handler. [is it a TODO?]
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008920 */
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008921static void
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008922dotrap(void)
8923{
Denis Vlasenko4b875702009-03-19 13:30:04 +00008924 uint8_t *g;
8925 int sig;
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008926 uint8_t last_status;
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008927
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008928 if (!pending_sig)
8929 return;
8930
8931 last_status = exitstatus;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02008932 pending_sig = 0;
Denys Vlasenkode892052016-10-02 01:49:13 +02008933 barrier();
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008934
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008935 TRACE(("dotrap entered\n"));
Denis Vlasenko4b875702009-03-19 13:30:04 +00008936 for (sig = 1, g = gotsig; sig < NSIG; sig++, g++) {
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008937 char *p;
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008938
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008939 if (!*g)
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008940 continue;
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008941
8942 if (evalskip) {
8943 pending_sig = sig;
8944 break;
8945 }
8946
8947 p = trap[sig];
Denis Vlasenko4b875702009-03-19 13:30:04 +00008948 /* non-trapped SIGINT is handled separately by raise_interrupt,
8949 * don't upset it by resetting gotsig[SIGINT-1] */
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008950 if (sig == SIGINT && !p)
Denis Vlasenko4b875702009-03-19 13:30:04 +00008951 continue;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008952
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008953 TRACE(("sig %d is active, will run handler '%s'\n", sig, p));
Denis Vlasenko4b875702009-03-19 13:30:04 +00008954 *g = 0;
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008955 if (!p)
Denis Vlasenko4b875702009-03-19 13:30:04 +00008956 continue;
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008957 evalstring(p, 0);
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008958 }
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008959 exitstatus = last_status;
8960 TRACE(("dotrap returns\n"));
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008961}
8962
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00008963/* forward declarations - evaluation is fairly recursive business... */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008964static int evalloop(union node *, int);
8965static int evalfor(union node *, int);
8966static int evalcase(union node *, int);
8967static int evalsubshell(union node *, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008968static void expredir(union node *);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008969static int evalpipe(union node *, int);
8970static int evalcommand(union node *, int);
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02008971static int evalbltin(const struct builtincmd *, int, char **, int);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008972static void prehash(union node *);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008973
Eric Andersen62483552001-07-10 06:09:16 +00008974/*
Eric Andersenc470f442003-07-28 09:56:35 +00008975 * Evaluate a parse tree. The value is left in the global variable
8976 * exitstatus.
Eric Andersen62483552001-07-10 06:09:16 +00008977 */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008978static int
Eric Andersenc470f442003-07-28 09:56:35 +00008979evaltree(union node *n, int flags)
Eric Andersen62483552001-07-10 06:09:16 +00008980{
Eric Andersenc470f442003-07-28 09:56:35 +00008981 int checkexit = 0;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008982 int (*evalfn)(union node *, int);
8983 int status = 0;
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008984
Eric Andersenc470f442003-07-28 09:56:35 +00008985 if (n == NULL) {
8986 TRACE(("evaltree(NULL) called\n"));
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02008987 goto out;
Eric Andersen62483552001-07-10 06:09:16 +00008988 }
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008989 TRACE(("evaltree(%p: %d, %d) called\n", n, n->type, flags));
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008990
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008991 dotrap();
8992
Eric Andersenc470f442003-07-28 09:56:35 +00008993 switch (n->type) {
8994 default:
Denis Vlasenkoa7189f02006-11-17 20:29:00 +00008995#if DEBUG
Eric Andersenc470f442003-07-28 09:56:35 +00008996 out1fmt("Node type = %d\n", n->type);
Denys Vlasenko8131eea2009-11-02 14:19:51 +01008997 fflush_all();
Eric Andersenc470f442003-07-28 09:56:35 +00008998 break;
8999#endif
9000 case NNOT:
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009001 status = !evaltree(n->nnot.com, EV_TESTED);
Eric Andersenc470f442003-07-28 09:56:35 +00009002 goto setstatus;
9003 case NREDIR:
Denys Vlasenko675d24a2018-01-27 22:02:05 +01009004 errlinno = lineno = n->nredir.linno;
9005 if (funcline)
9006 lineno -= funcline - 1;
Eric Andersenc470f442003-07-28 09:56:35 +00009007 expredir(n->nredir.redirect);
Denys Vlasenko1c79aeb2017-07-29 22:51:52 +02009008 pushredir(n->nredir.redirect);
Eric Andersenc470f442003-07-28 09:56:35 +00009009 status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
9010 if (!status) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009011 status = evaltree(n->nredir.n, flags & EV_TESTED);
Eric Andersenc470f442003-07-28 09:56:35 +00009012 }
Denys Vlasenkoeaf94362016-10-25 21:46:03 +02009013 if (n->nredir.redirect)
Denys Vlasenko035486c2017-07-31 04:09:19 +02009014 popredir(/*drop:*/ 0);
Eric Andersenc470f442003-07-28 09:56:35 +00009015 goto setstatus;
9016 case NCMD:
9017 evalfn = evalcommand;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009018 checkexit:
Eric Andersenc470f442003-07-28 09:56:35 +00009019 if (eflag && !(flags & EV_TESTED))
9020 checkexit = ~0;
9021 goto calleval;
9022 case NFOR:
9023 evalfn = evalfor;
9024 goto calleval;
9025 case NWHILE:
9026 case NUNTIL:
9027 evalfn = evalloop;
9028 goto calleval;
9029 case NSUBSHELL:
9030 case NBACKGND:
9031 evalfn = evalsubshell;
Denys Vlasenkocf98b0c2016-10-25 18:19:39 +02009032 goto checkexit;
Eric Andersenc470f442003-07-28 09:56:35 +00009033 case NPIPE:
9034 evalfn = evalpipe;
9035 goto checkexit;
9036 case NCASE:
9037 evalfn = evalcase;
9038 goto calleval;
9039 case NAND:
9040 case NOR:
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00009041 case NSEMI: {
9042
Eric Andersenc470f442003-07-28 09:56:35 +00009043#if NAND + 1 != NOR
9044#error NAND + 1 != NOR
9045#endif
9046#if NOR + 1 != NSEMI
9047#error NOR + 1 != NSEMI
9048#endif
Denis Vlasenko87d5fd92008-07-26 13:48:35 +00009049 unsigned is_or = n->type - NAND;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009050 status = evaltree(
Eric Andersenc470f442003-07-28 09:56:35 +00009051 n->nbinary.ch1,
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00009052 (flags | ((is_or >> 1) - 1)) & EV_TESTED
Eric Andersenc470f442003-07-28 09:56:35 +00009053 );
Denys Vlasenkobc1a0082016-10-02 15:31:33 +02009054 if ((!status) == is_or || evalskip)
Eric Andersenc470f442003-07-28 09:56:35 +00009055 break;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009056 n = n->nbinary.ch2;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009057 evaln:
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009058 evalfn = evaltree;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009059 calleval:
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009060 status = evalfn(n, flags);
9061 goto setstatus;
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00009062 }
Eric Andersenc470f442003-07-28 09:56:35 +00009063 case NIF:
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009064 status = evaltree(n->nif.test, EV_TESTED);
Eric Andersenc470f442003-07-28 09:56:35 +00009065 if (evalskip)
9066 break;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009067 if (!status) {
Eric Andersenc470f442003-07-28 09:56:35 +00009068 n = n->nif.ifpart;
9069 goto evaln;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00009070 }
9071 if (n->nif.elsepart) {
Eric Andersenc470f442003-07-28 09:56:35 +00009072 n = n->nif.elsepart;
9073 goto evaln;
9074 }
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009075 status = 0;
9076 goto setstatus;
Eric Andersenc470f442003-07-28 09:56:35 +00009077 case NDEFUN:
Denys Vlasenko7aec8682016-10-25 20:26:02 +02009078 defun(n);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009079 /* Not necessary. To test it:
9080 * "false; f() { qwerty; }; echo $?" should print 0.
9081 */
9082 /* status = 0; */
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009083 setstatus:
Eric Andersenc470f442003-07-28 09:56:35 +00009084 exitstatus = status;
9085 break;
9086 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009087 out:
Denys Vlasenkob563f622010-09-25 17:15:13 +02009088 /* Order of checks below is important:
9089 * signal handlers trigger before exit caused by "set -e".
9090 */
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02009091 dotrap();
9092
9093 if (checkexit & status)
Denis Vlasenkob012b102007-02-19 22:43:01 +00009094 raise_exception(EXEXIT);
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02009095 if (flags & EV_EXIT)
9096 raise_exception(EXEXIT);
Denis Vlasenko653d8e72009-03-19 21:59:35 +00009097
Denis Vlasenko653d8e72009-03-19 21:59:35 +00009098 TRACE(("leaving evaltree (no interrupts)\n"));
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009099 return exitstatus;
Eric Andersen62483552001-07-10 06:09:16 +00009100}
9101
Denys Vlasenko37dc08b2016-10-02 04:38:07 +02009102static int
9103skiploop(void)
Denys Vlasenko35ec8182016-10-01 19:56:52 +02009104{
9105 int skip = evalskip;
9106
9107 switch (skip) {
9108 case 0:
9109 break;
9110 case SKIPBREAK:
9111 case SKIPCONT:
9112 if (--skipcount <= 0) {
9113 evalskip = 0;
9114 break;
9115 }
9116 skip = SKIPBREAK;
9117 break;
9118 }
9119 return skip;
9120}
9121
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009122static int
Eric Andersenc470f442003-07-28 09:56:35 +00009123evalloop(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00009124{
Denys Vlasenko35ec8182016-10-01 19:56:52 +02009125 int skip;
Eric Andersencb57d552001-06-28 07:25:16 +00009126 int status;
9127
9128 loopnest++;
9129 status = 0;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009130 flags &= EV_TESTED;
Denys Vlasenko35ec8182016-10-01 19:56:52 +02009131 do {
Eric Andersenc470f442003-07-28 09:56:35 +00009132 int i;
9133
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009134 i = evaltree(n->nbinary.ch1, EV_TESTED);
Denys Vlasenko35ec8182016-10-01 19:56:52 +02009135 skip = skiploop();
9136 if (skip == SKIPFUNC)
9137 status = i;
9138 if (skip)
9139 continue;
Eric Andersenc470f442003-07-28 09:56:35 +00009140 if (n->type != NWHILE)
9141 i = !i;
9142 if (i != 0)
9143 break;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009144 status = evaltree(n->nbinary.ch2, flags);
Denys Vlasenko35ec8182016-10-01 19:56:52 +02009145 skip = skiploop();
9146 } while (!(skip & ~SKIPCONT));
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009147 loopnest--;
9148
9149 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00009150}
9151
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009152static int
Eric Andersenc470f442003-07-28 09:56:35 +00009153evalfor(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00009154{
9155 struct arglist arglist;
9156 union node *argp;
9157 struct strlist *sp;
9158 struct stackmark smark;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009159 int status = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00009160
Denys Vlasenko675d24a2018-01-27 22:02:05 +01009161 errlinno = lineno = n->ncase.linno;
9162 if (funcline)
9163 lineno -= funcline - 1;
9164
Eric Andersencb57d552001-06-28 07:25:16 +00009165 setstackmark(&smark);
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00009166 arglist.list = NULL;
Eric Andersencb57d552001-06-28 07:25:16 +00009167 arglist.lastp = &arglist.list;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009168 for (argp = n->nfor.args; argp; argp = argp->narg.next) {
Ron Yorston549deab2015-05-18 09:57:51 +02009169 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
Eric Andersencb57d552001-06-28 07:25:16 +00009170 }
9171 *arglist.lastp = NULL;
9172
Eric Andersencb57d552001-06-28 07:25:16 +00009173 loopnest++;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009174 flags &= EV_TESTED;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009175 for (sp = arglist.list; sp; sp = sp->next) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009176 setvar0(n->nfor.var, sp->text);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009177 status = evaltree(n->nfor.body, flags);
Denys Vlasenko35ec8182016-10-01 19:56:52 +02009178 if (skiploop() & ~SKIPCONT)
Eric Andersencb57d552001-06-28 07:25:16 +00009179 break;
Eric Andersencb57d552001-06-28 07:25:16 +00009180 }
9181 loopnest--;
Eric Andersencb57d552001-06-28 07:25:16 +00009182 popstackmark(&smark);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009183
9184 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00009185}
9186
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009187static int
Eric Andersenc470f442003-07-28 09:56:35 +00009188evalcase(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00009189{
9190 union node *cp;
9191 union node *patp;
9192 struct arglist arglist;
9193 struct stackmark smark;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009194 int status = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00009195
Denys Vlasenko675d24a2018-01-27 22:02:05 +01009196 errlinno = lineno = n->ncase.linno;
9197 if (funcline)
9198 lineno -= funcline - 1;
9199
Eric Andersencb57d552001-06-28 07:25:16 +00009200 setstackmark(&smark);
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00009201 arglist.list = NULL;
Eric Andersencb57d552001-06-28 07:25:16 +00009202 arglist.lastp = &arglist.list;
Eric Andersencb57d552001-06-28 07:25:16 +00009203 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009204 for (cp = n->ncase.cases; cp && evalskip == 0; cp = cp->nclist.next) {
9205 for (patp = cp->nclist.pattern; patp; patp = patp->narg.next) {
Eric Andersencb57d552001-06-28 07:25:16 +00009206 if (casematch(patp, arglist.list->text)) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009207 /* Ensure body is non-empty as otherwise
9208 * EV_EXIT may prevent us from setting the
9209 * exit status.
9210 */
9211 if (evalskip == 0 && cp->nclist.body) {
9212 status = evaltree(cp->nclist.body, flags);
Eric Andersencb57d552001-06-28 07:25:16 +00009213 }
9214 goto out;
9215 }
9216 }
9217 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009218 out:
Eric Andersencb57d552001-06-28 07:25:16 +00009219 popstackmark(&smark);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009220
9221 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00009222}
9223
Eric Andersenc470f442003-07-28 09:56:35 +00009224/*
9225 * Kick off a subshell to evaluate a tree.
9226 */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009227static int
Eric Andersenc470f442003-07-28 09:56:35 +00009228evalsubshell(union node *n, int flags)
9229{
9230 struct job *jp;
Denys Vlasenko098b7132017-01-11 19:59:03 +01009231 int backgnd = (n->type == NBACKGND); /* FORK_BG(1) if yes, else FORK_FG(0) */
Eric Andersenc470f442003-07-28 09:56:35 +00009232 int status;
9233
Denys Vlasenko675d24a2018-01-27 22:02:05 +01009234 errlinno = lineno = n->nredir.linno;
9235 if (funcline)
9236 lineno -= funcline - 1;
9237
Eric Andersenc470f442003-07-28 09:56:35 +00009238 expredir(n->nredir.redirect);
Denys Vlasenko238bf182010-05-18 15:49:07 +02009239 if (!backgnd && (flags & EV_EXIT) && !may_have_traps)
Eric Andersenc470f442003-07-28 09:56:35 +00009240 goto nofork;
Denis Vlasenkob012b102007-02-19 22:43:01 +00009241 INT_OFF;
Denys Vlasenko098b7132017-01-11 19:59:03 +01009242 if (backgnd == FORK_FG)
9243 get_tty_state();
Denis Vlasenko68404f12008-03-17 09:00:54 +00009244 jp = makejob(/*n,*/ 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009245 if (forkshell(jp, n, backgnd) == 0) {
Denys Vlasenko238bf182010-05-18 15:49:07 +02009246 /* child */
Denis Vlasenkob012b102007-02-19 22:43:01 +00009247 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +00009248 flags |= EV_EXIT;
9249 if (backgnd)
Denys Vlasenko238bf182010-05-18 15:49:07 +02009250 flags &= ~EV_TESTED;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00009251 nofork:
Eric Andersenc470f442003-07-28 09:56:35 +00009252 redirect(n->nredir.redirect, 0);
9253 evaltreenr(n->nredir.n, flags);
9254 /* never returns */
9255 }
Denys Vlasenko70392332016-10-27 02:31:55 +02009256 /* parent */
Eric Andersenc470f442003-07-28 09:56:35 +00009257 status = 0;
Denys Vlasenko098b7132017-01-11 19:59:03 +01009258 if (backgnd == FORK_FG)
Eric Andersenc470f442003-07-28 09:56:35 +00009259 status = waitforjob(jp);
Denis Vlasenkob012b102007-02-19 22:43:01 +00009260 INT_ON;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009261 return status;
Eric Andersenc470f442003-07-28 09:56:35 +00009262}
9263
Eric Andersenc470f442003-07-28 09:56:35 +00009264/*
9265 * Compute the names of the files in a redirection list.
9266 */
Denis Vlasenko99eb8502007-02-23 21:09:49 +00009267static void fixredir(union node *, const char *, int);
Eric Andersenc470f442003-07-28 09:56:35 +00009268static void
9269expredir(union node *n)
9270{
9271 union node *redir;
9272
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009273 for (redir = n; redir; redir = redir->nfile.next) {
Eric Andersenc470f442003-07-28 09:56:35 +00009274 struct arglist fn;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009275
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00009276 fn.list = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00009277 fn.lastp = &fn.list;
9278 switch (redir->type) {
9279 case NFROMTO:
9280 case NFROM:
9281 case NTO:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01009282#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00009283 case NTO2:
9284#endif
Eric Andersenc470f442003-07-28 09:56:35 +00009285 case NCLOBBER:
9286 case NAPPEND:
9287 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02009288 TRACE(("expredir expanded to '%s'\n", fn.list->text));
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01009289#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00009290 store_expfname:
9291#endif
Denys Vlasenko7c4b13e2013-01-17 13:02:27 +01009292#if 0
9293// By the design of stack allocator, the loop of this kind:
9294// while true; do while true; do break; done </dev/null; done
9295// will look like a memory leak: ash plans to free expfname's
9296// of "/dev/null" as soon as it finishes running the loop
9297// (in this case, never).
9298// This "fix" is wrong:
Jon Tollefson4ba6c5d2012-11-13 19:26:53 +01009299 if (redir->nfile.expfname)
9300 stunalloc(redir->nfile.expfname);
Denys Vlasenko7c4b13e2013-01-17 13:02:27 +01009301// It results in corrupted state of stacked allocations.
9302#endif
Eric Andersenc470f442003-07-28 09:56:35 +00009303 redir->nfile.expfname = fn.list->text;
9304 break;
9305 case NFROMFD:
Denis Vlasenko559691a2008-10-05 18:39:31 +00009306 case NTOFD: /* >& */
Eric Andersenc470f442003-07-28 09:56:35 +00009307 if (redir->ndup.vname) {
9308 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009309 if (fn.list == NULL)
Denis Vlasenkob012b102007-02-19 22:43:01 +00009310 ash_msg_and_raise_error("redir error");
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01009311#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00009312//FIXME: we used expandarg with different args!
9313 if (!isdigit_str9(fn.list->text)) {
9314 /* >&file, not >&fd */
9315 if (redir->nfile.fd != 1) /* 123>&file - BAD */
9316 ash_msg_and_raise_error("redir error");
9317 redir->type = NTO2;
9318 goto store_expfname;
9319 }
9320#endif
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009321 fixredir(redir, fn.list->text, 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009322 }
9323 break;
9324 }
9325 }
9326}
9327
Eric Andersencb57d552001-06-28 07:25:16 +00009328/*
Eric Andersencb57d552001-06-28 07:25:16 +00009329 * Evaluate a pipeline. All the processes in the pipeline are children
9330 * of the process creating the pipeline. (This differs from some versions
9331 * of the shell, which make the last process in a pipeline the parent
9332 * of all the rest.)
9333 */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009334static int
Eric Andersenc470f442003-07-28 09:56:35 +00009335evalpipe(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00009336{
9337 struct job *jp;
9338 struct nodelist *lp;
9339 int pipelen;
9340 int prevfd;
9341 int pip[2];
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009342 int status = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00009343
Eric Andersenc470f442003-07-28 09:56:35 +00009344 TRACE(("evalpipe(0x%lx) called\n", (long)n));
Eric Andersencb57d552001-06-28 07:25:16 +00009345 pipelen = 0;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009346 for (lp = n->npipe.cmdlist; lp; lp = lp->next)
Eric Andersencb57d552001-06-28 07:25:16 +00009347 pipelen++;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009348 flags |= EV_EXIT;
Denis Vlasenkob012b102007-02-19 22:43:01 +00009349 INT_OFF;
Denys Vlasenko098b7132017-01-11 19:59:03 +01009350 if (n->npipe.pipe_backgnd == 0)
9351 get_tty_state();
Denis Vlasenko68404f12008-03-17 09:00:54 +00009352 jp = makejob(/*n,*/ pipelen);
Eric Andersencb57d552001-06-28 07:25:16 +00009353 prevfd = -1;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009354 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009355 prehash(lp->n);
Eric Andersencb57d552001-06-28 07:25:16 +00009356 pip[1] = -1;
9357 if (lp->next) {
9358 if (pipe(pip) < 0) {
9359 close(prevfd);
Denys Vlasenko12ffefb2017-08-23 14:52:56 +02009360 ash_msg_and_raise_perror("can't create pipe");
Eric Andersencb57d552001-06-28 07:25:16 +00009361 }
9362 }
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00009363 if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) {
Denys Vlasenko70392332016-10-27 02:31:55 +02009364 /* child */
Denis Vlasenkob012b102007-02-19 22:43:01 +00009365 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +00009366 if (pip[1] >= 0) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009367 close(pip[0]);
Eric Andersencb57d552001-06-28 07:25:16 +00009368 }
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009369 if (prevfd > 0) {
9370 dup2(prevfd, 0);
9371 close(prevfd);
9372 }
9373 if (pip[1] > 1) {
9374 dup2(pip[1], 1);
9375 close(pip[1]);
9376 }
Eric Andersenc470f442003-07-28 09:56:35 +00009377 evaltreenr(lp->n, flags);
9378 /* never returns */
Eric Andersencb57d552001-06-28 07:25:16 +00009379 }
Denys Vlasenko70392332016-10-27 02:31:55 +02009380 /* parent */
Eric Andersencb57d552001-06-28 07:25:16 +00009381 if (prevfd >= 0)
9382 close(prevfd);
9383 prevfd = pip[0];
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +00009384 /* Don't want to trigger debugging */
9385 if (pip[1] != -1)
9386 close(pip[1]);
Eric Andersencb57d552001-06-28 07:25:16 +00009387 }
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00009388 if (n->npipe.pipe_backgnd == 0) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009389 status = waitforjob(jp);
9390 TRACE(("evalpipe: job done exit status %d\n", status));
Eric Andersencb57d552001-06-28 07:25:16 +00009391 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00009392 INT_ON;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009393
9394 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00009395}
9396
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009397/*
9398 * Controls whether the shell is interactive or not.
9399 */
9400static void
9401setinteractive(int on)
9402{
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009403 static smallint is_interactive;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009404
9405 if (++on == is_interactive)
9406 return;
9407 is_interactive = on;
9408 setsignal(SIGINT);
9409 setsignal(SIGQUIT);
9410 setsignal(SIGTERM);
9411#if !ENABLE_FEATURE_SH_EXTRA_QUIET
9412 if (is_interactive > 1) {
9413 /* Looks like they want an interactive shell */
Denis Vlasenkoca525b42007-06-13 12:27:17 +00009414 static smallint did_banner;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009415
Denis Vlasenkoca525b42007-06-13 12:27:17 +00009416 if (!did_banner) {
Denys Vlasenkoc34c0332009-09-29 12:25:30 +02009417 /* note: ash and hush share this string */
9418 out1fmt("\n\n%s %s\n"
Denys Vlasenko2ec34962014-09-08 16:52:39 +02009419 IF_ASH_HELP("Enter 'help' for a list of built-in commands.\n")
9420 "\n",
Denys Vlasenkoc34c0332009-09-29 12:25:30 +02009421 bb_banner,
9422 "built-in shell (ash)"
9423 );
Denis Vlasenkoca525b42007-06-13 12:27:17 +00009424 did_banner = 1;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009425 }
9426 }
9427#endif
9428}
9429
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009430static void
9431optschanged(void)
9432{
9433#if DEBUG
9434 opentrace();
9435#endif
9436 setinteractive(iflag);
9437 setjobctl(mflag);
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009438#if ENABLE_FEATURE_EDITING_VI
9439 if (viflag)
9440 line_input_state->flags |= VI_MODE;
9441 else
9442 line_input_state->flags &= ~VI_MODE;
9443#else
9444 viflag = 0; /* forcibly keep the option off */
9445#endif
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009446}
9447
Denys Vlasenkob8ab27b2017-07-26 19:22:34 +02009448struct localvar_list {
9449 struct localvar_list *next;
9450 struct localvar *lv;
9451};
9452
9453static struct localvar_list *localvar_stack;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009454
9455/*
9456 * Called after a function returns.
9457 * Interrupts must be off.
9458 */
9459static void
Denys Vlasenko981a0562017-07-26 19:53:11 +02009460poplocalvars(int keep)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009461{
Denys Vlasenkob8ab27b2017-07-26 19:22:34 +02009462 struct localvar_list *ll;
9463 struct localvar *lvp, *next;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009464 struct var *vp;
9465
Denys Vlasenkob8ab27b2017-07-26 19:22:34 +02009466 INT_OFF;
9467 ll = localvar_stack;
9468 localvar_stack = ll->next;
9469
9470 next = ll->lv;
9471 free(ll);
9472
9473 while ((lvp = next) != NULL) {
9474 next = lvp->next;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009475 vp = lvp->vp;
Denys Vlasenkob563f622010-09-25 17:15:13 +02009476 TRACE(("poplocalvar %s\n", vp ? vp->var_text : "-"));
Denys Vlasenko981a0562017-07-26 19:53:11 +02009477 if (keep) {
9478 int bits = VSTRFIXED;
9479
9480 if (lvp->flags != VUNSET) {
9481 if (vp->var_text == lvp->text)
9482 bits |= VTEXTFIXED;
9483 else if (!(lvp->flags & (VTEXTFIXED|VSTACK)))
9484 free((char*)lvp->text);
9485 }
9486
9487 vp->flags &= ~bits;
9488 vp->flags |= (lvp->flags & bits);
9489
9490 if ((vp->flags &
9491 (VEXPORT|VREADONLY|VSTRFIXED|VUNSET)) == VUNSET)
9492 unsetvar(vp->var_text);
9493 } else if (vp == NULL) { /* $- saved */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009494 memcpy(optlist, lvp->text, sizeof(optlist));
9495 free((char*)lvp->text);
9496 optschanged();
Denys Vlasenkod5b500c2017-07-26 19:25:40 +02009497 } else if (lvp->flags == VUNSET) {
9498 vp->flags &= ~(VSTRFIXED|VREADONLY);
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009499 unsetvar(vp->var_text);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009500 } else {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009501 if (vp->var_func)
9502 vp->var_func(var_end(lvp->text));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009503 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009504 free((char*)vp->var_text);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009505 vp->flags = lvp->flags;
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009506 vp->var_text = lvp->text;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009507 }
9508 free(lvp);
9509 }
Denys Vlasenkob8ab27b2017-07-26 19:22:34 +02009510 INT_ON;
9511}
9512
9513/*
9514 * Create a new localvar environment.
9515 */
Denys Vlasenko484fc202017-07-26 19:55:31 +02009516static struct localvar_list *
Denys Vlasenkob8ab27b2017-07-26 19:22:34 +02009517pushlocalvars(void)
9518{
9519 struct localvar_list *ll;
9520
9521 INT_OFF;
9522 ll = ckzalloc(sizeof(*ll));
9523 /*ll->lv = NULL; - zalloc did it */
9524 ll->next = localvar_stack;
9525 localvar_stack = ll;
9526 INT_ON;
Denys Vlasenko484fc202017-07-26 19:55:31 +02009527
9528 return ll->next;
9529}
9530
9531static void
9532unwindlocalvars(struct localvar_list *stop)
9533{
9534 while (localvar_stack != stop)
9535 poplocalvars(0);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009536}
9537
9538static int
9539evalfun(struct funcnode *func, int argc, char **argv, int flags)
9540{
9541 volatile struct shparam saveparam;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009542 struct jmploc *volatile savehandler;
9543 struct jmploc jmploc;
9544 int e;
Denys Vlasenko675d24a2018-01-27 22:02:05 +01009545 int savefuncline;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009546
9547 saveparam = shellparam;
Denys Vlasenko675d24a2018-01-27 22:02:05 +01009548 savefuncline = funcline;
Denys Vlasenkoa2d121c2016-09-30 11:30:11 +02009549 savehandler = exception_handler;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009550 e = setjmp(jmploc.loc);
9551 if (e) {
9552 goto funcdone;
9553 }
9554 INT_OFF;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009555 exception_handler = &jmploc;
Denis Vlasenko01631112007-12-16 17:20:38 +00009556 shellparam.malloced = 0;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009557 func->count++;
Denys Vlasenko675d24a2018-01-27 22:02:05 +01009558 funcline = func->n.ndefun.linno;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009559 INT_ON;
9560 shellparam.nparam = argc - 1;
9561 shellparam.p = argv + 1;
9562#if ENABLE_ASH_GETOPTS
9563 shellparam.optind = 1;
9564 shellparam.optoff = -1;
9565#endif
Denys Vlasenkob8ab27b2017-07-26 19:22:34 +02009566 pushlocalvars();
Denys Vlasenko675d24a2018-01-27 22:02:05 +01009567 evaltree(func->n.ndefun.body, flags & EV_TESTED);
Denys Vlasenko981a0562017-07-26 19:53:11 +02009568 poplocalvars(0);
Denis Vlasenko01631112007-12-16 17:20:38 +00009569 funcdone:
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009570 INT_OFF;
Denys Vlasenko675d24a2018-01-27 22:02:05 +01009571 funcline = savefuncline;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009572 freefunc(func);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009573 freeparam(&shellparam);
9574 shellparam = saveparam;
9575 exception_handler = savehandler;
9576 INT_ON;
9577 evalskip &= ~SKIPFUNC;
9578 return e;
9579}
9580
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009581/*
9582 * Make a variable a local variable. When a variable is made local, it's
9583 * value and flags are saved in a localvar structure. The saved values
9584 * will be restored when the shell function returns. We handle the name
Denys Vlasenkoe0a4e102015-05-13 02:20:14 +02009585 * "-" as a special case: it makes changes to "set +-options" local
9586 * (options will be restored on return from the function).
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009587 */
9588static void
9589mklocal(char *name)
9590{
9591 struct localvar *lvp;
9592 struct var **vpp;
9593 struct var *vp;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009594 char *eq = strchr(name, '=');
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009595
9596 INT_OFF;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009597 /* Cater for duplicate "local". Examples:
9598 * x=0; f() { local x=1; echo $x; local x; echo $x; }; f; echo $x
9599 * x=0; f() { local x=1; echo $x; local x=2; echo $x; }; f; echo $x
9600 */
Denys Vlasenkob8ab27b2017-07-26 19:22:34 +02009601 lvp = localvar_stack->lv;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009602 while (lvp) {
Eugene Rudoy1285aa62015-04-26 23:32:00 +02009603 if (lvp->vp && varcmp(lvp->vp->var_text, name) == 0) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009604 if (eq)
9605 setvareq(name, 0);
9606 /* else:
9607 * it's a duplicate "local VAR" declaration, do nothing
9608 */
Denys Vlasenko06b11492016-11-04 16:43:18 +01009609 goto ret;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009610 }
9611 lvp = lvp->next;
9612 }
9613
9614 lvp = ckzalloc(sizeof(*lvp));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009615 if (LONE_DASH(name)) {
9616 char *p;
9617 p = ckmalloc(sizeof(optlist));
9618 lvp->text = memcpy(p, optlist, sizeof(optlist));
9619 vp = NULL;
9620 } else {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009621 vpp = hashvar(name);
9622 vp = *findvar(vpp, name);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009623 if (vp == NULL) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009624 /* variable did not exist yet */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009625 if (eq)
Denys Vlasenkod04fc712017-07-26 20:06:48 +02009626 vp = setvareq(name, VSTRFIXED);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009627 else
Denys Vlasenkod04fc712017-07-26 20:06:48 +02009628 vp = setvar(name, NULL, VSTRFIXED);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009629 lvp->flags = VUNSET;
9630 } else {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009631 lvp->text = vp->var_text;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009632 lvp->flags = vp->flags;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009633 /* make sure neither "struct var" nor string gets freed
9634 * during (un)setting:
9635 */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009636 vp->flags |= VSTRFIXED|VTEXTFIXED;
9637 if (eq)
9638 setvareq(name, 0);
Denys Vlasenko109ee5d2014-03-16 18:41:11 +01009639 else
9640 /* "local VAR" unsets VAR: */
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009641 setvar0(name, NULL);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009642 }
9643 }
9644 lvp->vp = vp;
Denys Vlasenkob8ab27b2017-07-26 19:22:34 +02009645 lvp->next = localvar_stack->lv;
9646 localvar_stack->lv = lvp;
Denys Vlasenko06b11492016-11-04 16:43:18 +01009647 ret:
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009648 INT_ON;
9649}
9650
9651/*
9652 * The "local" command.
9653 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009654static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009655localcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009656{
9657 char *name;
9658
Denys Vlasenkob8ab27b2017-07-26 19:22:34 +02009659 if (!localvar_stack)
Ron Yorstonef2386b2015-10-29 16:19:14 +00009660 ash_msg_and_raise_error("not in a function");
9661
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009662 argv = argptr;
9663 while ((name = *argv++) != NULL) {
9664 mklocal(name);
9665 }
9666 return 0;
9667}
9668
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009669static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009670falsecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009671{
9672 return 1;
9673}
9674
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009675static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009676truecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009677{
9678 return 0;
9679}
9680
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009681static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009682execcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009683{
Denys Vlasenko6c149f42017-04-12 21:31:32 +02009684 optionarg = NULL;
9685 while (nextopt("a:") != '\0')
9686 /* nextopt() sets optionarg to "-a ARGV0" */;
9687
9688 argv = argptr;
9689 if (argv[0]) {
9690 char *prog;
9691
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009692 iflag = 0; /* exit on error */
9693 mflag = 0;
9694 optschanged();
Denys Vlasenkoe5814a52016-07-16 18:33:55 +02009695 /* We should set up signals for "exec CMD"
9696 * the same way as for "CMD" without "exec".
9697 * But optschanged->setinteractive->setsignal
9698 * still thought we are a root shell. Therefore, for example,
9699 * SIGQUIT is still set to IGN. Fix it:
9700 */
9701 shlvl++;
9702 setsignal(SIGQUIT);
9703 /*setsignal(SIGTERM); - unnecessary because of iflag=0 */
9704 /*setsignal(SIGTSTP); - unnecessary because of mflag=0 */
9705 /*setsignal(SIGTTOU); - unnecessary because of mflag=0 */
9706
Denys Vlasenko6c149f42017-04-12 21:31:32 +02009707 prog = argv[0];
9708 if (optionarg)
9709 argv[0] = optionarg;
9710 shellexec(prog, argv, pathval(), 0);
Denys Vlasenkoe5814a52016-07-16 18:33:55 +02009711 /* NOTREACHED */
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009712 }
9713 return 0;
9714}
9715
9716/*
9717 * The return command.
9718 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009719static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009720returncmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009721{
9722 /*
9723 * If called outside a function, do what ksh does;
9724 * skip the rest of the file.
9725 */
Denys Vlasenko6a0710e2016-09-30 14:18:34 +02009726 evalskip = SKIPFUNC;
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009727 return argv[1] ? number(argv[1]) : exitstatus;
9728}
9729
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009730/* Forward declarations for builtintab[] */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009731static int breakcmd(int, char **) FAST_FUNC;
9732static int dotcmd(int, char **) FAST_FUNC;
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009733static int evalcmd(int, char **, int) FAST_FUNC;
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009734static int exitcmd(int, char **) FAST_FUNC;
9735static int exportcmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009736#if ENABLE_ASH_GETOPTS
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009737static int getoptscmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009738#endif
Denys Vlasenko2ec34962014-09-08 16:52:39 +02009739#if ENABLE_ASH_HELP
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009740static int helpcmd(int, char **) FAST_FUNC;
Denis Vlasenko52764022007-02-24 13:42:56 +00009741#endif
Flemming Madsend96ffda2013-04-07 18:47:24 +02009742#if MAX_HISTORY
9743static int historycmd(int, char **) FAST_FUNC;
9744#endif
Denys Vlasenko0b883582016-12-23 16:49:07 +01009745#if ENABLE_FEATURE_SH_MATH
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009746static int letcmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009747#endif
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009748static int readcmd(int, char **) FAST_FUNC;
9749static int setcmd(int, char **) FAST_FUNC;
9750static int shiftcmd(int, char **) FAST_FUNC;
9751static int timescmd(int, char **) FAST_FUNC;
9752static int trapcmd(int, char **) FAST_FUNC;
9753static int umaskcmd(int, char **) FAST_FUNC;
9754static int unsetcmd(int, char **) FAST_FUNC;
9755static int ulimitcmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009756
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009757#define BUILTIN_NOSPEC "0"
9758#define BUILTIN_SPECIAL "1"
9759#define BUILTIN_REGULAR "2"
9760#define BUILTIN_SPEC_REG "3"
9761#define BUILTIN_ASSIGN "4"
9762#define BUILTIN_SPEC_ASSG "5"
9763#define BUILTIN_REG_ASSG "6"
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009764#define BUILTIN_SPEC_REG_ASSG "7"
9765
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009766/* Stubs for calling non-FAST_FUNC's */
Denys Vlasenko265062d2017-01-10 15:13:30 +01009767#if ENABLE_ASH_ECHO
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009768static int FAST_FUNC echocmd(int argc, char **argv) { return echo_main(argc, argv); }
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009769#endif
Denys Vlasenko265062d2017-01-10 15:13:30 +01009770#if ENABLE_ASH_PRINTF
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009771static int FAST_FUNC printfcmd(int argc, char **argv) { return printf_main(argc, argv); }
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009772#endif
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01009773#if ENABLE_ASH_TEST || BASH_TEST2
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009774static int FAST_FUNC testcmd(int argc, char **argv) { return test_main(argc, argv); }
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009775#endif
Denis Vlasenko468aea22008-04-01 14:47:57 +00009776
Denis Vlasenkof7d56652008-03-25 05:51:41 +00009777/* Keep these in proper order since it is searched via bsearch() */
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009778static const struct builtincmd builtintab[] = {
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009779 { BUILTIN_SPEC_REG "." , dotcmd },
9780 { BUILTIN_SPEC_REG ":" , truecmd },
Denys Vlasenko265062d2017-01-10 15:13:30 +01009781#if ENABLE_ASH_TEST
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009782 { BUILTIN_REGULAR "[" , testcmd },
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01009783#endif
9784#if BASH_TEST2
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009785 { BUILTIN_REGULAR "[[" , testcmd },
Denis Vlasenko80591b02008-03-25 07:49:43 +00009786#endif
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009787#if ENABLE_ASH_ALIAS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009788 { BUILTIN_REG_ASSG "alias" , aliascmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009789#endif
9790#if JOBS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009791 { BUILTIN_REGULAR "bg" , fg_bgcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009792#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009793 { BUILTIN_SPEC_REG "break" , breakcmd },
9794 { BUILTIN_REGULAR "cd" , cdcmd },
9795 { BUILTIN_NOSPEC "chdir" , cdcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009796#if ENABLE_ASH_CMDCMD
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009797 { BUILTIN_REGULAR "command" , commandcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009798#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009799 { BUILTIN_SPEC_REG "continue", breakcmd },
Denys Vlasenko265062d2017-01-10 15:13:30 +01009800#if ENABLE_ASH_ECHO
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009801 { BUILTIN_REGULAR "echo" , echocmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009802#endif
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009803 { BUILTIN_SPEC_REG "eval" , NULL }, /*evalcmd() has a differing prototype*/
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009804 { BUILTIN_SPEC_REG "exec" , execcmd },
9805 { BUILTIN_SPEC_REG "exit" , exitcmd },
9806 { BUILTIN_SPEC_REG_ASSG "export" , exportcmd },
9807 { BUILTIN_REGULAR "false" , falsecmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009808#if JOBS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009809 { BUILTIN_REGULAR "fg" , fg_bgcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009810#endif
9811#if ENABLE_ASH_GETOPTS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009812 { BUILTIN_REGULAR "getopts" , getoptscmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009813#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009814 { BUILTIN_NOSPEC "hash" , hashcmd },
Denys Vlasenko2ec34962014-09-08 16:52:39 +02009815#if ENABLE_ASH_HELP
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009816 { BUILTIN_NOSPEC "help" , helpcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009817#endif
Flemming Madsend96ffda2013-04-07 18:47:24 +02009818#if MAX_HISTORY
9819 { BUILTIN_NOSPEC "history" , historycmd },
9820#endif
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009821#if JOBS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009822 { BUILTIN_REGULAR "jobs" , jobscmd },
9823 { BUILTIN_REGULAR "kill" , killcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009824#endif
Denys Vlasenko0b883582016-12-23 16:49:07 +01009825#if ENABLE_FEATURE_SH_MATH
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009826 { BUILTIN_NOSPEC "let" , letcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009827#endif
Denys Vlasenko85241c72017-07-26 20:00:08 +02009828 { BUILTIN_SPEC_REG_ASSG "local" , localcmd },
Denys Vlasenko265062d2017-01-10 15:13:30 +01009829#if ENABLE_ASH_PRINTF
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009830 { BUILTIN_REGULAR "printf" , printfcmd },
Denis Vlasenkocd2663f2008-06-01 22:36:39 +00009831#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009832 { BUILTIN_NOSPEC "pwd" , pwdcmd },
9833 { BUILTIN_REGULAR "read" , readcmd },
9834 { BUILTIN_SPEC_REG_ASSG "readonly", exportcmd },
9835 { BUILTIN_SPEC_REG "return" , returncmd },
9836 { BUILTIN_SPEC_REG "set" , setcmd },
9837 { BUILTIN_SPEC_REG "shift" , shiftcmd },
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01009838#if BASH_SOURCE
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009839 { BUILTIN_SPEC_REG "source" , dotcmd },
Denys Vlasenko82731b42010-05-17 17:49:52 +02009840#endif
Denys Vlasenko265062d2017-01-10 15:13:30 +01009841#if ENABLE_ASH_TEST
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009842 { BUILTIN_REGULAR "test" , testcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009843#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009844 { BUILTIN_SPEC_REG "times" , timescmd },
9845 { BUILTIN_SPEC_REG "trap" , trapcmd },
9846 { BUILTIN_REGULAR "true" , truecmd },
9847 { BUILTIN_NOSPEC "type" , typecmd },
9848 { BUILTIN_NOSPEC "ulimit" , ulimitcmd },
9849 { BUILTIN_REGULAR "umask" , umaskcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009850#if ENABLE_ASH_ALIAS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009851 { BUILTIN_REGULAR "unalias" , unaliascmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009852#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009853 { BUILTIN_SPEC_REG "unset" , unsetcmd },
9854 { BUILTIN_REGULAR "wait" , waitcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009855};
9856
Denis Vlasenko80591b02008-03-25 07:49:43 +00009857/* Should match the above table! */
9858#define COMMANDCMD (builtintab + \
Denys Vlasenko928e2a72016-09-29 00:30:31 +02009859 /* . : */ 2 + \
Denys Vlasenko265062d2017-01-10 15:13:30 +01009860 /* [ */ 1 * ENABLE_ASH_TEST + \
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01009861 /* [[ */ 1 * BASH_TEST2 + \
Denys Vlasenko928e2a72016-09-29 00:30:31 +02009862 /* alias */ 1 * ENABLE_ASH_ALIAS + \
9863 /* bg */ 1 * ENABLE_ASH_JOB_CONTROL + \
9864 /* break cd cddir */ 3)
9865#define EVALCMD (COMMANDCMD + \
9866 /* command */ 1 * ENABLE_ASH_CMDCMD + \
9867 /* continue */ 1 + \
Denys Vlasenko265062d2017-01-10 15:13:30 +01009868 /* echo */ 1 * ENABLE_ASH_ECHO + \
Denys Vlasenko928e2a72016-09-29 00:30:31 +02009869 0)
9870#define EXECCMD (EVALCMD + \
9871 /* eval */ 1)
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009872
9873/*
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009874 * Search the table of builtin commands.
9875 */
Denys Vlasenko888527c2016-10-02 16:54:17 +02009876static int
9877pstrcmp1(const void *a, const void *b)
9878{
9879 return strcmp((char*)a, *(char**)b + 1);
9880}
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009881static struct builtincmd *
9882find_builtin(const char *name)
9883{
9884 struct builtincmd *bp;
9885
9886 bp = bsearch(
Denis Vlasenko80b8b392007-06-25 10:55:35 +00009887 name, builtintab, ARRAY_SIZE(builtintab), sizeof(builtintab[0]),
Denys Vlasenko888527c2016-10-02 16:54:17 +02009888 pstrcmp1
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009889 );
9890 return bp;
9891}
9892
9893/*
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009894 * Execute a simple command.
9895 */
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009896static int
9897isassignment(const char *p)
Paul Foxc3850c82005-07-20 18:23:39 +00009898{
9899 const char *q = endofname(p);
9900 if (p == q)
9901 return 0;
9902 return *q == '=';
9903}
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009904static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009905bltincmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009906{
9907 /* Preserve exitstatus of a previous possible redirection
9908 * as POSIX mandates */
9909 return back_exitstatus;
9910}
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009911static int
Eric Andersenc470f442003-07-28 09:56:35 +00009912evalcommand(union node *cmd, int flags)
9913{
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00009914 static const struct builtincmd null_bltin = {
9915 "\0\0", bltincmd /* why three NULs? */
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009916 };
Denys Vlasenko484fc202017-07-26 19:55:31 +02009917 struct localvar_list *localvar_stop;
Denys Vlasenko1c79aeb2017-07-29 22:51:52 +02009918 struct redirtab *redir_stop;
Eric Andersenc470f442003-07-28 09:56:35 +00009919 struct stackmark smark;
9920 union node *argp;
9921 struct arglist arglist;
9922 struct arglist varlist;
9923 char **argv;
9924 int argc;
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009925 const struct strlist *sp;
Eric Andersenc470f442003-07-28 09:56:35 +00009926 struct cmdentry cmdentry;
9927 struct job *jp;
9928 char *lastarg;
9929 const char *path;
9930 int spclbltin;
Eric Andersenc470f442003-07-28 09:56:35 +00009931 int status;
9932 char **nargv;
Denis Vlasenko34c73c42008-08-16 11:48:02 +00009933 smallint cmd_is_exec;
Eric Andersenc470f442003-07-28 09:56:35 +00009934
Denys Vlasenko675d24a2018-01-27 22:02:05 +01009935 errlinno = lineno = cmd->ncmd.linno;
9936 if (funcline)
9937 lineno -= funcline - 1;
9938
Eric Andersenc470f442003-07-28 09:56:35 +00009939 /* First expand the arguments. */
9940 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
9941 setstackmark(&smark);
Denys Vlasenko484fc202017-07-26 19:55:31 +02009942 localvar_stop = pushlocalvars();
Eric Andersenc470f442003-07-28 09:56:35 +00009943 back_exitstatus = 0;
9944
9945 cmdentry.cmdtype = CMDBUILTIN;
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00009946 cmdentry.u.cmd = &null_bltin;
Eric Andersenc470f442003-07-28 09:56:35 +00009947 varlist.lastp = &varlist.list;
9948 *varlist.lastp = NULL;
9949 arglist.lastp = &arglist.list;
9950 *arglist.lastp = NULL;
9951
9952 argc = 0;
Denis Vlasenkob012b102007-02-19 22:43:01 +00009953 if (cmd->ncmd.args) {
Denys Vlasenkod07a15b2017-07-30 16:51:05 +02009954 struct builtincmd *bcmd;
9955 smallint pseudovarflag;
9956
Paul Foxc3850c82005-07-20 18:23:39 +00009957 bcmd = find_builtin(cmd->ncmd.args->narg.text);
9958 pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd);
Paul Foxc3850c82005-07-20 18:23:39 +00009959
Denys Vlasenkod07a15b2017-07-30 16:51:05 +02009960 for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) {
9961 struct strlist **spp;
Eric Andersenc470f442003-07-28 09:56:35 +00009962
Denys Vlasenkod07a15b2017-07-30 16:51:05 +02009963 spp = arglist.lastp;
9964 if (pseudovarflag && isassignment(argp->narg.text))
9965 expandarg(argp, &arglist, EXP_VARTILDE);
9966 else
9967 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
Paul Foxc3850c82005-07-20 18:23:39 +00009968
Denys Vlasenkod07a15b2017-07-30 16:51:05 +02009969 for (sp = *spp; sp; sp = sp->next)
9970 argc++;
9971 }
Eric Andersenc470f442003-07-28 09:56:35 +00009972 }
9973
Denys Vlasenko65a8b852016-10-26 22:29:11 +02009974 /* Reserve one extra spot at the front for shellexec. */
9975 nargv = stalloc(sizeof(char *) * (argc + 2));
9976 argv = ++nargv;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009977 for (sp = arglist.list; sp; sp = sp->next) {
Eric Andersenc470f442003-07-28 09:56:35 +00009978 TRACE(("evalcommand arg: %s\n", sp->text));
9979 *nargv++ = sp->text;
9980 }
9981 *nargv = NULL;
9982
9983 lastarg = NULL;
Denys Vlasenko675d24a2018-01-27 22:02:05 +01009984 if (iflag && funcline == 0 && argc > 0)
Eric Andersenc470f442003-07-28 09:56:35 +00009985 lastarg = nargv[-1];
9986
9987 expredir(cmd->ncmd.redirect);
Denys Vlasenko1c79aeb2017-07-29 22:51:52 +02009988 redir_stop = pushredir(cmd->ncmd.redirect);
Denys Vlasenkod07a15b2017-07-30 16:51:05 +02009989 preverrout_fd = 2;
Denys Vlasenkof8cdc7a2017-08-04 15:24:49 +02009990 if (BASH_XTRACEFD && xflag) {
9991 /* NB: bash closes fd == $BASH_XTRACEFD when it is changed.
9992 * we do not emulate this. We only use its value.
9993 */
9994 const char *xtracefd = lookupvar("BASH_XTRACEFD");
9995 if (xtracefd && is_number(xtracefd))
9996 preverrout_fd = atoi(xtracefd);
9997
9998 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009999 status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH | REDIR_SAVEFD2);
Eric Andersenc470f442003-07-28 09:56:35 +000010000
Denys Vlasenko8837c5d2010-06-02 12:56:18 +020010001 path = vpath.var_text;
Eric Andersenc470f442003-07-28 09:56:35 +000010002 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
10003 struct strlist **spp;
10004 char *p;
10005
10006 spp = varlist.lastp;
10007 expandarg(argp, &varlist, EXP_VARTILDE);
10008
Denys Vlasenko981a0562017-07-26 19:53:11 +020010009 mklocal((*spp)->text);
10010
Eric Andersenc470f442003-07-28 09:56:35 +000010011 /*
10012 * Modify the command lookup path, if a PATH= assignment
10013 * is present
10014 */
10015 p = (*spp)->text;
Denys Vlasenko8837c5d2010-06-02 12:56:18 +020010016 if (varcmp(p, path) == 0)
Eric Andersenc470f442003-07-28 09:56:35 +000010017 path = p;
10018 }
10019
10020 /* Print the command if xflag is set. */
10021 if (xflag) {
Denys Vlasenko42ba7572017-07-21 13:20:14 +020010022 const char *pfx = "";
Eric Andersenc470f442003-07-28 09:56:35 +000010023
Denys Vlasenko46999802017-07-29 21:12:29 +020010024 fdprintf(preverrout_fd, "%s", expandstr(ps4val(), DQSYNTAX));
Denys Vlasenko42ba7572017-07-21 13:20:14 +020010025
Glenn L McGrath7b8765c2003-08-29 07:29:30 +000010026 sp = varlist.list;
Denys Vlasenko42ba7572017-07-21 13:20:14 +020010027 while (sp) {
10028 char *varval = sp->text;
10029 char *eq = strchrnul(varval, '=');
10030 if (*eq)
10031 eq++;
10032 fdprintf(preverrout_fd, "%s%.*s%s",
10033 pfx,
10034 (int)(eq - varval), varval,
10035 maybe_single_quote(eq)
10036 );
10037 sp = sp->next;
10038 pfx = " ";
10039 }
10040
10041 sp = arglist.list;
10042 while (sp) {
10043 fdprintf(preverrout_fd, "%s%s",
10044 pfx,
10045 /* always quote if matches reserved word: */
10046 findkwd(sp->text)
10047 ? single_quote(sp->text)
10048 : maybe_single_quote(sp->text)
10049 );
10050 sp = sp->next;
10051 pfx = " ";
Glenn L McGrath7b8765c2003-08-29 07:29:30 +000010052 }
Denis Vlasenko0e6f6612008-02-15 15:02:15 +000010053 safe_write(preverrout_fd, "\n", 1);
Eric Andersenc470f442003-07-28 09:56:35 +000010054 }
10055
10056 cmd_is_exec = 0;
10057 spclbltin = -1;
10058
10059 /* Now locate the command. */
10060 if (argc) {
Eric Andersenc470f442003-07-28 09:56:35 +000010061 int cmd_flag = DO_ERR;
Denys Vlasenko0b4980c2012-09-25 12:49:29 +020010062#if ENABLE_ASH_CMDCMD
10063 const char *oldpath = path + 5;
10064#endif
Eric Andersenc470f442003-07-28 09:56:35 +000010065 path += 5;
Eric Andersenc470f442003-07-28 09:56:35 +000010066 for (;;) {
10067 find_command(argv[0], &cmdentry, cmd_flag, path);
10068 if (cmdentry.cmdtype == CMDUNKNOWN) {
Denys Vlasenko8131eea2009-11-02 14:19:51 +010010069 flush_stdout_stderr();
Denis Vlasenko6514c5e2008-07-24 13:41:37 +000010070 status = 127;
Eric Andersenc470f442003-07-28 09:56:35 +000010071 goto bail;
10072 }
10073
10074 /* implement bltin and command here */
10075 if (cmdentry.cmdtype != CMDBUILTIN)
10076 break;
10077 if (spclbltin < 0)
10078 spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd);
10079 if (cmdentry.u.cmd == EXECCMD)
Denis Vlasenko34c73c42008-08-16 11:48:02 +000010080 cmd_is_exec = 1;
Denis Vlasenko131ae172007-02-18 13:00:19 +000010081#if ENABLE_ASH_CMDCMD
Eric Andersenc470f442003-07-28 09:56:35 +000010082 if (cmdentry.u.cmd == COMMANDCMD) {
Eric Andersenc470f442003-07-28 09:56:35 +000010083 path = oldpath;
10084 nargv = parse_command_args(argv, &path);
10085 if (!nargv)
10086 break;
Denys Vlasenkocac4d002016-10-01 03:02:25 +020010087 /* It's "command [-p] PROG ARGS" (that is, no -Vv).
10088 * nargv => "PROG". path is updated if -p.
10089 */
Eric Andersenc470f442003-07-28 09:56:35 +000010090 argc -= nargv - argv;
10091 argv = nargv;
10092 cmd_flag |= DO_NOFUNC;
10093 } else
10094#endif
10095 break;
10096 }
10097 }
10098
10099 if (status) {
Ron Yorstonea7d2f62017-01-03 11:18:23 +010010100 bail:
10101 exitstatus = status;
10102
Eric Andersenc470f442003-07-28 09:56:35 +000010103 /* We have a redirection error. */
10104 if (spclbltin > 0)
Denis Vlasenkob012b102007-02-19 22:43:01 +000010105 raise_exception(EXERROR);
Ron Yorstonea7d2f62017-01-03 11:18:23 +010010106
Eric Andersenc470f442003-07-28 09:56:35 +000010107 goto out;
10108 }
10109
10110 /* Execute the command. */
10111 switch (cmdentry.cmdtype) {
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +020010112 default: {
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +000010113
Denys Vlasenko1750d3a2018-01-15 00:41:04 +010010114#if ENABLE_FEATURE_SH_STANDALONE \
10115 && ENABLE_FEATURE_SH_NOFORK \
10116 && NUM_APPLETS > 1
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +020010117/* (1) BUG: if variables are set, we need to fork, or save/restore them
10118 * around run_nofork_applet() call.
10119 * (2) Should this check also be done in forkshell()?
10120 * (perhaps it should, so that "VAR=VAL nofork" at least avoids exec...)
10121 */
Denis Vlasenko7465dbc2008-04-13 02:25:53 +000010122 /* find_command() encodes applet_no as (-2 - applet_no) */
10123 int applet_no = (- cmdentry.u.index - 2);
Denis Vlasenko9bc80d72008-04-12 20:07:53 +000010124 if (applet_no >= 0 && APPLET_IS_NOFORK(applet_no)) {
Denys Vlasenkoa5060b82017-11-03 14:16:25 +010010125 char **sv_environ;
10126
10127 INT_OFF;
10128 sv_environ = environ;
10129 environ = listvars(VEXPORT, VUNSET, varlist.list, /*end:*/ NULL);
Denys Vlasenkod329e342017-08-04 14:50:03 +020010130 /*
10131 * Run <applet>_main().
10132 * Signals (^C) can't interrupt here.
10133 * Otherwise we can mangle stdio or malloc internal state.
10134 * This makes applets which can run for a long time
10135 * and/or wait for user input ineligible for NOFORK:
10136 * for example, "yes" or "rm" (rm -i waits for input).
10137 */
Ron Yorston5ccb0e92016-10-20 12:24:02 +010010138 status = run_nofork_applet(applet_no, argv);
Denys Vlasenkoa5060b82017-11-03 14:16:25 +010010139 environ = sv_environ;
Denys Vlasenkod329e342017-08-04 14:50:03 +020010140 /*
10141 * Try enabling NOFORK for "yes" applet.
10142 * ^C _will_ stop it (write returns EINTR),
10143 * but this causes stdout FILE to be stuck
10144 * and needing clearerr(). What if other applets
10145 * also can get EINTRs? Do we need to switch
10146 * our signals to SA_RESTART?
10147 */
10148 /*clearerr(stdout);*/
10149 INT_ON;
Denis Vlasenko9bc80d72008-04-12 20:07:53 +000010150 break;
10151 }
Denis Vlasenko9bc80d72008-04-12 20:07:53 +000010152#endif
Denys Vlasenkocfd392b2017-08-03 19:56:29 +020010153 /* Can we avoid forking? For example, very last command
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +020010154 * in a script or a subshell does not need forking,
10155 * we can just exec it.
10156 */
Denys Vlasenko238bf182010-05-18 15:49:07 +020010157 if (!(flags & EV_EXIT) || may_have_traps) {
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +020010158 /* No, forking off a child is necessary */
Denis Vlasenkob012b102007-02-19 22:43:01 +000010159 INT_OFF;
Denys Vlasenko098b7132017-01-11 19:59:03 +010010160 get_tty_state();
Denis Vlasenko68404f12008-03-17 09:00:54 +000010161 jp = makejob(/*cmd,*/ 1);
Eric Andersenc470f442003-07-28 09:56:35 +000010162 if (forkshell(jp, cmd, FORK_FG) != 0) {
Denys Vlasenko238bf182010-05-18 15:49:07 +020010163 /* parent */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020010164 status = waitforjob(jp);
Denis Vlasenkob012b102007-02-19 22:43:01 +000010165 INT_ON;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020010166 TRACE(("forked child exited with %d\n", status));
Eric Andersenc470f442003-07-28 09:56:35 +000010167 break;
10168 }
Denys Vlasenko238bf182010-05-18 15:49:07 +020010169 /* child */
Denis Vlasenkob012b102007-02-19 22:43:01 +000010170 FORCE_INT_ON;
Denys Vlasenkoc7f95d22010-05-18 15:52:23 +020010171 /* fall through to exec'ing external program */
Eric Andersenc470f442003-07-28 09:56:35 +000010172 }
10173 listsetvar(varlist.list, VEXPORT|VSTACK);
Denys Vlasenkoe139ae32017-04-12 21:02:33 +020010174 shellexec(argv[0], argv, path, cmdentry.u.index);
Eric Andersenc470f442003-07-28 09:56:35 +000010175 /* NOTREACHED */
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +020010176 } /* default */
Eric Andersenc470f442003-07-28 09:56:35 +000010177 case CMDBUILTIN:
Denys Vlasenko85241c72017-07-26 20:00:08 +020010178 if (spclbltin > 0 || argc == 0) {
10179 poplocalvars(1);
10180 if (cmd_is_exec && argc > 1)
10181 listsetvar(varlist.list, VEXPORT);
10182 }
Denys Vlasenko981a0562017-07-26 19:53:11 +020010183
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +000010184 /* Tight loop with builtins only:
10185 * "while kill -0 $child; do true; done"
10186 * will never exit even if $child died, unless we do this
10187 * to reap the zombie and make kill detect that it's gone: */
10188 dowait(DOWAIT_NONBLOCK, NULL);
10189
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020010190 if (evalbltin(cmdentry.u.cmd, argc, argv, flags)) {
Denys Vlasenkoc0663c72016-10-27 21:09:01 +020010191 if (exception_type == EXERROR && spclbltin <= 0) {
10192 FORCE_INT_ON;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020010193 goto readstatus;
Eric Andersenc470f442003-07-28 09:56:35 +000010194 }
Denys Vlasenkoc0663c72016-10-27 21:09:01 +020010195 raise:
10196 longjmp(exception_handler->loc, 1);
Eric Andersenc470f442003-07-28 09:56:35 +000010197 }
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020010198 goto readstatus;
Eric Andersenc470f442003-07-28 09:56:35 +000010199
10200 case CMDFUNCTION:
Denys Vlasenko981a0562017-07-26 19:53:11 +020010201 poplocalvars(1);
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +000010202 /* See above for the rationale */
10203 dowait(DOWAIT_NONBLOCK, NULL);
Eric Andersenc470f442003-07-28 09:56:35 +000010204 if (evalfun(cmdentry.u.func, argc, argv, flags))
10205 goto raise;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020010206 readstatus:
10207 status = exitstatus;
Eric Andersenc470f442003-07-28 09:56:35 +000010208 break;
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +020010209 } /* switch */
Eric Andersenc470f442003-07-28 09:56:35 +000010210
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010211 out:
Denys Vlasenkoeaf94362016-10-25 21:46:03 +020010212 if (cmd->ncmd.redirect)
Denys Vlasenko035486c2017-07-31 04:09:19 +020010213 popredir(/*drop:*/ cmd_is_exec);
Denys Vlasenko1c79aeb2017-07-29 22:51:52 +020010214 unwindredir(redir_stop);
Denys Vlasenko484fc202017-07-26 19:55:31 +020010215 unwindlocalvars(localvar_stop);
Denis Vlasenko6514c5e2008-07-24 13:41:37 +000010216 if (lastarg) {
Eric Andersenc470f442003-07-28 09:56:35 +000010217 /* dsl: I think this is intended to be used to support
10218 * '_' in 'vi' command mode during line editing...
10219 * However I implemented that within libedit itself.
10220 */
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020010221 setvar0("_", lastarg);
Denis Vlasenko6514c5e2008-07-24 13:41:37 +000010222 }
Eric Andersenc470f442003-07-28 09:56:35 +000010223 popstackmark(&smark);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020010224
10225 return status;
Eric Andersenc470f442003-07-28 09:56:35 +000010226}
10227
10228static int
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020010229evalbltin(const struct builtincmd *cmd, int argc, char **argv, int flags)
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010230{
Eric Andersenc470f442003-07-28 09:56:35 +000010231 char *volatile savecmdname;
10232 struct jmploc *volatile savehandler;
10233 struct jmploc jmploc;
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020010234 int status;
Eric Andersenc470f442003-07-28 09:56:35 +000010235 int i;
10236
10237 savecmdname = commandname;
Denys Vlasenkoa2d121c2016-09-30 11:30:11 +020010238 savehandler = exception_handler;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010239 i = setjmp(jmploc.loc);
10240 if (i)
Eric Andersenc470f442003-07-28 09:56:35 +000010241 goto cmddone;
Denis Vlasenko2da584f2007-02-19 22:44:05 +000010242 exception_handler = &jmploc;
Eric Andersenc470f442003-07-28 09:56:35 +000010243 commandname = argv[0];
10244 argptr = argv + 1;
10245 optptr = NULL; /* initialize nextopt */
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020010246 if (cmd == EVALCMD)
10247 status = evalcmd(argc, argv, flags);
10248 else
10249 status = (*cmd->builtin)(argc, argv);
Denis Vlasenkob012b102007-02-19 22:43:01 +000010250 flush_stdout_stderr();
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020010251 status |= ferror(stdout);
10252 exitstatus = status;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010253 cmddone:
Rob Landleyf296f0b2006-07-06 01:09:21 +000010254 clearerr(stdout);
Eric Andersenc470f442003-07-28 09:56:35 +000010255 commandname = savecmdname;
Denis Vlasenko2da584f2007-02-19 22:44:05 +000010256 exception_handler = savehandler;
Eric Andersenc470f442003-07-28 09:56:35 +000010257
10258 return i;
10259}
10260
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010261static int
10262goodname(const char *p)
Glenn L McGrath16e45d72004-02-04 08:24:39 +000010263{
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +020010264 return endofname(p)[0] == '\0';
Glenn L McGrath16e45d72004-02-04 08:24:39 +000010265}
10266
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010267
Glenn L McGrath50812ff2002-08-23 13:14:48 +000010268/*
10269 * Search for a command. This is called before we fork so that the
10270 * location of the command will be available in the parent as well as
Glenn L McGrath16e45d72004-02-04 08:24:39 +000010271 * the child. The check for "goodname" is an overly conservative
10272 * check that the name will not be subject to expansion.
Glenn L McGrath50812ff2002-08-23 13:14:48 +000010273 */
Eric Andersenc470f442003-07-28 09:56:35 +000010274static void
10275prehash(union node *n)
Glenn L McGrath50812ff2002-08-23 13:14:48 +000010276{
10277 struct cmdentry entry;
10278
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000010279 if (n->type == NCMD && n->ncmd.args && goodname(n->ncmd.args->narg.text))
10280 find_command(n->ncmd.args->narg.text, &entry, 0, pathval());
Glenn L McGrath50812ff2002-08-23 13:14:48 +000010281}
10282
Eric Andersencb57d552001-06-28 07:25:16 +000010283
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000010284/* ============ Builtin commands
10285 *
10286 * Builtin commands whose functions are closely tied to evaluation
10287 * are implemented here.
Eric Andersencb57d552001-06-28 07:25:16 +000010288 */
10289
10290/*
Eric Andersencb57d552001-06-28 07:25:16 +000010291 * Handle break and continue commands. Break, continue, and return are
10292 * all handled by setting the evalskip flag. The evaluation routines
10293 * above all check this flag, and if it is set they start skipping
10294 * commands rather than executing them. The variable skipcount is
10295 * the number of loops to break/continue, or the number of function
10296 * levels to return. (The latter is always 1.) It should probably
10297 * be an error to break out of more loops than exist, but it isn't
10298 * in the standard shell so we don't make it one here.
10299 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010300static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010301breakcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000010302{
Denis Vlasenko68404f12008-03-17 09:00:54 +000010303 int n = argv[1] ? number(argv[1]) : 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010304
Aaron Lehmann2aef3a62001-12-31 06:03:12 +000010305 if (n <= 0)
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +020010306 ash_msg_and_raise_error(msg_illnum, argv[1]);
Eric Andersencb57d552001-06-28 07:25:16 +000010307 if (n > loopnest)
10308 n = loopnest;
10309 if (n > 0) {
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000010310 evalskip = (**argv == 'c') ? SKIPCONT : SKIPBREAK;
Eric Andersencb57d552001-06-28 07:25:16 +000010311 skipcount = n;
10312 }
10313 return 0;
10314}
10315
Eric Andersenc470f442003-07-28 09:56:35 +000010316
Denys Vlasenko70392332016-10-27 02:31:55 +020010317/*
Eric Andersen90898442003-08-06 11:20:52 +000010318 * This implements the input routines used by the parser.
Eric Andersencb57d552001-06-28 07:25:16 +000010319 */
Denis Vlasenko99eb8502007-02-23 21:09:49 +000010320
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010321enum {
10322 INPUT_PUSH_FILE = 1,
10323 INPUT_NOFILE_OK = 2,
10324};
Eric Andersencb57d552001-06-28 07:25:16 +000010325
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010326static smallint checkkwd;
Denis Vlasenko99eb8502007-02-23 21:09:49 +000010327/* values of checkkwd variable */
10328#define CHKALIAS 0x1
10329#define CHKKWD 0x2
10330#define CHKNL 0x4
Denys Vlasenkoa7328982017-07-29 19:57:28 +020010331#define CHKEOFMARK 0x8
Denis Vlasenko99eb8502007-02-23 21:09:49 +000010332
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010333/*
10334 * Push a string back onto the input at this current parsefile level.
10335 * We handle aliases this way.
10336 */
10337#if !ENABLE_ASH_ALIAS
10338#define pushstring(s, ap) pushstring(s)
10339#endif
10340static void
10341pushstring(char *s, struct alias *ap)
10342{
10343 struct strpush *sp;
10344 int len;
10345
10346 len = strlen(s);
10347 INT_OFF;
10348 if (g_parsefile->strpush) {
10349 sp = ckzalloc(sizeof(*sp));
10350 sp->prev = g_parsefile->strpush;
10351 } else {
10352 sp = &(g_parsefile->basestrpush);
10353 }
10354 g_parsefile->strpush = sp;
10355 sp->prev_string = g_parsefile->next_to_pgetc;
10356 sp->prev_left_in_line = g_parsefile->left_in_line;
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010357 sp->unget = g_parsefile->unget;
10358 memcpy(sp->lastc, g_parsefile->lastc, sizeof(sp->lastc));
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010359#if ENABLE_ASH_ALIAS
10360 sp->ap = ap;
10361 if (ap) {
10362 ap->flag |= ALIASINUSE;
10363 sp->string = s;
10364 }
10365#endif
10366 g_parsefile->next_to_pgetc = s;
10367 g_parsefile->left_in_line = len;
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010368 g_parsefile->unget = 0;
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010369 INT_ON;
10370}
10371
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010372static void
10373popstring(void)
Eric Andersenc470f442003-07-28 09:56:35 +000010374{
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010375 struct strpush *sp = g_parsefile->strpush;
Eric Andersenc470f442003-07-28 09:56:35 +000010376
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010377 INT_OFF;
Denis Vlasenko131ae172007-02-18 13:00:19 +000010378#if ENABLE_ASH_ALIAS
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010379 if (sp->ap) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010380 if (g_parsefile->next_to_pgetc[-1] == ' '
10381 || g_parsefile->next_to_pgetc[-1] == '\t'
10382 ) {
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010383 checkkwd |= CHKALIAS;
Glenn L McGrath28939ad2004-07-21 10:20:19 +000010384 }
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010385 if (sp->string != sp->ap->val) {
10386 free(sp->string);
10387 }
10388 sp->ap->flag &= ~ALIASINUSE;
10389 if (sp->ap->flag & ALIASDEAD) {
10390 unalias(sp->ap->name);
10391 }
Glenn L McGrath28939ad2004-07-21 10:20:19 +000010392 }
Denis Vlasenko8e1c7152007-01-22 07:21:38 +000010393#endif
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010394 g_parsefile->next_to_pgetc = sp->prev_string;
10395 g_parsefile->left_in_line = sp->prev_left_in_line;
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010396 g_parsefile->unget = sp->unget;
10397 memcpy(g_parsefile->lastc, sp->lastc, sizeof(sp->lastc));
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010398 g_parsefile->strpush = sp->prev;
10399 if (sp != &(g_parsefile->basestrpush))
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010400 free(sp);
10401 INT_ON;
10402}
Denis Vlasenko8e1c7152007-01-22 07:21:38 +000010403
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010404static int
10405preadfd(void)
Eric Andersencb57d552001-06-28 07:25:16 +000010406{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010407 int nr;
Denis Vlasenko6a0ad252008-07-25 13:34:05 +000010408 char *buf = g_parsefile->buf;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010409
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010410 g_parsefile->next_to_pgetc = buf;
Denis Vlasenko38f63192007-01-22 09:03:07 +000010411#if ENABLE_FEATURE_EDITING
Denis Vlasenko85c24712008-03-17 09:04:04 +000010412 retry:
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010413 if (!iflag || g_parsefile->pf_fd != STDIN_FILENO)
Ron Yorston61d6ae22015-04-19 10:50:25 +010010414 nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1);
Eric Andersenc470f442003-07-28 09:56:35 +000010415 else {
Denys Vlasenko66c5b122011-02-08 05:07:02 +010010416# if ENABLE_ASH_IDLE_TIMEOUT
Denys Vlasenko84ea60e2017-08-02 17:27:28 +020010417 int timeout = -1;
Denys Vlasenko66c5b122011-02-08 05:07:02 +010010418 if (iflag) {
10419 const char *tmout_var = lookupvar("TMOUT");
10420 if (tmout_var) {
10421 timeout = atoi(tmout_var) * 1000;
10422 if (timeout <= 0)
10423 timeout = -1;
10424 }
10425 }
Denys Vlasenko84ea60e2017-08-02 17:27:28 +020010426 line_input_state->timeout = timeout;
Denys Vlasenko66c5b122011-02-08 05:07:02 +010010427# endif
Denys Vlasenko8c52f802011-02-04 17:36:21 +010010428# if ENABLE_FEATURE_TAB_COMPLETION
Denis Vlasenko8e1c7152007-01-22 07:21:38 +000010429 line_input_state->path_lookup = pathval();
Denys Vlasenko8c52f802011-02-04 17:36:21 +010010430# endif
Denys Vlasenkoe9ab07c2014-08-13 18:00:08 +020010431 reinit_unicode_for_ash();
Denys Vlasenko84ea60e2017-08-02 17:27:28 +020010432 nr = read_line_input(line_input_state, cmdedit_prompt, buf, IBUFSIZ);
Denis Vlasenko8e1c7152007-01-22 07:21:38 +000010433 if (nr == 0) {
Denys Vlasenko4b89d512016-11-25 03:41:03 +010010434 /* ^C pressed, "convert" to SIGINT */
10435 write(STDOUT_FILENO, "^C", 2);
Denis Vlasenko8e1c7152007-01-22 07:21:38 +000010436 if (trap[SIGINT]) {
Glenn L McGrath16e45d72004-02-04 08:24:39 +000010437 buf[0] = '\n';
Denis Vlasenko8e1c7152007-01-22 07:21:38 +000010438 buf[1] = '\0';
Glenn L McGrath16e45d72004-02-04 08:24:39 +000010439 raise(SIGINT);
10440 return 1;
10441 }
Denys Vlasenko8660aeb2016-11-24 17:44:02 +010010442 exitstatus = 128 + SIGINT;
Denys Vlasenko4b89d512016-11-25 03:41:03 +010010443 bb_putchar('\n');
Eric Andersenc470f442003-07-28 09:56:35 +000010444 goto retry;
10445 }
Denys Vlasenko66c5b122011-02-08 05:07:02 +010010446 if (nr < 0) {
10447 if (errno == 0) {
10448 /* Ctrl+D pressed */
10449 nr = 0;
10450 }
10451# if ENABLE_ASH_IDLE_TIMEOUT
10452 else if (errno == EAGAIN && timeout > 0) {
Denys Vlasenkod60752f2015-10-07 22:42:45 +020010453 puts("\007timed out waiting for input: auto-logout");
Denys Vlasenko66c5b122011-02-08 05:07:02 +010010454 exitshell();
10455 }
10456# endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010457 }
Eric Andersencb57d552001-06-28 07:25:16 +000010458 }
10459#else
Ron Yorston61d6ae22015-04-19 10:50:25 +010010460 nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1);
Eric Andersencb57d552001-06-28 07:25:16 +000010461#endif
10462
Denys Vlasenko80c5b682011-05-08 21:21:10 +020010463#if 0 /* disabled: nonblock_immune_read() handles this problem */
Eric Andersencb57d552001-06-28 07:25:16 +000010464 if (nr < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +000010465 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
Denis Vlasenkod37f2222007-08-19 13:42:08 +000010466 int flags = fcntl(0, F_GETFL);
Denis Vlasenko9cb220b2007-12-09 10:03:28 +000010467 if (flags >= 0 && (flags & O_NONBLOCK)) {
10468 flags &= ~O_NONBLOCK;
Eric Andersencb57d552001-06-28 07:25:16 +000010469 if (fcntl(0, F_SETFL, flags) >= 0) {
10470 out2str("sh: turning off NDELAY mode\n");
10471 goto retry;
10472 }
10473 }
10474 }
10475 }
Denis Vlasenkoe376d452008-02-20 22:23:24 +000010476#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010477 return nr;
10478}
10479
10480/*
10481 * Refill the input buffer and return the next input character:
10482 *
10483 * 1) If a string was pushed back on the input, pop it;
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010484 * 2) If an EOF was pushed back (g_parsefile->left_in_line < -BIGNUM)
10485 * or we are reading from a string so we can't refill the buffer,
10486 * return EOF.
Denys Vlasenko883cea42009-07-11 15:31:59 +020010487 * 3) If there is more stuff in this buffer, use it else call read to fill it.
Eric Andersencb57d552001-06-28 07:25:16 +000010488 * 4) Process input up to the next newline, deleting nul characters.
10489 */
Denis Vlasenko727752d2008-11-28 03:41:47 +000010490//#define pgetc_debug(...) bb_error_msg(__VA_ARGS__)
10491#define pgetc_debug(...) ((void)0)
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010492static int pgetc(void);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010493static int
Eric Andersenc470f442003-07-28 09:56:35 +000010494preadbuffer(void)
Eric Andersencb57d552001-06-28 07:25:16 +000010495{
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010496 char *q;
Eric Andersencb57d552001-06-28 07:25:16 +000010497 int more;
Eric Andersencb57d552001-06-28 07:25:16 +000010498
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010499 if (g_parsefile->strpush) {
Denis Vlasenko131ae172007-02-18 13:00:19 +000010500#if ENABLE_ASH_ALIAS
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010501 if (g_parsefile->left_in_line == -1
10502 && g_parsefile->strpush->ap
10503 && g_parsefile->next_to_pgetc[-1] != ' '
10504 && g_parsefile->next_to_pgetc[-1] != '\t'
Denis Vlasenko16898402008-11-25 01:34:52 +000010505 ) {
Denis Vlasenko727752d2008-11-28 03:41:47 +000010506 pgetc_debug("preadbuffer PEOA");
Eric Andersencb57d552001-06-28 07:25:16 +000010507 return PEOA;
10508 }
Eric Andersen2870d962001-07-02 17:27:21 +000010509#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010510 popstring();
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010511 return pgetc();
Eric Andersencb57d552001-06-28 07:25:16 +000010512 }
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010513 /* on both branches above g_parsefile->left_in_line < 0.
Denis Vlasenko727752d2008-11-28 03:41:47 +000010514 * "pgetc" needs refilling.
10515 */
10516
Denis Vlasenkoe27dafd2008-11-28 04:01:03 +000010517 /* -90 is our -BIGNUM. Below we use -99 to mark "EOF on read",
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010518 * pungetc() may increment it a few times.
Denis Vlasenkoe27dafd2008-11-28 04:01:03 +000010519 * Assuming it won't increment it to less than -90.
Denis Vlasenko727752d2008-11-28 03:41:47 +000010520 */
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010521 if (g_parsefile->left_in_line < -90 || g_parsefile->buf == NULL) {
Denis Vlasenko727752d2008-11-28 03:41:47 +000010522 pgetc_debug("preadbuffer PEOF1");
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010523 /* even in failure keep left_in_line and next_to_pgetc
10524 * in lock step, for correct multi-layer pungetc.
10525 * left_in_line was decremented before preadbuffer(),
10526 * must inc next_to_pgetc: */
10527 g_parsefile->next_to_pgetc++;
Eric Andersencb57d552001-06-28 07:25:16 +000010528 return PEOF;
Denis Vlasenko727752d2008-11-28 03:41:47 +000010529 }
Eric Andersencb57d552001-06-28 07:25:16 +000010530
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010531 more = g_parsefile->left_in_buffer;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010532 if (more <= 0) {
Denis Vlasenko727752d2008-11-28 03:41:47 +000010533 flush_stdout_stderr();
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010534 again:
10535 more = preadfd();
10536 if (more <= 0) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010537 /* don't try reading again */
10538 g_parsefile->left_in_line = -99;
Denis Vlasenko727752d2008-11-28 03:41:47 +000010539 pgetc_debug("preadbuffer PEOF2");
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010540 g_parsefile->next_to_pgetc++;
Eric Andersencb57d552001-06-28 07:25:16 +000010541 return PEOF;
10542 }
10543 }
10544
Denis Vlasenko727752d2008-11-28 03:41:47 +000010545 /* Find out where's the end of line.
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010546 * Set g_parsefile->left_in_line
10547 * and g_parsefile->left_in_buffer acordingly.
Denis Vlasenko727752d2008-11-28 03:41:47 +000010548 * NUL chars are deleted.
10549 */
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010550 q = g_parsefile->next_to_pgetc;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010551 for (;;) {
Denis Vlasenko727752d2008-11-28 03:41:47 +000010552 char c;
Eric Andersencb57d552001-06-28 07:25:16 +000010553
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010554 more--;
Eric Andersenc470f442003-07-28 09:56:35 +000010555
Denis Vlasenko727752d2008-11-28 03:41:47 +000010556 c = *q;
10557 if (c == '\0') {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010558 memmove(q, q + 1, more);
Denis Vlasenko727752d2008-11-28 03:41:47 +000010559 } else {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010560 q++;
10561 if (c == '\n') {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010562 g_parsefile->left_in_line = q - g_parsefile->next_to_pgetc - 1;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010563 break;
10564 }
Eric Andersencb57d552001-06-28 07:25:16 +000010565 }
10566
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010567 if (more <= 0) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010568 g_parsefile->left_in_line = q - g_parsefile->next_to_pgetc - 1;
10569 if (g_parsefile->left_in_line < 0)
Eric Andersencb57d552001-06-28 07:25:16 +000010570 goto again;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010571 break;
Eric Andersencb57d552001-06-28 07:25:16 +000010572 }
10573 }
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010574 g_parsefile->left_in_buffer = more;
Eric Andersencb57d552001-06-28 07:25:16 +000010575
Eric Andersencb57d552001-06-28 07:25:16 +000010576 if (vflag) {
Denis Vlasenko727752d2008-11-28 03:41:47 +000010577 char save = *q;
10578 *q = '\0';
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010579 out2str(g_parsefile->next_to_pgetc);
Denis Vlasenko727752d2008-11-28 03:41:47 +000010580 *q = save;
Eric Andersencb57d552001-06-28 07:25:16 +000010581 }
10582
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010583 pgetc_debug("preadbuffer at %d:%p'%s'",
10584 g_parsefile->left_in_line,
10585 g_parsefile->next_to_pgetc,
10586 g_parsefile->next_to_pgetc);
Denys Vlasenkocd716832009-11-28 22:14:02 +010010587 return (unsigned char)*g_parsefile->next_to_pgetc++;
Eric Andersencb57d552001-06-28 07:25:16 +000010588}
10589
Denys Vlasenkoce332a22016-10-02 23:47:34 +020010590static void
10591nlprompt(void)
10592{
10593 g_parsefile->linno++;
10594 setprompt_if(doprompt, 2);
10595}
10596static void
10597nlnoprompt(void)
10598{
10599 g_parsefile->linno++;
10600 needprompt = doprompt;
10601}
10602
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010603static int
10604pgetc(void)
10605{
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010606 int c;
10607
10608 pgetc_debug("pgetc at %d:%p'%s'",
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010609 g_parsefile->left_in_line,
10610 g_parsefile->next_to_pgetc,
10611 g_parsefile->next_to_pgetc);
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010612 if (g_parsefile->unget)
10613 return g_parsefile->lastc[--g_parsefile->unget];
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010614
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010615 if (--g_parsefile->left_in_line >= 0)
Denys Vlasenko2fe66b12016-12-12 17:39:12 +010010616 c = (unsigned char)*g_parsefile->next_to_pgetc++;
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010617 else
10618 c = preadbuffer();
10619
10620 g_parsefile->lastc[1] = g_parsefile->lastc[0];
10621 g_parsefile->lastc[0] = c;
10622
10623 return c;
10624}
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010625
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010626#if ENABLE_ASH_ALIAS
10627static int
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010010628pgetc_without_PEOA(void)
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010629{
10630 int c;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010631 do {
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010632 pgetc_debug("pgetc at %d:%p'%s'",
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010633 g_parsefile->left_in_line,
10634 g_parsefile->next_to_pgetc,
10635 g_parsefile->next_to_pgetc);
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010636 c = pgetc();
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010637 } while (c == PEOA);
10638 return c;
10639}
10640#else
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010010641# define pgetc_without_PEOA() pgetc()
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010642#endif
10643
10644/*
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010645 * Undo a call to pgetc. Only two characters may be pushed back.
Eric Andersenc470f442003-07-28 09:56:35 +000010646 * PEOF may be pushed back.
10647 */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010648static void
Eric Andersenc470f442003-07-28 09:56:35 +000010649pungetc(void)
10650{
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010651 g_parsefile->unget++;
Eric Andersencb57d552001-06-28 07:25:16 +000010652}
10653
Denys Vlasenko73c3e072016-09-29 17:17:04 +020010654/* This one eats backslash+newline */
10655static int
10656pgetc_eatbnl(void)
10657{
10658 int c;
10659
10660 while ((c = pgetc()) == '\\') {
10661 if (pgetc() != '\n') {
10662 pungetc();
10663 break;
10664 }
10665
Denys Vlasenkoce332a22016-10-02 23:47:34 +020010666 nlprompt();
Denys Vlasenko73c3e072016-09-29 17:17:04 +020010667 }
10668
10669 return c;
10670}
10671
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010672/*
10673 * To handle the "." command, a stack of input files is used. Pushfile
10674 * adds a new entry to the stack and popfile restores the previous level.
10675 */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010676static void
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010677pushfile(void)
Eric Andersenc470f442003-07-28 09:56:35 +000010678{
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010679 struct parsefile *pf;
10680
Denis Vlasenko597906c2008-02-20 16:38:54 +000010681 pf = ckzalloc(sizeof(*pf));
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010682 pf->prev = g_parsefile;
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010683 pf->pf_fd = -1;
Denis Vlasenko597906c2008-02-20 16:38:54 +000010684 /*pf->strpush = NULL; - ckzalloc did it */
10685 /*pf->basestrpush.prev = NULL;*/
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010686 /*pf->unget = 0;*/
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010687 g_parsefile = pf;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010688}
10689
10690static void
10691popfile(void)
10692{
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010693 struct parsefile *pf = g_parsefile;
Eric Andersenc470f442003-07-28 09:56:35 +000010694
Denys Vlasenko493b9ca2016-10-30 18:27:14 +010010695 if (pf == &basepf)
10696 return;
10697
Denis Vlasenkob012b102007-02-19 22:43:01 +000010698 INT_OFF;
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010699 if (pf->pf_fd >= 0)
10700 close(pf->pf_fd);
Denis Vlasenko60818682007-09-28 22:07:23 +000010701 free(pf->buf);
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010702 while (pf->strpush)
10703 popstring();
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010704 g_parsefile = pf->prev;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010705 free(pf);
Denis Vlasenkob012b102007-02-19 22:43:01 +000010706 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +000010707}
10708
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010709/*
10710 * Return to top level.
10711 */
10712static void
10713popallfiles(void)
10714{
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010715 while (g_parsefile != &basepf)
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010716 popfile();
10717}
10718
10719/*
10720 * Close the file(s) that the shell is reading commands from. Called
10721 * after a fork is done.
10722 */
10723static void
10724closescript(void)
10725{
10726 popallfiles();
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010727 if (g_parsefile->pf_fd > 0) {
10728 close(g_parsefile->pf_fd);
10729 g_parsefile->pf_fd = 0;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010730 }
10731}
10732
10733/*
10734 * Like setinputfile, but takes an open file descriptor. Call this with
10735 * interrupts off.
10736 */
10737static void
10738setinputfd(int fd, int push)
10739{
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010740 if (push) {
10741 pushfile();
Denis Vlasenko727752d2008-11-28 03:41:47 +000010742 g_parsefile->buf = NULL;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010743 }
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010744 g_parsefile->pf_fd = fd;
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010745 if (g_parsefile->buf == NULL)
10746 g_parsefile->buf = ckmalloc(IBUFSIZ);
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010747 g_parsefile->left_in_buffer = 0;
10748 g_parsefile->left_in_line = 0;
10749 g_parsefile->linno = 1;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010750}
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010751
Eric Andersenc470f442003-07-28 09:56:35 +000010752/*
10753 * Set the input to take input from a file. If push is set, push the
10754 * old input onto the stack first.
10755 */
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010756static int
10757setinputfile(const char *fname, int flags)
Eric Andersenc470f442003-07-28 09:56:35 +000010758{
10759 int fd;
Eric Andersenc470f442003-07-28 09:56:35 +000010760
Denis Vlasenkob012b102007-02-19 22:43:01 +000010761 INT_OFF;
Denys Vlasenko60fb98e2018-03-30 22:15:14 +020010762 fd = open(fname, O_RDONLY | O_CLOEXEC);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010763 if (fd < 0) {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010764 if (flags & INPUT_NOFILE_OK)
10765 goto out;
Denys Vlasenkob7adf7a2016-10-25 17:00:13 +020010766 exitstatus = 127;
Johannes Schindelin20a63b22017-08-22 22:03:17 +020010767 ash_msg_and_raise_perror("can't open '%s'", fname);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010768 }
Denys Vlasenko64774602016-10-26 15:24:30 +020010769 if (fd < 10)
10770 fd = savefd(fd);
Denys Vlasenko60fb98e2018-03-30 22:15:14 +020010771 else if (O_CLOEXEC == 0) /* old libc */
Denys Vlasenkoe19923f2016-10-26 15:38:44 +020010772 close_on_exec_on(fd);
Denys Vlasenko60fb98e2018-03-30 22:15:14 +020010773
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010774 setinputfd(fd, flags & INPUT_PUSH_FILE);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010775 out:
Denis Vlasenkob012b102007-02-19 22:43:01 +000010776 INT_ON;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010777 return fd;
Eric Andersenc470f442003-07-28 09:56:35 +000010778}
10779
Eric Andersencb57d552001-06-28 07:25:16 +000010780/*
10781 * Like setinputfile, but takes input from a string.
10782 */
Eric Andersenc470f442003-07-28 09:56:35 +000010783static void
10784setinputstring(char *string)
Eric Andersen62483552001-07-10 06:09:16 +000010785{
Denis Vlasenkob012b102007-02-19 22:43:01 +000010786 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +000010787 pushfile();
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010788 g_parsefile->next_to_pgetc = string;
10789 g_parsefile->left_in_line = strlen(string);
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010790 g_parsefile->buf = NULL;
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010791 g_parsefile->linno = 1;
Denis Vlasenkob012b102007-02-19 22:43:01 +000010792 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +000010793}
10794
10795
Denys Vlasenko70392332016-10-27 02:31:55 +020010796/*
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010797 * Routines to check for mail.
Eric Andersencb57d552001-06-28 07:25:16 +000010798 */
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010799
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010800#if ENABLE_ASH_MAIL
Eric Andersencb57d552001-06-28 07:25:16 +000010801
Denys Vlasenko23841622015-10-09 15:52:03 +020010802/* Hash of mtimes of mailboxes */
10803static unsigned mailtime_hash;
Eric Andersenc470f442003-07-28 09:56:35 +000010804/* Set if MAIL or MAILPATH is changed. */
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010805static smallint mail_var_path_changed;
Eric Andersencb57d552001-06-28 07:25:16 +000010806
Eric Andersencb57d552001-06-28 07:25:16 +000010807/*
Eric Andersenc470f442003-07-28 09:56:35 +000010808 * Print appropriate message(s) if mail has arrived.
10809 * If mail_var_path_changed is set,
10810 * then the value of MAIL has mail_var_path_changed,
10811 * so we just update the values.
Eric Andersencb57d552001-06-28 07:25:16 +000010812 */
Eric Andersenc470f442003-07-28 09:56:35 +000010813static void
10814chkmail(void)
Eric Andersencb57d552001-06-28 07:25:16 +000010815{
Eric Andersencb57d552001-06-28 07:25:16 +000010816 const char *mpath;
10817 char *p;
10818 char *q;
Denys Vlasenko23841622015-10-09 15:52:03 +020010819 unsigned new_hash;
Eric Andersencb57d552001-06-28 07:25:16 +000010820 struct stackmark smark;
10821 struct stat statb;
10822
Eric Andersencb57d552001-06-28 07:25:16 +000010823 setstackmark(&smark);
Eric Andersenc470f442003-07-28 09:56:35 +000010824 mpath = mpathset() ? mpathval() : mailval();
Denys Vlasenko23841622015-10-09 15:52:03 +020010825 new_hash = 0;
10826 for (;;) {
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020010827 p = path_advance(&mpath, nullstr);
Eric Andersencb57d552001-06-28 07:25:16 +000010828 if (p == NULL)
10829 break;
10830 if (*p == '\0')
10831 continue;
Denis Vlasenkof7d56652008-03-25 05:51:41 +000010832 for (q = p; *q; q++)
10833 continue;
Denis Vlasenkoa7189f02006-11-17 20:29:00 +000010834#if DEBUG
Eric Andersencb57d552001-06-28 07:25:16 +000010835 if (q[-1] != '/')
10836 abort();
10837#endif
Eric Andersenc470f442003-07-28 09:56:35 +000010838 q[-1] = '\0'; /* delete trailing '/' */
10839 if (stat(p, &statb) < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +000010840 continue;
Eric Andersencb57d552001-06-28 07:25:16 +000010841 }
Denys Vlasenko23841622015-10-09 15:52:03 +020010842 /* Very simplistic "hash": just a sum of all mtimes */
10843 new_hash += (unsigned)statb.st_mtime;
10844 }
10845 if (!mail_var_path_changed && mailtime_hash != new_hash) {
Denys Vlasenko4cd99e72015-10-09 16:02:53 +020010846 if (mailtime_hash != 0)
10847 out2str("you have mail\n");
Denys Vlasenko23841622015-10-09 15:52:03 +020010848 mailtime_hash = new_hash;
Eric Andersencb57d552001-06-28 07:25:16 +000010849 }
Eric Andersenc470f442003-07-28 09:56:35 +000010850 mail_var_path_changed = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010851 popstackmark(&smark);
10852}
Eric Andersencb57d552001-06-28 07:25:16 +000010853
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010854static void FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010855changemail(const char *val UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000010856{
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010857 mail_var_path_changed = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000010858}
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010859
Denis Vlasenko131ae172007-02-18 13:00:19 +000010860#endif /* ASH_MAIL */
Eric Andersenc470f442003-07-28 09:56:35 +000010861
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010862
10863/* ============ ??? */
10864
Eric Andersencb57d552001-06-28 07:25:16 +000010865/*
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010866 * Set the shell parameters.
Eric Andersencb57d552001-06-28 07:25:16 +000010867 */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010868static void
10869setparam(char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000010870{
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010871 char **newparam;
10872 char **ap;
10873 int nparam;
Eric Andersencb57d552001-06-28 07:25:16 +000010874
Denis Vlasenkof7d56652008-03-25 05:51:41 +000010875 for (nparam = 0; argv[nparam]; nparam++)
10876 continue;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010877 ap = newparam = ckmalloc((nparam + 1) * sizeof(*ap));
10878 while (*argv) {
10879 *ap++ = ckstrdup(*argv++);
Eric Andersencb57d552001-06-28 07:25:16 +000010880 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010881 *ap = NULL;
10882 freeparam(&shellparam);
Denis Vlasenko01631112007-12-16 17:20:38 +000010883 shellparam.malloced = 1;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010884 shellparam.nparam = nparam;
10885 shellparam.p = newparam;
10886#if ENABLE_ASH_GETOPTS
10887 shellparam.optind = 1;
10888 shellparam.optoff = -1;
10889#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010890}
10891
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010892/*
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010893 * Process shell options. The global variable argptr contains a pointer
10894 * to the argument list; we advance it past the options.
Denis Vlasenko94e87bc2008-02-14 16:51:58 +000010895 *
10896 * SUSv3 section 2.8.1 "Consequences of Shell Errors" says:
10897 * For a non-interactive shell, an error condition encountered
10898 * by a special built-in ... shall cause the shell to write a diagnostic message
10899 * to standard error and exit as shown in the following table:
Denis Vlasenko56244732008-02-17 15:14:04 +000010900 * Error Special Built-In
Denis Vlasenko94e87bc2008-02-14 16:51:58 +000010901 * ...
10902 * Utility syntax error (option or operand error) Shall exit
10903 * ...
10904 * However, in bug 1142 (http://busybox.net/bugs/view.php?id=1142)
10905 * we see that bash does not do that (set "finishes" with error code 1 instead,
10906 * and shell continues), and people rely on this behavior!
10907 * Testcase:
10908 * set -o barfoo 2>/dev/null
10909 * echo $?
10910 *
10911 * Oh well. Let's mimic that.
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010912 */
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010913static int
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010914plus_minus_o(char *name, int val)
Eric Andersen62483552001-07-10 06:09:16 +000010915{
10916 int i;
10917
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010918 if (name) {
10919 for (i = 0; i < NOPTS; i++) {
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000010920 if (strcmp(name, optnames(i)) == 0) {
Eric Andersenc470f442003-07-28 09:56:35 +000010921 optlist[i] = val;
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010922 return 0;
Eric Andersen62483552001-07-10 06:09:16 +000010923 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010924 }
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010925 ash_msg("illegal option %co %s", val ? '-' : '+', name);
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010926 return 1;
Eric Andersen62483552001-07-10 06:09:16 +000010927 }
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000010928 for (i = 0; i < NOPTS; i++) {
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010929 if (val) {
10930 out1fmt("%-16s%s\n", optnames(i), optlist[i] ? "on" : "off");
10931 } else {
10932 out1fmt("set %co %s\n", optlist[i] ? '-' : '+', optnames(i));
10933 }
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000010934 }
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010935 return 0;
Eric Andersen62483552001-07-10 06:09:16 +000010936}
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010937static void
10938setoption(int flag, int val)
10939{
10940 int i;
10941
10942 for (i = 0; i < NOPTS; i++) {
10943 if (optletters(i) == flag) {
10944 optlist[i] = val;
10945 return;
10946 }
10947 }
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010948 ash_msg_and_raise_error("illegal option %c%c", val ? '-' : '+', flag);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010949 /* NOTREACHED */
10950}
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010951static int
Denys Vlasenkoec05df12017-07-31 19:43:47 +020010952options(int cmdline, int *login_sh)
Eric Andersencb57d552001-06-28 07:25:16 +000010953{
10954 char *p;
10955 int val;
10956 int c;
10957
10958 if (cmdline)
10959 minusc = NULL;
10960 while ((p = *argptr) != NULL) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010961 c = *p++;
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010962 if (c != '-' && c != '+')
10963 break;
10964 argptr++;
10965 val = 0; /* val = 0 if c == '+' */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010966 if (c == '-') {
Eric Andersencb57d552001-06-28 07:25:16 +000010967 val = 1;
Denis Vlasenko9f739442006-12-16 23:49:13 +000010968 if (p[0] == '\0' || LONE_DASH(p)) {
Eric Andersen2870d962001-07-02 17:27:21 +000010969 if (!cmdline) {
10970 /* "-" means turn off -x and -v */
10971 if (p[0] == '\0')
10972 xflag = vflag = 0;
10973 /* "--" means reset params */
10974 else if (*argptr == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +000010975 setparam(argptr);
Eric Andersen2870d962001-07-02 17:27:21 +000010976 }
Denys Vlasenkob0b83432011-03-07 12:34:59 +010010977 break; /* "-" or "--" terminates options */
Eric Andersencb57d552001-06-28 07:25:16 +000010978 }
Eric Andersencb57d552001-06-28 07:25:16 +000010979 }
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010980 /* first char was + or - */
Eric Andersencb57d552001-06-28 07:25:16 +000010981 while ((c = *p++) != '\0') {
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010982 /* bash 3.2 indeed handles -c CMD and +c CMD the same */
Eric Andersencb57d552001-06-28 07:25:16 +000010983 if (c == 'c' && cmdline) {
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010984 minusc = p; /* command is after shell args */
Eric Andersencb57d552001-06-28 07:25:16 +000010985 } else if (c == 'o') {
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010986 if (plus_minus_o(*argptr, val)) {
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010987 /* it already printed err message */
10988 return 1; /* error */
10989 }
Eric Andersencb57d552001-06-28 07:25:16 +000010990 if (*argptr)
10991 argptr++;
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010992 } else if (cmdline && (c == 'l')) { /* -l or +l == --login */
Denys Vlasenkoec05df12017-07-31 19:43:47 +020010993 if (login_sh)
10994 *login_sh = 1;
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010995 /* bash does not accept +-login, we also won't */
10996 } else if (cmdline && val && (c == '-')) { /* long options */
Denys Vlasenkoec05df12017-07-31 19:43:47 +020010997 if (strcmp(p, "login") == 0) {
10998 if (login_sh)
10999 *login_sh = 1;
11000 }
Robert Griebl64f70cc2002-05-14 23:22:06 +000011001 break;
Eric Andersencb57d552001-06-28 07:25:16 +000011002 } else {
11003 setoption(c, val);
11004 }
11005 }
11006 }
Denis Vlasenko28bf6712008-02-14 15:01:47 +000011007 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +000011008}
11009
Eric Andersencb57d552001-06-28 07:25:16 +000011010/*
Eric Andersencb57d552001-06-28 07:25:16 +000011011 * The shift builtin command.
11012 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020011013static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000011014shiftcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000011015{
11016 int n;
11017 char **ap1, **ap2;
11018
11019 n = 1;
Denis Vlasenko68404f12008-03-17 09:00:54 +000011020 if (argv[1])
Eric Andersencb57d552001-06-28 07:25:16 +000011021 n = number(argv[1]);
11022 if (n > shellparam.nparam)
Ingo van Lil9c8e94b2018-01-05 15:04:23 +010011023 return 1;
Denis Vlasenkob012b102007-02-19 22:43:01 +000011024 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +000011025 shellparam.nparam -= n;
Denis Vlasenko2da584f2007-02-19 22:44:05 +000011026 for (ap1 = shellparam.p; --n >= 0; ap1++) {
Denis Vlasenko01631112007-12-16 17:20:38 +000011027 if (shellparam.malloced)
Denis Vlasenkob012b102007-02-19 22:43:01 +000011028 free(*ap1);
Eric Andersencb57d552001-06-28 07:25:16 +000011029 }
11030 ap2 = shellparam.p;
Denis Vlasenkof7d56652008-03-25 05:51:41 +000011031 while ((*ap2++ = *ap1++) != NULL)
11032 continue;
Denis Vlasenko131ae172007-02-18 13:00:19 +000011033#if ENABLE_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +000011034 shellparam.optind = 1;
11035 shellparam.optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +000011036#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +000011037 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +000011038 return 0;
11039}
11040
Eric Andersencb57d552001-06-28 07:25:16 +000011041/*
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011042 * POSIX requires that 'set' (but not export or readonly) output the
11043 * variables in lexicographic order - by the locale's collating order (sigh).
11044 * Maybe we could keep them in an ordered balanced binary tree
11045 * instead of hashed lists.
11046 * For now just roll 'em through qsort for printing...
11047 */
11048static int
11049showvars(const char *sep_prefix, int on, int off)
11050{
11051 const char *sep;
11052 char **ep, **epend;
11053
Denys Vlasenkoa5060b82017-11-03 14:16:25 +010011054 ep = listvars(on, off, /*strlist:*/ NULL, &epend);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011055 qsort(ep, epend - ep, sizeof(char *), vpcmp);
11056
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000011057 sep = *sep_prefix ? " " : sep_prefix;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011058
11059 for (; ep < epend; ep++) {
11060 const char *p;
11061 const char *q;
11062
Denys Vlasenko9c143ce2017-11-02 12:56:24 +010011063 p = endofname(*ep);
11064/* Used to have simple "p = strchrnul(*ep, '=')" here instead, but this
11065 * makes "export -p" to have output not suitable for "eval":
11066 * import os
11067 * os.environ["test-test"]="test"
11068 * if os.fork() == 0:
11069 * os.execv("ash", [ 'ash', '-c', 'eval $(export -p); echo OK' ]) # fixes this
11070 * os.execv("ash", [ 'ash', '-c', 'env | grep test-test' ])
11071 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011072 q = nullstr;
Denys Vlasenko9c143ce2017-11-02 12:56:24 +010011073 if (*p == '=')
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011074 q = single_quote(++p);
11075 out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
11076 }
11077 return 0;
11078}
11079
11080/*
Eric Andersencb57d552001-06-28 07:25:16 +000011081 * The set command builtin.
11082 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020011083static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000011084setcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +000011085{
Denis Vlasenko28bf6712008-02-14 15:01:47 +000011086 int retval;
11087
Denis Vlasenko68404f12008-03-17 09:00:54 +000011088 if (!argv[1])
Eric Andersenc470f442003-07-28 09:56:35 +000011089 return showvars(nullstr, 0, VUNSET);
Denys Vlasenkob0b83432011-03-07 12:34:59 +010011090
Denis Vlasenkob012b102007-02-19 22:43:01 +000011091 INT_OFF;
Denys Vlasenkoec05df12017-07-31 19:43:47 +020011092 retval = options(/*cmdline:*/ 0, NULL);
Denys Vlasenkob0b83432011-03-07 12:34:59 +010011093 if (retval == 0) { /* if no parse error... */
Denis Vlasenko28bf6712008-02-14 15:01:47 +000011094 optschanged();
11095 if (*argptr != NULL) {
11096 setparam(argptr);
11097 }
Eric Andersencb57d552001-06-28 07:25:16 +000011098 }
Denis Vlasenkob012b102007-02-19 22:43:01 +000011099 INT_ON;
Denis Vlasenko28bf6712008-02-14 15:01:47 +000011100 return retval;
Eric Andersencb57d552001-06-28 07:25:16 +000011101}
11102
Denis Vlasenko131ae172007-02-18 13:00:19 +000011103#if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020011104static void FAST_FUNC
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000011105change_random(const char *value)
Eric Andersenef02f822004-03-11 13:34:24 +000011106{
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020011107 uint32_t t;
11108
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011109 if (value == NULL) {
Eric Andersen16767e22004-03-16 05:14:10 +000011110 /* "get", generate */
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020011111 t = next_random(&random_gen);
Eric Andersen16767e22004-03-16 05:14:10 +000011112 /* set without recursion */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +020011113 setvar(vrandom.var_text, utoa(t), VNOFUNC);
Eric Andersen16767e22004-03-16 05:14:10 +000011114 vrandom.flags &= ~VNOFUNC;
11115 } else {
11116 /* set/reset */
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020011117 t = strtoul(value, NULL, 10);
11118 INIT_RANDOM_T(&random_gen, (t ? t : 1), t);
Eric Andersen16767e22004-03-16 05:14:10 +000011119 }
Eric Andersenef02f822004-03-11 13:34:24 +000011120}
Eric Andersen16767e22004-03-16 05:14:10 +000011121#endif
11122
Denis Vlasenko131ae172007-02-18 13:00:19 +000011123#if ENABLE_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +000011124static int
Denys Vlasenko35c2a132016-10-26 17:34:26 +020011125getopts(char *optstr, char *optvar, char **optfirst)
Eric Andersencb57d552001-06-28 07:25:16 +000011126{
11127 char *p, *q;
11128 char c = '?';
11129 int done = 0;
Denys Vlasenko9c541002015-10-07 15:44:36 +020011130 char sbuf[2];
Eric Andersena48b0a32003-10-22 10:56:47 +000011131 char **optnext;
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020011132 int ind = shellparam.optind;
11133 int off = shellparam.optoff;
Eric Andersencb57d552001-06-28 07:25:16 +000011134
Denys Vlasenko9c541002015-10-07 15:44:36 +020011135 sbuf[1] = '\0';
11136
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020011137 shellparam.optind = -1;
11138 optnext = optfirst + ind - 1;
Eric Andersena48b0a32003-10-22 10:56:47 +000011139
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020011140 if (ind <= 1 || off < 0 || (int)strlen(optnext[-1]) < off)
Eric Andersencb57d552001-06-28 07:25:16 +000011141 p = NULL;
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020011142 else
11143 p = optnext[-1] + off;
Eric Andersencb57d552001-06-28 07:25:16 +000011144 if (p == NULL || *p == '\0') {
11145 /* Current word is done, advance */
Eric Andersencb57d552001-06-28 07:25:16 +000011146 p = *optnext;
11147 if (p == NULL || *p != '-' || *++p == '\0') {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011148 atend:
Denys Vlasenko9832bba2017-08-15 15:44:41 +020011149 unsetvar("OPTARG");
Eric Andersencb57d552001-06-28 07:25:16 +000011150 p = NULL;
11151 done = 1;
11152 goto out;
11153 }
11154 optnext++;
Denis Vlasenko9f739442006-12-16 23:49:13 +000011155 if (LONE_DASH(p)) /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +000011156 goto atend;
11157 }
11158
11159 c = *p++;
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +000011160 for (q = optstr; *q != c;) {
Eric Andersencb57d552001-06-28 07:25:16 +000011161 if (*q == '\0') {
Denys Vlasenko9832bba2017-08-15 15:44:41 +020011162 /* OPTERR is a bashism */
11163 const char *cp = lookupvar("OPTERR");
11164 if ((cp && LONE_CHAR(cp, '0'))
11165 || (optstr[0] == ':')
11166 ) {
Denys Vlasenko9c541002015-10-07 15:44:36 +020011167 sbuf[0] = c;
11168 /*sbuf[1] = '\0'; - already is */
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020011169 setvar0("OPTARG", sbuf);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011170 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000011171 fprintf(stderr, "Illegal option -%c\n", c);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011172 unsetvar("OPTARG");
Eric Andersencb57d552001-06-28 07:25:16 +000011173 }
11174 c = '?';
Eric Andersenc470f442003-07-28 09:56:35 +000011175 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +000011176 }
11177 if (*++q == ':')
11178 q++;
11179 }
11180
11181 if (*++q == ':') {
11182 if (*p == '\0' && (p = *optnext) == NULL) {
Denys Vlasenko9832bba2017-08-15 15:44:41 +020011183 /* OPTERR is a bashism */
11184 const char *cp = lookupvar("OPTERR");
11185 if ((cp && LONE_CHAR(cp, '0'))
11186 || (optstr[0] == ':')
11187 ) {
Denys Vlasenko9c541002015-10-07 15:44:36 +020011188 sbuf[0] = c;
11189 /*sbuf[1] = '\0'; - already is */
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020011190 setvar0("OPTARG", sbuf);
Eric Andersencb57d552001-06-28 07:25:16 +000011191 c = ':';
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011192 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000011193 fprintf(stderr, "No arg for -%c option\n", c);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011194 unsetvar("OPTARG");
Eric Andersencb57d552001-06-28 07:25:16 +000011195 c = '?';
11196 }
Eric Andersenc470f442003-07-28 09:56:35 +000011197 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +000011198 }
11199
11200 if (p == *optnext)
11201 optnext++;
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020011202 setvar0("OPTARG", p);
Eric Andersencb57d552001-06-28 07:25:16 +000011203 p = NULL;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011204 } else
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020011205 setvar0("OPTARG", nullstr);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011206 out:
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020011207 ind = optnext - optfirst + 1;
11208 setvar("OPTIND", itoa(ind), VNOFUNC);
Denys Vlasenko9c541002015-10-07 15:44:36 +020011209 sbuf[0] = c;
11210 /*sbuf[1] = '\0'; - already is */
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020011211 setvar0(optvar, sbuf);
11212
11213 shellparam.optoff = p ? p - *(optnext - 1) : -1;
11214 shellparam.optind = ind;
11215
Eric Andersencb57d552001-06-28 07:25:16 +000011216 return done;
11217}
Eric Andersenc470f442003-07-28 09:56:35 +000011218
11219/*
11220 * The getopts builtin. Shellparam.optnext points to the next argument
11221 * to be processed. Shellparam.optptr points to the next character to
11222 * be processed in the current argument. If shellparam.optnext is NULL,
11223 * then it's the first time getopts has been called.
11224 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020011225static int FAST_FUNC
Eric Andersenc470f442003-07-28 09:56:35 +000011226getoptscmd(int argc, char **argv)
11227{
11228 char **optbase;
11229
11230 if (argc < 3)
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +000011231 ash_msg_and_raise_error("usage: getopts optstring var [arg]");
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011232 if (argc == 3) {
Eric Andersenc470f442003-07-28 09:56:35 +000011233 optbase = shellparam.p;
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020011234 if ((unsigned)shellparam.optind > shellparam.nparam + 1) {
Eric Andersenc470f442003-07-28 09:56:35 +000011235 shellparam.optind = 1;
11236 shellparam.optoff = -1;
11237 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011238 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000011239 optbase = &argv[3];
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020011240 if ((unsigned)shellparam.optind > argc - 2) {
Eric Andersenc470f442003-07-28 09:56:35 +000011241 shellparam.optind = 1;
11242 shellparam.optoff = -1;
11243 }
11244 }
11245
Denys Vlasenko35c2a132016-10-26 17:34:26 +020011246 return getopts(argv[1], argv[2], optbase);
Eric Andersenc470f442003-07-28 09:56:35 +000011247}
Denis Vlasenko131ae172007-02-18 13:00:19 +000011248#endif /* ASH_GETOPTS */
Eric Andersencb57d552001-06-28 07:25:16 +000011249
Eric Andersencb57d552001-06-28 07:25:16 +000011250
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011251/* ============ Shell parser */
Eric Andersencb57d552001-06-28 07:25:16 +000011252
Denis Vlasenkob07a4962008-06-22 13:16:23 +000011253struct heredoc {
11254 struct heredoc *next; /* next here document in list */
11255 union node *here; /* redirection node */
11256 char *eofmark; /* string indicating end of input */
11257 smallint striptabs; /* if set, strip leading tabs */
11258};
11259
11260static smallint tokpushback; /* last token pushed back */
Denis Vlasenkob07a4962008-06-22 13:16:23 +000011261static smallint quoteflag; /* set if (part of) last token was quoted */
11262static token_id_t lasttoken; /* last token read (integer id Txxx) */
11263static struct heredoc *heredoclist; /* list of here documents to read */
11264static char *wordtext; /* text of last word returned by readtoken */
11265static struct nodelist *backquotelist;
11266static union node *redirnode;
11267static struct heredoc *heredoc;
Denis Vlasenko99eb8502007-02-23 21:09:49 +000011268
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020011269static const char *
11270tokname(char *buf, int tok)
11271{
11272 if (tok < TSEMI)
Denys Vlasenko888527c2016-10-02 16:54:17 +020011273 return tokname_array[tok];
11274 sprintf(buf, "\"%s\"", tokname_array[tok]);
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020011275 return buf;
11276}
11277
11278/* raise_error_unexpected_syntax:
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011279 * Called when an unexpected token is read during the parse. The argument
11280 * is the token that is expected, or -1 if more than one type of token can
11281 * occur at this point.
11282 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000011283static void raise_error_unexpected_syntax(int) NORETURN;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011284static void
11285raise_error_unexpected_syntax(int token)
11286{
11287 char msg[64];
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020011288 char buf[16];
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011289 int l;
11290
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020011291 l = sprintf(msg, "unexpected %s", tokname(buf, lasttoken));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011292 if (token >= 0)
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020011293 sprintf(msg + l, " (expecting %s)", tokname(buf, token));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011294 raise_error_syntax(msg);
11295 /* NOTREACHED */
11296}
Eric Andersencb57d552001-06-28 07:25:16 +000011297
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011298/* parsing is heavily cross-recursive, need these forward decls */
11299static union node *andor(void);
11300static union node *pipeline(void);
11301static union node *parse_command(void);
11302static void parseheredoc(void);
Ron Yorstonc0e00762015-10-29 11:30:55 +000011303static int peektoken(void);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011304static int readtoken(void);
Eric Andersencb57d552001-06-28 07:25:16 +000011305
Eric Andersenc470f442003-07-28 09:56:35 +000011306static union node *
11307list(int nlflag)
Eric Andersencb57d552001-06-28 07:25:16 +000011308{
11309 union node *n1, *n2, *n3;
11310 int tok;
11311
Eric Andersencb57d552001-06-28 07:25:16 +000011312 n1 = NULL;
11313 for (;;) {
Ron Yorstonc0e00762015-10-29 11:30:55 +000011314 switch (peektoken()) {
11315 case TNL:
11316 if (!(nlflag & 1))
11317 break;
11318 parseheredoc();
11319 return n1;
11320
11321 case TEOF:
11322 if (!n1 && (nlflag & 1))
11323 n1 = NODE_EOF;
11324 parseheredoc();
11325 return n1;
11326 }
11327
11328 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Denys Vlasenko888527c2016-10-02 16:54:17 +020011329 if (nlflag == 2 && ((1 << peektoken()) & tokendlist))
Ron Yorstonc0e00762015-10-29 11:30:55 +000011330 return n1;
11331 nlflag |= 2;
11332
Eric Andersencb57d552001-06-28 07:25:16 +000011333 n2 = andor();
11334 tok = readtoken();
11335 if (tok == TBACKGND) {
Eric Andersenc470f442003-07-28 09:56:35 +000011336 if (n2->type == NPIPE) {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +000011337 n2->npipe.pipe_backgnd = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011338 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000011339 if (n2->type != NREDIR) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011340 n3 = stzalloc(sizeof(struct nredir));
Eric Andersenc470f442003-07-28 09:56:35 +000011341 n3->nredir.n = n2;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011342 /*n3->nredir.redirect = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011343 n2 = n3;
11344 }
11345 n2->type = NBACKGND;
Eric Andersencb57d552001-06-28 07:25:16 +000011346 }
11347 }
11348 if (n1 == NULL) {
11349 n1 = n2;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011350 } else {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011351 n3 = stzalloc(sizeof(struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +000011352 n3->type = NSEMI;
11353 n3->nbinary.ch1 = n1;
11354 n3->nbinary.ch2 = n2;
11355 n1 = n3;
11356 }
11357 switch (tok) {
Ron Yorstonc0e00762015-10-29 11:30:55 +000011358 case TNL:
11359 case TEOF:
11360 tokpushback = 1;
11361 /* fall through */
Eric Andersencb57d552001-06-28 07:25:16 +000011362 case TBACKGND:
11363 case TSEMI:
Eric Andersencb57d552001-06-28 07:25:16 +000011364 break;
Eric Andersencb57d552001-06-28 07:25:16 +000011365 default:
Ron Yorstonc0e00762015-10-29 11:30:55 +000011366 if ((nlflag & 1))
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011367 raise_error_unexpected_syntax(-1);
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011368 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011369 return n1;
11370 }
11371 }
11372}
11373
Eric Andersenc470f442003-07-28 09:56:35 +000011374static union node *
11375andor(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011376{
Eric Andersencb57d552001-06-28 07:25:16 +000011377 union node *n1, *n2, *n3;
11378 int t;
11379
Eric Andersencb57d552001-06-28 07:25:16 +000011380 n1 = pipeline();
11381 for (;;) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011382 t = readtoken();
11383 if (t == TAND) {
Eric Andersencb57d552001-06-28 07:25:16 +000011384 t = NAND;
11385 } else if (t == TOR) {
11386 t = NOR;
11387 } else {
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011388 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011389 return n1;
11390 }
Eric Andersenc470f442003-07-28 09:56:35 +000011391 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000011392 n2 = pipeline();
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011393 n3 = stzalloc(sizeof(struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +000011394 n3->type = t;
11395 n3->nbinary.ch1 = n1;
11396 n3->nbinary.ch2 = n2;
11397 n1 = n3;
11398 }
11399}
11400
Eric Andersenc470f442003-07-28 09:56:35 +000011401static union node *
11402pipeline(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011403{
Eric Andersencb57d552001-06-28 07:25:16 +000011404 union node *n1, *n2, *pipenode;
11405 struct nodelist *lp, *prev;
11406 int negate;
11407
11408 negate = 0;
11409 TRACE(("pipeline: entered\n"));
11410 if (readtoken() == TNOT) {
11411 negate = !negate;
Eric Andersenc470f442003-07-28 09:56:35 +000011412 checkkwd = CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000011413 } else
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011414 tokpushback = 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011415 n1 = parse_command();
Eric Andersencb57d552001-06-28 07:25:16 +000011416 if (readtoken() == TPIPE) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011417 pipenode = stzalloc(sizeof(struct npipe));
Eric Andersencb57d552001-06-28 07:25:16 +000011418 pipenode->type = NPIPE;
Denis Vlasenko2dc240c2008-07-24 06:07:50 +000011419 /*pipenode->npipe.pipe_backgnd = 0; - stzalloc did it */
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011420 lp = stzalloc(sizeof(struct nodelist));
Eric Andersencb57d552001-06-28 07:25:16 +000011421 pipenode->npipe.cmdlist = lp;
11422 lp->n = n1;
11423 do {
11424 prev = lp;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011425 lp = stzalloc(sizeof(struct nodelist));
Eric Andersenc470f442003-07-28 09:56:35 +000011426 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011427 lp->n = parse_command();
Eric Andersencb57d552001-06-28 07:25:16 +000011428 prev->next = lp;
11429 } while (readtoken() == TPIPE);
11430 lp->next = NULL;
11431 n1 = pipenode;
11432 }
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011433 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011434 if (negate) {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011435 n2 = stzalloc(sizeof(struct nnot));
Eric Andersencb57d552001-06-28 07:25:16 +000011436 n2->type = NNOT;
11437 n2->nnot.com = n1;
11438 return n2;
Denis Vlasenko2da584f2007-02-19 22:44:05 +000011439 }
11440 return n1;
Eric Andersencb57d552001-06-28 07:25:16 +000011441}
11442
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011443static union node *
11444makename(void)
11445{
11446 union node *n;
11447
Denis Vlasenko597906c2008-02-20 16:38:54 +000011448 n = stzalloc(sizeof(struct narg));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011449 n->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011450 /*n->narg.next = NULL; - stzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011451 n->narg.text = wordtext;
11452 n->narg.backquote = backquotelist;
11453 return n;
11454}
11455
11456static void
11457fixredir(union node *n, const char *text, int err)
11458{
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000011459 int fd;
11460
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011461 TRACE(("Fix redir %s %d\n", text, err));
11462 if (!err)
11463 n->ndup.vname = NULL;
11464
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000011465 fd = bb_strtou(text, NULL, 10);
11466 if (!errno && fd >= 0)
11467 n->ndup.dupfd = fd;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011468 else if (LONE_DASH(text))
11469 n->ndup.dupfd = -1;
11470 else {
11471 if (err)
Denis Vlasenko559691a2008-10-05 18:39:31 +000011472 raise_error_syntax("bad fd number");
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011473 n->ndup.vname = makename();
11474 }
11475}
11476
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011477static void
11478parsefname(void)
11479{
11480 union node *n = redirnode;
11481
Denys Vlasenkoa7328982017-07-29 19:57:28 +020011482 if (n->type == NHERE)
11483 checkkwd = CHKEOFMARK;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011484 if (readtoken() != TWORD)
11485 raise_error_unexpected_syntax(-1);
11486 if (n->type == NHERE) {
11487 struct heredoc *here = heredoc;
11488 struct heredoc *p;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011489
11490 if (quoteflag == 0)
11491 n->type = NXHERE;
11492 TRACE(("Here document %d\n", n->type));
Denys Vlasenko740058b2018-01-09 17:01:00 +010011493 rmescapes(wordtext, 0, NULL);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011494 here->eofmark = wordtext;
11495 here->next = NULL;
11496 if (heredoclist == NULL)
11497 heredoclist = here;
11498 else {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011499 for (p = heredoclist; p->next; p = p->next)
11500 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011501 p->next = here;
11502 }
11503 } else if (n->type == NTOFD || n->type == NFROMFD) {
11504 fixredir(n, wordtext, 0);
11505 } else {
11506 n->nfile.fname = makename();
11507 }
11508}
Eric Andersencb57d552001-06-28 07:25:16 +000011509
Eric Andersenc470f442003-07-28 09:56:35 +000011510static union node *
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011511simplecmd(void)
11512{
11513 union node *args, **app;
11514 union node *n = NULL;
11515 union node *vars, **vpp;
11516 union node **rpp, *redir;
11517 int savecheckkwd;
Denys Vlasenko675d24a2018-01-27 22:02:05 +010011518 int savelinno;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011519#if BASH_TEST2
Denis Vlasenko80591b02008-03-25 07:49:43 +000011520 smallint double_brackets_flag = 0;
11521#endif
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011522 IF_BASH_FUNCTION(smallint function_flag = 0;)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011523
11524 args = NULL;
11525 app = &args;
11526 vars = NULL;
11527 vpp = &vars;
11528 redir = NULL;
11529 rpp = &redir;
11530
11531 savecheckkwd = CHKALIAS;
Denys Vlasenko675d24a2018-01-27 22:02:05 +010011532 savelinno = g_parsefile->linno;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011533 for (;;) {
Denis Vlasenko80591b02008-03-25 07:49:43 +000011534 int t;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011535 checkkwd = savecheckkwd;
Denis Vlasenko80591b02008-03-25 07:49:43 +000011536 t = readtoken();
11537 switch (t) {
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011538#if BASH_FUNCTION
Ron Yorston95ebcf72015-11-03 09:42:23 +000011539 case TFUNCTION:
11540 if (peektoken() != TWORD)
11541 raise_error_unexpected_syntax(TWORD);
11542 function_flag = 1;
11543 break;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011544#endif
11545#if BASH_TEST2
Denis Vlasenko80591b02008-03-25 07:49:43 +000011546 case TAND: /* "&&" */
11547 case TOR: /* "||" */
11548 if (!double_brackets_flag) {
11549 tokpushback = 1;
11550 goto out;
11551 }
11552 wordtext = (char *) (t == TAND ? "-a" : "-o");
11553#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011554 case TWORD:
Denis Vlasenko597906c2008-02-20 16:38:54 +000011555 n = stzalloc(sizeof(struct narg));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011556 n->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011557 /*n->narg.next = NULL; - stzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011558 n->narg.text = wordtext;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011559#if BASH_TEST2
Denis Vlasenko80591b02008-03-25 07:49:43 +000011560 if (strcmp("[[", wordtext) == 0)
11561 double_brackets_flag = 1;
11562 else if (strcmp("]]", wordtext) == 0)
11563 double_brackets_flag = 0;
11564#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011565 n->narg.backquote = backquotelist;
11566 if (savecheckkwd && isassignment(wordtext)) {
11567 *vpp = n;
11568 vpp = &n->narg.next;
11569 } else {
11570 *app = n;
11571 app = &n->narg.next;
11572 savecheckkwd = 0;
11573 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011574#if BASH_FUNCTION
Ron Yorston95ebcf72015-11-03 09:42:23 +000011575 if (function_flag) {
11576 checkkwd = CHKNL | CHKKWD;
11577 switch (peektoken()) {
11578 case TBEGIN:
11579 case TIF:
11580 case TCASE:
11581 case TUNTIL:
11582 case TWHILE:
11583 case TFOR:
11584 goto do_func;
11585 case TLP:
11586 function_flag = 0;
11587 break;
11588 case TWORD:
11589 if (strcmp("[[", wordtext) == 0)
11590 goto do_func;
11591 /* fall through */
11592 default:
11593 raise_error_unexpected_syntax(-1);
11594 }
11595 }
11596#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011597 break;
11598 case TREDIR:
11599 *rpp = n = redirnode;
11600 rpp = &n->nfile.next;
11601 parsefname(); /* read name of redirection file */
11602 break;
11603 case TLP:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011604 IF_BASH_FUNCTION(do_func:)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011605 if (args && app == &args->narg.next
11606 && !vars && !redir
11607 ) {
11608 struct builtincmd *bcmd;
11609 const char *name;
11610
11611 /* We have a function */
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011612 if (IF_BASH_FUNCTION(!function_flag &&) readtoken() != TRP)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011613 raise_error_unexpected_syntax(TRP);
11614 name = n->narg.text;
11615 if (!goodname(name)
11616 || ((bcmd = find_builtin(name)) && IS_BUILTIN_SPECIAL(bcmd))
11617 ) {
Denis Vlasenko559691a2008-10-05 18:39:31 +000011618 raise_error_syntax("bad function name");
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011619 }
11620 n->type = NDEFUN;
11621 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Denys Vlasenko675d24a2018-01-27 22:02:05 +010011622 n->ndefun.text = n->narg.text;
11623 n->ndefun.linno = g_parsefile->linno;
11624 n->ndefun.body = parse_command();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011625 return n;
11626 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011627 IF_BASH_FUNCTION(function_flag = 0;)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011628 /* fall through */
11629 default:
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011630 tokpushback = 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011631 goto out;
11632 }
11633 }
11634 out:
11635 *app = NULL;
11636 *vpp = NULL;
11637 *rpp = NULL;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011638 n = stzalloc(sizeof(struct ncmd));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011639 n->type = NCMD;
Denys Vlasenko675d24a2018-01-27 22:02:05 +010011640 n->ncmd.linno = savelinno;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011641 n->ncmd.args = args;
11642 n->ncmd.assign = vars;
11643 n->ncmd.redirect = redir;
11644 return n;
11645}
11646
11647static union node *
11648parse_command(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011649{
Eric Andersencb57d552001-06-28 07:25:16 +000011650 union node *n1, *n2;
11651 union node *ap, **app;
11652 union node *cp, **cpp;
11653 union node *redir, **rpp;
Eric Andersenc470f442003-07-28 09:56:35 +000011654 union node **rpp2;
Eric Andersencb57d552001-06-28 07:25:16 +000011655 int t;
Denys Vlasenko675d24a2018-01-27 22:02:05 +010011656 int savelinno;
Eric Andersencb57d552001-06-28 07:25:16 +000011657
11658 redir = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +000011659 rpp2 = &redir;
Eric Andersen88cec252001-09-06 17:35:20 +000011660
Denys Vlasenko675d24a2018-01-27 22:02:05 +010011661 savelinno = g_parsefile->linno;
11662
Eric Andersencb57d552001-06-28 07:25:16 +000011663 switch (readtoken()) {
Eric Andersenc470f442003-07-28 09:56:35 +000011664 default:
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011665 raise_error_unexpected_syntax(-1);
Eric Andersenc470f442003-07-28 09:56:35 +000011666 /* NOTREACHED */
Eric Andersencb57d552001-06-28 07:25:16 +000011667 case TIF:
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011668 n1 = stzalloc(sizeof(struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +000011669 n1->type = NIF;
11670 n1->nif.test = list(0);
11671 if (readtoken() != TTHEN)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011672 raise_error_unexpected_syntax(TTHEN);
Eric Andersencb57d552001-06-28 07:25:16 +000011673 n1->nif.ifpart = list(0);
11674 n2 = n1;
11675 while (readtoken() == TELIF) {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011676 n2->nif.elsepart = stzalloc(sizeof(struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +000011677 n2 = n2->nif.elsepart;
11678 n2->type = NIF;
11679 n2->nif.test = list(0);
11680 if (readtoken() != TTHEN)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011681 raise_error_unexpected_syntax(TTHEN);
Eric Andersencb57d552001-06-28 07:25:16 +000011682 n2->nif.ifpart = list(0);
11683 }
11684 if (lasttoken == TELSE)
11685 n2->nif.elsepart = list(0);
11686 else {
11687 n2->nif.elsepart = NULL;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011688 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011689 }
Eric Andersenc470f442003-07-28 09:56:35 +000011690 t = TFI;
Eric Andersencb57d552001-06-28 07:25:16 +000011691 break;
11692 case TWHILE:
Eric Andersenc470f442003-07-28 09:56:35 +000011693 case TUNTIL: {
Eric Andersencb57d552001-06-28 07:25:16 +000011694 int got;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011695 n1 = stzalloc(sizeof(struct nbinary));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011696 n1->type = (lasttoken == TWHILE) ? NWHILE : NUNTIL;
Eric Andersencb57d552001-06-28 07:25:16 +000011697 n1->nbinary.ch1 = list(0);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011698 got = readtoken();
11699 if (got != TDO) {
Denys Vlasenko888527c2016-10-02 16:54:17 +020011700 TRACE(("expecting DO got '%s' %s\n", tokname_array[got],
Denis Vlasenko131ae172007-02-18 13:00:19 +000011701 got == TWORD ? wordtext : ""));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011702 raise_error_unexpected_syntax(TDO);
Eric Andersencb57d552001-06-28 07:25:16 +000011703 }
11704 n1->nbinary.ch2 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +000011705 t = TDONE;
Eric Andersencb57d552001-06-28 07:25:16 +000011706 break;
11707 }
11708 case TFOR:
Denis Vlasenko2dc240c2008-07-24 06:07:50 +000011709 if (readtoken() != TWORD || quoteflag || !goodname(wordtext))
Denis Vlasenko559691a2008-10-05 18:39:31 +000011710 raise_error_syntax("bad for loop variable");
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011711 n1 = stzalloc(sizeof(struct nfor));
Eric Andersencb57d552001-06-28 07:25:16 +000011712 n1->type = NFOR;
Denys Vlasenko675d24a2018-01-27 22:02:05 +010011713 n1->nfor.linno = savelinno;
Eric Andersencb57d552001-06-28 07:25:16 +000011714 n1->nfor.var = wordtext;
Ron Yorstonab80e012015-08-03 13:46:00 +010011715 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000011716 if (readtoken() == TIN) {
11717 app = &ap;
11718 while (readtoken() == TWORD) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011719 n2 = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000011720 n2->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011721 /*n2->narg.next = NULL; - stzalloc did it */
Eric Andersencb57d552001-06-28 07:25:16 +000011722 n2->narg.text = wordtext;
11723 n2->narg.backquote = backquotelist;
11724 *app = n2;
11725 app = &n2->narg.next;
11726 }
11727 *app = NULL;
11728 n1->nfor.args = ap;
11729 if (lasttoken != TNL && lasttoken != TSEMI)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011730 raise_error_unexpected_syntax(-1);
Eric Andersencb57d552001-06-28 07:25:16 +000011731 } else {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011732 n2 = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000011733 n2->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011734 /*n2->narg.next = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011735 n2->narg.text = (char *)dolatstr;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011736 /*n2->narg.backquote = NULL;*/
Eric Andersencb57d552001-06-28 07:25:16 +000011737 n1->nfor.args = n2;
11738 /*
11739 * Newline or semicolon here is optional (but note
11740 * that the original Bourne shell only allowed NL).
11741 */
Ron Yorstonab80e012015-08-03 13:46:00 +010011742 if (lasttoken != TSEMI)
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011743 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011744 }
Eric Andersenc470f442003-07-28 09:56:35 +000011745 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000011746 if (readtoken() != TDO)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011747 raise_error_unexpected_syntax(TDO);
Eric Andersencb57d552001-06-28 07:25:16 +000011748 n1->nfor.body = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +000011749 t = TDONE;
Eric Andersencb57d552001-06-28 07:25:16 +000011750 break;
11751 case TCASE:
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011752 n1 = stzalloc(sizeof(struct ncase));
Eric Andersencb57d552001-06-28 07:25:16 +000011753 n1->type = NCASE;
Denys Vlasenko675d24a2018-01-27 22:02:05 +010011754 n1->ncase.linno = savelinno;
Eric Andersencb57d552001-06-28 07:25:16 +000011755 if (readtoken() != TWORD)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011756 raise_error_unexpected_syntax(TWORD);
Denis Vlasenko597906c2008-02-20 16:38:54 +000011757 n1->ncase.expr = n2 = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000011758 n2->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011759 /*n2->narg.next = NULL; - stzalloc did it */
Eric Andersencb57d552001-06-28 07:25:16 +000011760 n2->narg.text = wordtext;
11761 n2->narg.backquote = backquotelist;
Ron Yorston383b8852015-08-03 13:46:25 +010011762 checkkwd = CHKNL | CHKKWD | CHKALIAS;
11763 if (readtoken() != TIN)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011764 raise_error_unexpected_syntax(TIN);
Eric Andersencb57d552001-06-28 07:25:16 +000011765 cpp = &n1->ncase.cases;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011766 next_case:
Eric Andersenc470f442003-07-28 09:56:35 +000011767 checkkwd = CHKNL | CHKKWD;
11768 t = readtoken();
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011769 while (t != TESAC) {
Eric Andersencb57d552001-06-28 07:25:16 +000011770 if (lasttoken == TLP)
11771 readtoken();
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011772 *cpp = cp = stzalloc(sizeof(struct nclist));
Eric Andersencb57d552001-06-28 07:25:16 +000011773 cp->type = NCLIST;
11774 app = &cp->nclist.pattern;
11775 for (;;) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011776 *app = ap = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000011777 ap->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011778 /*ap->narg.next = NULL; - stzalloc did it */
Eric Andersencb57d552001-06-28 07:25:16 +000011779 ap->narg.text = wordtext;
11780 ap->narg.backquote = backquotelist;
Eric Andersenc470f442003-07-28 09:56:35 +000011781 if (readtoken() != TPIPE)
Eric Andersencb57d552001-06-28 07:25:16 +000011782 break;
11783 app = &ap->narg.next;
11784 readtoken();
11785 }
Denis Vlasenko597906c2008-02-20 16:38:54 +000011786 //ap->narg.next = NULL;
Eric Andersencb57d552001-06-28 07:25:16 +000011787 if (lasttoken != TRP)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011788 raise_error_unexpected_syntax(TRP);
Eric Andersenc470f442003-07-28 09:56:35 +000011789 cp->nclist.body = list(2);
Eric Andersencb57d552001-06-28 07:25:16 +000011790
Eric Andersenc470f442003-07-28 09:56:35 +000011791 cpp = &cp->nclist.next;
11792
11793 checkkwd = CHKNL | CHKKWD;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011794 t = readtoken();
11795 if (t != TESAC) {
Eric Andersencb57d552001-06-28 07:25:16 +000011796 if (t != TENDCASE)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011797 raise_error_unexpected_syntax(TENDCASE);
11798 goto next_case;
Eric Andersencb57d552001-06-28 07:25:16 +000011799 }
Eric Andersenc470f442003-07-28 09:56:35 +000011800 }
Eric Andersencb57d552001-06-28 07:25:16 +000011801 *cpp = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +000011802 goto redir;
Eric Andersencb57d552001-06-28 07:25:16 +000011803 case TLP:
Denis Vlasenko597906c2008-02-20 16:38:54 +000011804 n1 = stzalloc(sizeof(struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +000011805 n1->type = NSUBSHELL;
Denys Vlasenko675d24a2018-01-27 22:02:05 +010011806 n1->nredir.linno = savelinno;
Eric Andersencb57d552001-06-28 07:25:16 +000011807 n1->nredir.n = list(0);
Denis Vlasenko597906c2008-02-20 16:38:54 +000011808 /*n1->nredir.redirect = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011809 t = TRP;
Eric Andersencb57d552001-06-28 07:25:16 +000011810 break;
11811 case TBEGIN:
11812 n1 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +000011813 t = TEND;
Eric Andersencb57d552001-06-28 07:25:16 +000011814 break;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011815 IF_BASH_FUNCTION(case TFUNCTION:)
Eric Andersencb57d552001-06-28 07:25:16 +000011816 case TWORD:
Eric Andersenc470f442003-07-28 09:56:35 +000011817 case TREDIR:
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011818 tokpushback = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000011819 return simplecmd();
Eric Andersencb57d552001-06-28 07:25:16 +000011820 }
11821
Eric Andersenc470f442003-07-28 09:56:35 +000011822 if (readtoken() != t)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011823 raise_error_unexpected_syntax(t);
Eric Andersenc470f442003-07-28 09:56:35 +000011824
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011825 redir:
Eric Andersencb57d552001-06-28 07:25:16 +000011826 /* Now check for redirection which may follow command */
Eric Andersenc470f442003-07-28 09:56:35 +000011827 checkkwd = CHKKWD | CHKALIAS;
11828 rpp = rpp2;
Eric Andersencb57d552001-06-28 07:25:16 +000011829 while (readtoken() == TREDIR) {
11830 *rpp = n2 = redirnode;
11831 rpp = &n2->nfile.next;
11832 parsefname();
11833 }
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011834 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011835 *rpp = NULL;
11836 if (redir) {
11837 if (n1->type != NSUBSHELL) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011838 n2 = stzalloc(sizeof(struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +000011839 n2->type = NREDIR;
Denys Vlasenko675d24a2018-01-27 22:02:05 +010011840 n2->nredir.linno = savelinno;
Eric Andersencb57d552001-06-28 07:25:16 +000011841 n2->nredir.n = n1;
11842 n1 = n2;
11843 }
11844 n1->nredir.redirect = redir;
11845 }
Eric Andersencb57d552001-06-28 07:25:16 +000011846 return n1;
11847}
11848
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011849#if BASH_DOLLAR_SQUOTE
Denys Vlasenko37dc08b2016-10-02 04:38:07 +020011850static int
11851decode_dollar_squote(void)
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011852{
11853 static const char C_escapes[] ALIGN1 = "nrbtfav""x\\01234567";
11854 int c, cnt;
11855 char *p;
11856 char buf[4];
11857
11858 c = pgetc();
11859 p = strchr(C_escapes, c);
11860 if (p) {
11861 buf[0] = c;
11862 p = buf;
11863 cnt = 3;
11864 if ((unsigned char)(c - '0') <= 7) { /* \ooo */
11865 do {
11866 c = pgetc();
11867 *++p = c;
11868 } while ((unsigned char)(c - '0') <= 7 && --cnt);
11869 pungetc();
11870 } else if (c == 'x') { /* \xHH */
11871 do {
11872 c = pgetc();
11873 *++p = c;
11874 } while (isxdigit(c) && --cnt);
11875 pungetc();
11876 if (cnt == 3) { /* \x but next char is "bad" */
11877 c = 'x';
11878 goto unrecognized;
11879 }
11880 } else { /* simple seq like \\ or \t */
11881 p++;
11882 }
11883 *p = '\0';
11884 p = buf;
11885 c = bb_process_escape_sequence((void*)&p);
11886 } else { /* unrecognized "\z": print both chars unless ' or " */
11887 if (c != '\'' && c != '"') {
11888 unrecognized:
11889 c |= 0x100; /* "please encode \, then me" */
11890 }
11891 }
11892 return c;
11893}
11894#endif
11895
Denys Vlasenko46999802017-07-29 21:12:29 +020011896/* Used by expandstr to get here-doc like behaviour. */
11897#define FAKEEOFMARK ((char*)(uintptr_t)1)
11898
11899static ALWAYS_INLINE int
11900realeofmark(const char *eofmark)
11901{
11902 return eofmark && eofmark != FAKEEOFMARK;
11903}
11904
Eric Andersencb57d552001-06-28 07:25:16 +000011905/*
11906 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
11907 * is not NULL, read a here document. In the latter case, eofmark is the
11908 * word which marks the end of the document and striptabs is true if
Denys Vlasenkocd716832009-11-28 22:14:02 +010011909 * leading tabs should be stripped from the document. The argument c
Eric Andersencb57d552001-06-28 07:25:16 +000011910 * is the first character of the input token or document.
11911 *
11912 * Because C does not have internal subroutines, I have simulated them
11913 * using goto's to implement the subroutine linkage. The following macros
11914 * will run code that appears at the end of readtoken1.
11915 */
Eric Andersen2870d962001-07-02 17:27:21 +000011916#define CHECKEND() {goto checkend; checkend_return:;}
11917#define PARSEREDIR() {goto parseredir; parseredir_return:;}
11918#define PARSESUB() {goto parsesub; parsesub_return:;}
11919#define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
11920#define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
11921#define PARSEARITH() {goto parsearith; parsearith_return:;}
Eric Andersencb57d552001-06-28 07:25:16 +000011922static int
Denys Vlasenkocd716832009-11-28 22:14:02 +010011923readtoken1(int c, int syntax, char *eofmark, int striptabs)
Manuel Novoa III 16815d42001-08-10 19:36:07 +000011924{
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011925 /* NB: syntax parameter fits into smallint */
Denys Vlasenkocd716832009-11-28 22:14:02 +010011926 /* c parameter is an unsigned char or PEOF or PEOA */
Eric Andersencb57d552001-06-28 07:25:16 +000011927 char *out;
Denys Vlasenko50e6d422016-09-30 11:35:54 +020011928 size_t len;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011929 struct nodelist *bqlist;
11930 smallint quotef;
11931 smallint dblquote;
11932 smallint oldstyle;
Denys Vlasenko0b883582016-12-23 16:49:07 +010011933 IF_FEATURE_SH_MATH(smallint prevsyntax;) /* syntax before arithmetic */
Denis Vlasenko46a53062007-09-24 18:30:02 +000011934 smallint pssyntax; /* we are expanding a prompt string */
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011935 int varnest; /* levels of variables expansion */
Denys Vlasenko0b883582016-12-23 16:49:07 +010011936 IF_FEATURE_SH_MATH(int arinest;) /* levels of arithmetic expansion */
11937 IF_FEATURE_SH_MATH(int parenlevel;) /* levels of parens in arithmetic */
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011938 int dqvarnest; /* levels of variables expansion within double quotes */
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011939 IF_BASH_DOLLAR_SQUOTE(smallint bash_dollar_squote = 0;)
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011940
Eric Andersencb57d552001-06-28 07:25:16 +000011941 bqlist = NULL;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011942 quotef = 0;
Denys Vlasenko0b883582016-12-23 16:49:07 +010011943 IF_FEATURE_SH_MATH(prevsyntax = 0;)
Denys Vlasenko5f0a75f2017-07-29 22:58:44 +020011944#if ENABLE_ASH_EXPAND_PRMT
Denis Vlasenko46a53062007-09-24 18:30:02 +000011945 pssyntax = (syntax == PSSYNTAX);
11946 if (pssyntax)
11947 syntax = DQSYNTAX;
Denys Vlasenko5f0a75f2017-07-29 22:58:44 +020011948#else
11949 pssyntax = 0; /* constant */
11950#endif
Denis Vlasenko46a53062007-09-24 18:30:02 +000011951 dblquote = (syntax == DQSYNTAX);
Eric Andersencb57d552001-06-28 07:25:16 +000011952 varnest = 0;
Denys Vlasenko0b883582016-12-23 16:49:07 +010011953 IF_FEATURE_SH_MATH(arinest = 0;)
11954 IF_FEATURE_SH_MATH(parenlevel = 0;)
Eric Andersencb57d552001-06-28 07:25:16 +000011955 dqvarnest = 0;
11956
11957 STARTSTACKSTR(out);
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011958 loop:
11959 /* For each line, until end of word */
Denys Vlasenko958581a2010-09-12 15:04:27 +020011960 CHECKEND(); /* set c to PEOF if at end of here document */
11961 for (;;) { /* until end of line or end of word */
11962 CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */
11963 switch (SIT(c, syntax)) {
11964 case CNL: /* '\n' */
11965 if (syntax == BASESYNTAX)
11966 goto endword; /* exit outer loop */
11967 USTPUTC(c, out);
Denys Vlasenkoce332a22016-10-02 23:47:34 +020011968 nlprompt();
Denys Vlasenko958581a2010-09-12 15:04:27 +020011969 c = pgetc();
11970 goto loop; /* continue outer loop */
11971 case CWORD:
11972 USTPUTC(c, out);
11973 break;
11974 case CCTL:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011975#if BASH_DOLLAR_SQUOTE
Denys Vlasenko958581a2010-09-12 15:04:27 +020011976 if (c == '\\' && bash_dollar_squote) {
11977 c = decode_dollar_squote();
Denys Vlasenko13f20912016-09-25 20:54:25 +020011978 if (c == '\0') {
11979 /* skip $'\000', $'\x00' (like bash) */
11980 break;
11981 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020011982 if (c & 0x100) {
Denys Vlasenko13f20912016-09-25 20:54:25 +020011983 /* Unknown escape. Encode as '\z' */
Denys Vlasenko958581a2010-09-12 15:04:27 +020011984 c = (unsigned char)c;
Denys Vlasenko13f20912016-09-25 20:54:25 +020011985 if (eofmark == NULL || dblquote)
11986 USTPUTC(CTLESC, out);
11987 USTPUTC('\\', out);
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011988 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020011989 }
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011990#endif
Denys Vlasenko13f20912016-09-25 20:54:25 +020011991 if (eofmark == NULL || dblquote)
11992 USTPUTC(CTLESC, out);
Denys Vlasenko958581a2010-09-12 15:04:27 +020011993 USTPUTC(c, out);
11994 break;
11995 case CBACK: /* backslash */
11996 c = pgetc_without_PEOA();
11997 if (c == PEOF) {
11998 USTPUTC(CTLESC, out);
11999 USTPUTC('\\', out);
12000 pungetc();
12001 } else if (c == '\n') {
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012002 nlprompt();
Denys Vlasenko958581a2010-09-12 15:04:27 +020012003 } else {
Denys Vlasenko5f0a75f2017-07-29 22:58:44 +020012004 if (pssyntax && c == '$') {
Eric Andersenc470f442003-07-28 09:56:35 +000012005 USTPUTC(CTLESC, out);
Eric Andersencb57d552001-06-28 07:25:16 +000012006 USTPUTC('\\', out);
Denys Vlasenko958581a2010-09-12 15:04:27 +020012007 }
Denys Vlasenko8de5b9f2018-02-13 14:43:29 +010012008 /* Backslash is retained if we are in "str"
12009 * and next char isn't dquote-special.
12010 */
Denys Vlasenko958581a2010-09-12 15:04:27 +020012011 if (dblquote
12012 && c != '\\'
12013 && c != '`'
12014 && c != '$'
12015 && (c != '"' || eofmark != NULL)
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000012016 ) {
Denys Vlasenko8de5b9f2018-02-13 14:43:29 +010012017//dash survives not doing USTPUTC(CTLESC), but merely by chance:
12018//Example: "\z" gets encoded as "\<CTLESC>z".
12019//rmescapes() then emits "\", "\z", protecting z from globbing.
12020//But it's wrong, should protect _both_ from globbing:
12021//everything in double quotes is not globbed.
12022//Unlike dash, we have a fix in rmescapes() which emits bare "z"
12023//for "<CTLESC>z" since "z" is not glob-special (else unicode may break),
12024//and glob would see "\z" and eat "\". Thus:
12025 USTPUTC(CTLESC, out); /* protect '\' from glob */
Denys Vlasenko958581a2010-09-12 15:04:27 +020012026 USTPUTC('\\', out);
Eric Andersencb57d552001-06-28 07:25:16 +000012027 }
Ron Yorston549deab2015-05-18 09:57:51 +020012028 USTPUTC(CTLESC, out);
Denys Vlasenko0ff78a02010-08-30 15:20:07 +020012029 USTPUTC(c, out);
Denys Vlasenko958581a2010-09-12 15:04:27 +020012030 quotef = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000012031 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020012032 break;
12033 case CSQUOTE:
12034 syntax = SQSYNTAX;
12035 quotemark:
12036 if (eofmark == NULL) {
12037 USTPUTC(CTLQUOTEMARK, out);
12038 }
12039 break;
12040 case CDQUOTE:
12041 syntax = DQSYNTAX;
12042 dblquote = 1;
12043 goto quotemark;
12044 case CENDQUOTE:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010012045 IF_BASH_DOLLAR_SQUOTE(bash_dollar_squote = 0;)
Ron Yorston7e4ed262015-05-18 09:54:43 +020012046 if (eofmark != NULL && varnest == 0) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020012047 USTPUTC(c, out);
12048 } else {
12049 if (dqvarnest == 0) {
12050 syntax = BASESYNTAX;
12051 dblquote = 0;
12052 }
12053 quotef = 1;
12054 goto quotemark;
12055 }
12056 break;
12057 case CVAR: /* '$' */
12058 PARSESUB(); /* parse substitution */
12059 break;
12060 case CENDVAR: /* '}' */
12061 if (varnest > 0) {
12062 varnest--;
12063 if (dqvarnest > 0) {
12064 dqvarnest--;
12065 }
12066 c = CTLENDVAR;
12067 }
12068 USTPUTC(c, out);
12069 break;
Denys Vlasenko0b883582016-12-23 16:49:07 +010012070#if ENABLE_FEATURE_SH_MATH
Denys Vlasenko958581a2010-09-12 15:04:27 +020012071 case CLP: /* '(' in arithmetic */
12072 parenlevel++;
12073 USTPUTC(c, out);
12074 break;
12075 case CRP: /* ')' in arithmetic */
12076 if (parenlevel > 0) {
12077 parenlevel--;
12078 } else {
Denys Vlasenko459293b2016-09-29 17:58:58 +020012079 if (pgetc_eatbnl() == ')') {
Ron Yorstonad88bde2015-05-18 09:56:16 +020012080 c = CTLENDARI;
Denys Vlasenko958581a2010-09-12 15:04:27 +020012081 if (--arinest == 0) {
12082 syntax = prevsyntax;
Denys Vlasenko958581a2010-09-12 15:04:27 +020012083 }
12084 } else {
12085 /*
12086 * unbalanced parens
12087 * (don't 2nd guess - no error)
12088 */
12089 pungetc();
12090 }
12091 }
12092 USTPUTC(c, out);
12093 break;
12094#endif
12095 case CBQUOTE: /* '`' */
12096 PARSEBACKQOLD();
12097 break;
12098 case CENDFILE:
12099 goto endword; /* exit outer loop */
12100 case CIGN:
12101 break;
12102 default:
12103 if (varnest == 0) {
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010012104#if BASH_REDIR_OUTPUT
Denys Vlasenko958581a2010-09-12 15:04:27 +020012105 if (c == '&') {
Denys Vlasenko459293b2016-09-29 17:58:58 +020012106//Can't call pgetc_eatbnl() here, this requires three-deep pungetc()
Denys Vlasenko958581a2010-09-12 15:04:27 +020012107 if (pgetc() == '>')
12108 c = 0x100 + '>'; /* flag &> */
12109 pungetc();
12110 }
12111#endif
12112 goto endword; /* exit outer loop */
12113 }
12114 IF_ASH_ALIAS(if (c != PEOA))
12115 USTPUTC(c, out);
12116 }
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020012117 c = pgetc();
Denys Vlasenko958581a2010-09-12 15:04:27 +020012118 } /* for (;;) */
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000012119 endword:
Denys Vlasenko958581a2010-09-12 15:04:27 +020012120
Denys Vlasenko0b883582016-12-23 16:49:07 +010012121#if ENABLE_FEATURE_SH_MATH
Eric Andersencb57d552001-06-28 07:25:16 +000012122 if (syntax == ARISYNTAX)
Denis Vlasenko559691a2008-10-05 18:39:31 +000012123 raise_error_syntax("missing '))'");
Eric Andersenc470f442003-07-28 09:56:35 +000012124#endif
Ron Yorston0e056f72015-07-01 16:45:40 +010012125 if (syntax != BASESYNTAX && eofmark == NULL)
Denis Vlasenko559691a2008-10-05 18:39:31 +000012126 raise_error_syntax("unterminated quoted string");
Eric Andersencb57d552001-06-28 07:25:16 +000012127 if (varnest != 0) {
Eric Andersenc470f442003-07-28 09:56:35 +000012128 /* { */
Denis Vlasenko559691a2008-10-05 18:39:31 +000012129 raise_error_syntax("missing '}'");
Eric Andersencb57d552001-06-28 07:25:16 +000012130 }
12131 USTPUTC('\0', out);
Eric Andersenc470f442003-07-28 09:56:35 +000012132 len = out - (char *)stackblock();
Eric Andersencb57d552001-06-28 07:25:16 +000012133 out = stackblock();
12134 if (eofmark == NULL) {
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010012135 if ((c == '>' || c == '<' IF_BASH_REDIR_OUTPUT( || c == 0x100 + '>'))
Denis Vlasenko834dee72008-10-07 09:18:30 +000012136 && quotef == 0
12137 ) {
Denis Vlasenko559691a2008-10-05 18:39:31 +000012138 if (isdigit_str9(out)) {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000012139 PARSEREDIR(); /* passed as params: out, c */
12140 lasttoken = TREDIR;
12141 return lasttoken;
12142 }
12143 /* else: non-number X seen, interpret it
12144 * as "NNNX>file" = "NNNX >file" */
Eric Andersencb57d552001-06-28 07:25:16 +000012145 }
Denis Vlasenkoef527f52008-06-23 01:52:30 +000012146 pungetc();
Eric Andersencb57d552001-06-28 07:25:16 +000012147 }
12148 quoteflag = quotef;
12149 backquotelist = bqlist;
12150 grabstackblock(len);
12151 wordtext = out;
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000012152 lasttoken = TWORD;
12153 return lasttoken;
Eric Andersencb57d552001-06-28 07:25:16 +000012154/* end of readtoken routine */
12155
Eric Andersencb57d552001-06-28 07:25:16 +000012156/*
12157 * Check to see whether we are at the end of the here document. When this
12158 * is called, c is set to the first character of the next input line. If
12159 * we are at the end of the here document, this routine sets the c to PEOF.
12160 */
Eric Andersenc470f442003-07-28 09:56:35 +000012161checkend: {
Denys Vlasenko46999802017-07-29 21:12:29 +020012162 if (realeofmark(eofmark)) {
Denys Vlasenkoa7328982017-07-29 19:57:28 +020012163 int markloc;
12164 char *p;
12165
Denis Vlasenko131ae172007-02-18 13:00:19 +000012166#if ENABLE_ASH_ALIAS
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010012167 if (c == PEOA)
12168 c = pgetc_without_PEOA();
Eric Andersenc470f442003-07-28 09:56:35 +000012169#endif
12170 if (striptabs) {
12171 while (c == '\t') {
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010012172 c = pgetc_without_PEOA();
Eric Andersencb57d552001-06-28 07:25:16 +000012173 }
Eric Andersenc470f442003-07-28 09:56:35 +000012174 }
Eric Andersencb57d552001-06-28 07:25:16 +000012175
Denys Vlasenkoa7328982017-07-29 19:57:28 +020012176 markloc = out - (char *)stackblock();
12177 for (p = eofmark; STPUTC(c, out), *p; p++) {
12178 if (c != *p)
12179 goto more_heredoc;
12180
12181 c = pgetc_without_PEOA();
12182 }
12183
12184 if (c == '\n' || c == PEOF) {
12185 c = PEOF;
12186 g_parsefile->linno++;
12187 needprompt = doprompt;
12188 } else {
12189 int len_here;
12190
12191 more_heredoc:
12192 p = (char *)stackblock() + markloc + 1;
12193 len_here = out - p;
12194
12195 if (len_here) {
12196 len_here -= (c >= PEOF);
12197 c = p[-1];
12198
12199 if (len_here) {
12200 char *str;
12201
12202 str = alloca(len_here + 1);
12203 *(char *)mempcpy(str, p, len_here) = '\0';
12204
12205 pushstring(str, NULL);
Eric Andersencb57d552001-06-28 07:25:16 +000012206 }
12207 }
12208 }
Denys Vlasenkoa7328982017-07-29 19:57:28 +020012209
12210 STADJUST((char *)stackblock() + markloc - out, out);
Eric Andersencb57d552001-06-28 07:25:16 +000012211 }
Eric Andersenc470f442003-07-28 09:56:35 +000012212 goto checkend_return;
12213}
Eric Andersencb57d552001-06-28 07:25:16 +000012214
Eric Andersencb57d552001-06-28 07:25:16 +000012215/*
12216 * Parse a redirection operator. The variable "out" points to a string
12217 * specifying the fd to be redirected. The variable "c" contains the
12218 * first character of the redirection operator.
12219 */
Eric Andersenc470f442003-07-28 09:56:35 +000012220parseredir: {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000012221 /* out is already checked to be a valid number or "" */
12222 int fd = (*out == '\0' ? -1 : atoi(out));
Eric Andersenc470f442003-07-28 09:56:35 +000012223 union node *np;
Eric Andersencb57d552001-06-28 07:25:16 +000012224
Denis Vlasenko597906c2008-02-20 16:38:54 +000012225 np = stzalloc(sizeof(struct nfile));
Eric Andersenc470f442003-07-28 09:56:35 +000012226 if (c == '>') {
12227 np->nfile.fd = 1;
Denys Vlasenko220be532018-03-31 19:21:31 +020012228 c = pgetc_eatbnl();
Eric Andersenc470f442003-07-28 09:56:35 +000012229 if (c == '>')
12230 np->type = NAPPEND;
12231 else if (c == '|')
12232 np->type = NCLOBBER;
12233 else if (c == '&')
12234 np->type = NTOFD;
Denis Vlasenko559691a2008-10-05 18:39:31 +000012235 /* it also can be NTO2 (>&file), but we can't figure it out yet */
Eric Andersenc470f442003-07-28 09:56:35 +000012236 else {
12237 np->type = NTO;
12238 pungetc();
Eric Andersencb57d552001-06-28 07:25:16 +000012239 }
Denis Vlasenko834dee72008-10-07 09:18:30 +000012240 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010012241#if BASH_REDIR_OUTPUT
Denis Vlasenko834dee72008-10-07 09:18:30 +000012242 else if (c == 0x100 + '>') { /* this flags &> redirection */
12243 np->nfile.fd = 1;
12244 pgetc(); /* this is '>', no need to check */
12245 np->type = NTO2;
12246 }
12247#endif
12248 else { /* c == '<' */
Denis Vlasenko597906c2008-02-20 16:38:54 +000012249 /*np->nfile.fd = 0; - stzalloc did it */
Denys Vlasenko220be532018-03-31 19:21:31 +020012250 c = pgetc_eatbnl();
Denis Vlasenko5cedb752007-02-18 19:56:41 +000012251 switch (c) {
Eric Andersenc470f442003-07-28 09:56:35 +000012252 case '<':
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000012253 if (sizeof(struct nfile) != sizeof(struct nhere)) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000012254 np = stzalloc(sizeof(struct nhere));
12255 /*np->nfile.fd = 0; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000012256 }
12257 np->type = NHERE;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000012258 heredoc = stzalloc(sizeof(struct heredoc));
Eric Andersenc470f442003-07-28 09:56:35 +000012259 heredoc->here = np;
Denys Vlasenko220be532018-03-31 19:21:31 +020012260 c = pgetc_eatbnl();
Denis Vlasenko5cedb752007-02-18 19:56:41 +000012261 if (c == '-') {
Eric Andersenc470f442003-07-28 09:56:35 +000012262 heredoc->striptabs = 1;
12263 } else {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000012264 /*heredoc->striptabs = 0; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000012265 pungetc();
12266 }
12267 break;
12268
12269 case '&':
12270 np->type = NFROMFD;
12271 break;
12272
12273 case '>':
12274 np->type = NFROMTO;
12275 break;
12276
12277 default:
12278 np->type = NFROM;
12279 pungetc();
12280 break;
12281 }
Eric Andersencb57d552001-06-28 07:25:16 +000012282 }
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000012283 if (fd >= 0)
12284 np->nfile.fd = fd;
Eric Andersenc470f442003-07-28 09:56:35 +000012285 redirnode = np;
12286 goto parseredir_return;
12287}
Eric Andersencb57d552001-06-28 07:25:16 +000012288
Eric Andersencb57d552001-06-28 07:25:16 +000012289/*
12290 * Parse a substitution. At this point, we have read the dollar sign
12291 * and nothing else.
12292 */
Denis Vlasenkocc571512007-02-23 21:10:35 +000012293
12294/* is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise
12295 * (assuming ascii char codes, as the original implementation did) */
12296#define is_special(c) \
Denis Vlasenkoef527f52008-06-23 01:52:30 +000012297 (((unsigned)(c) - 33 < 32) \
12298 && ((0xc1ff920dU >> ((unsigned)(c) - 33)) & 1))
Eric Andersenc470f442003-07-28 09:56:35 +000012299parsesub: {
Denys Vlasenkocd716832009-11-28 22:14:02 +010012300 unsigned char subtype;
Eric Andersenc470f442003-07-28 09:56:35 +000012301 int typeloc;
Eric Andersencb57d552001-06-28 07:25:16 +000012302
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012303 c = pgetc_eatbnl();
Denys Vlasenkoa7328982017-07-29 19:57:28 +020012304 if ((checkkwd & CHKEOFMARK)
12305 || c > 255 /* PEOA or PEOF */
Denis Vlasenkoef527f52008-06-23 01:52:30 +000012306 || (c != '(' && c != '{' && !is_name(c) && !is_special(c))
Eric Andersenc470f442003-07-28 09:56:35 +000012307 ) {
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010012308#if BASH_DOLLAR_SQUOTE
Ron Yorston84ba50c2016-04-03 22:43:14 +010012309 if (syntax != DQSYNTAX && c == '\'')
Denis Vlasenkoef527f52008-06-23 01:52:30 +000012310 bash_dollar_squote = 1;
12311 else
12312#endif
12313 USTPUTC('$', out);
Eric Andersenc470f442003-07-28 09:56:35 +000012314 pungetc();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012315 } else if (c == '(') {
12316 /* $(command) or $((arith)) */
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012317 if (pgetc_eatbnl() == '(') {
Denys Vlasenko0b883582016-12-23 16:49:07 +010012318#if ENABLE_FEATURE_SH_MATH
Eric Andersenc470f442003-07-28 09:56:35 +000012319 PARSEARITH();
12320#else
Denys Vlasenko4f8079d2017-07-17 17:11:48 +020012321 raise_error_syntax("support for $((arith)) is disabled");
Eric Andersenc470f442003-07-28 09:56:35 +000012322#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012323 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000012324 pungetc();
12325 PARSEBACKQNEW();
12326 }
12327 } else {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012328 /* $VAR, $<specialchar>, ${...}, or PEOA/PEOF */
Eric Andersenc470f442003-07-28 09:56:35 +000012329 USTPUTC(CTLVAR, out);
12330 typeloc = out - (char *)stackblock();
Denys Vlasenko3df14102016-10-26 16:41:13 +020012331 STADJUST(1, out);
Eric Andersenc470f442003-07-28 09:56:35 +000012332 subtype = VSNORMAL;
12333 if (c == '{') {
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012334 c = pgetc_eatbnl();
Denys Vlasenkof15aa572016-10-26 15:56:53 +020012335 subtype = 0;
Eric Andersenc470f442003-07-28 09:56:35 +000012336 }
Denys Vlasenkof15aa572016-10-26 15:56:53 +020012337 varname:
Denys Vlasenko3df14102016-10-26 16:41:13 +020012338 if (is_name(c)) {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012339 /* $[{[#]]NAME[}] */
Eric Andersenc470f442003-07-28 09:56:35 +000012340 do {
12341 STPUTC(c, out);
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012342 c = pgetc_eatbnl();
Denys Vlasenko3df14102016-10-26 16:41:13 +020012343 } while (is_in_name(c));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012344 } else if (isdigit(c)) {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012345 /* $[{[#]]NUM[}] */
Eric Andersenc470f442003-07-28 09:56:35 +000012346 do {
12347 STPUTC(c, out);
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012348 c = pgetc_eatbnl();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012349 } while (isdigit(c));
Denys Vlasenko452cc1d2017-08-14 14:23:45 +020012350 } else {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012351 /* $[{[#]]<specialchar>[}] */
Denys Vlasenkof15aa572016-10-26 15:56:53 +020012352 int cc = c;
12353
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012354 c = pgetc_eatbnl();
Denys Vlasenkof15aa572016-10-26 15:56:53 +020012355 if (!subtype && cc == '#') {
12356 subtype = VSLENGTH;
12357 if (c == '_' || isalnum(c))
12358 goto varname;
12359 cc = c;
12360 c = pgetc_eatbnl();
12361 if (cc == '}' || c != '}') {
12362 pungetc();
12363 subtype = 0;
12364 c = cc;
12365 cc = '#';
12366 }
12367 }
Denys Vlasenko452cc1d2017-08-14 14:23:45 +020012368
12369 if (!is_special(cc)) {
12370 if (subtype == VSLENGTH)
12371 subtype = 0;
12372 goto badsub;
12373 }
12374
Denys Vlasenkof15aa572016-10-26 15:56:53 +020012375 USTPUTC(cc, out);
Denis Vlasenko559691a2008-10-05 18:39:31 +000012376 }
Denys Vlasenko452cc1d2017-08-14 14:23:45 +020012377
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012378 if (c != '}' && subtype == VSLENGTH) {
12379 /* ${#VAR didn't end with } */
Cristian Ionescu-Idbohrn301f5ec2009-10-05 02:07:23 +020012380 goto badsub;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012381 }
Eric Andersencb57d552001-06-28 07:25:16 +000012382
Eric Andersenc470f442003-07-28 09:56:35 +000012383 if (subtype == 0) {
Denys Vlasenkof8ddbe12016-07-25 03:56:00 +020012384 static const char types[] ALIGN1 = "}-+?=";
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012385 /* ${VAR...} but not $VAR or ${#VAR} */
12386 /* c == first char after VAR */
Eric Andersenc470f442003-07-28 09:56:35 +000012387 switch (c) {
12388 case ':':
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012389 c = pgetc_eatbnl();
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010012390#if BASH_SUBSTR
Denys Vlasenkof8ddbe12016-07-25 03:56:00 +020012391 /* This check is only needed to not misinterpret
12392 * ${VAR:-WORD}, ${VAR:+WORD}, ${VAR:=WORD}, ${VAR:?WORD}
12393 * constructs.
12394 */
12395 if (!strchr(types, c)) {
Denis Vlasenko92e13c22008-03-25 01:17:40 +000012396 subtype = VSSUBSTR;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012397 pungetc();
Denys Vlasenko88e15702016-10-26 01:55:56 +020012398 break; /* "goto badsub" is bigger (!) */
Denis Vlasenko92e13c22008-03-25 01:17:40 +000012399 }
12400#endif
Denys Vlasenko3df14102016-10-26 16:41:13 +020012401 subtype = VSNUL;
Eric Andersenc470f442003-07-28 09:56:35 +000012402 /*FALLTHROUGH*/
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012403 default: {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012404 const char *p = strchr(types, c);
Eric Andersenc470f442003-07-28 09:56:35 +000012405 if (p == NULL)
Denys Vlasenko88e15702016-10-26 01:55:56 +020012406 break;
Denys Vlasenko3df14102016-10-26 16:41:13 +020012407 subtype |= p - types + VSNORMAL;
Eric Andersenc470f442003-07-28 09:56:35 +000012408 break;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012409 }
Eric Andersenc470f442003-07-28 09:56:35 +000012410 case '%':
Denis Vlasenko92e13c22008-03-25 01:17:40 +000012411 case '#': {
12412 int cc = c;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012413 subtype = (c == '#' ? VSTRIMLEFT : VSTRIMRIGHT);
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012414 c = pgetc_eatbnl();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012415 if (c != cc)
Denys Vlasenko88e15702016-10-26 01:55:56 +020012416 goto badsub;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012417 subtype++;
Denis Vlasenko92e13c22008-03-25 01:17:40 +000012418 break;
12419 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010012420#if BASH_PATTERN_SUBST
Denis Vlasenko92e13c22008-03-25 01:17:40 +000012421 case '/':
Denys Vlasenko6040fe82010-09-12 15:03:16 +020012422 /* ${v/[/]pattern/repl} */
12423//TODO: encode pattern and repl separately.
12424// Currently ${v/$var_with_slash/repl} is horribly broken
Denis Vlasenko92e13c22008-03-25 01:17:40 +000012425 subtype = VSREPLACE;
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012426 c = pgetc_eatbnl();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012427 if (c != '/')
Denys Vlasenko88e15702016-10-26 01:55:56 +020012428 goto badsub;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012429 subtype++; /* VSREPLACEALL */
Denis Vlasenko92e13c22008-03-25 01:17:40 +000012430 break;
12431#endif
Eric Andersencb57d552001-06-28 07:25:16 +000012432 }
Eric Andersenc470f442003-07-28 09:56:35 +000012433 } else {
Denys Vlasenko88e15702016-10-26 01:55:56 +020012434 badsub:
Eric Andersenc470f442003-07-28 09:56:35 +000012435 pungetc();
12436 }
Denys Vlasenko3df14102016-10-26 16:41:13 +020012437 ((unsigned char *)stackblock())[typeloc] = subtype;
Eric Andersenc470f442003-07-28 09:56:35 +000012438 if (subtype != VSNORMAL) {
12439 varnest++;
Denys Vlasenko3df14102016-10-26 16:41:13 +020012440 if (dblquote)
Eric Andersenc470f442003-07-28 09:56:35 +000012441 dqvarnest++;
Eric Andersencb57d552001-06-28 07:25:16 +000012442 }
Denys Vlasenko88e15702016-10-26 01:55:56 +020012443 STPUTC('=', out);
Eric Andersencb57d552001-06-28 07:25:16 +000012444 }
Eric Andersenc470f442003-07-28 09:56:35 +000012445 goto parsesub_return;
12446}
Eric Andersencb57d552001-06-28 07:25:16 +000012447
Eric Andersencb57d552001-06-28 07:25:16 +000012448/*
12449 * Called to parse command substitutions. Newstyle is set if the command
12450 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
12451 * list of commands (passed by reference), and savelen is the number of
12452 * characters on the top of the stack which must be preserved.
12453 */
Eric Andersenc470f442003-07-28 09:56:35 +000012454parsebackq: {
12455 struct nodelist **nlpp;
Eric Andersenc470f442003-07-28 09:56:35 +000012456 union node *n;
Ron Yorston072fc602015-07-01 16:46:18 +010012457 char *str;
Eric Andersenc470f442003-07-28 09:56:35 +000012458 size_t savelen;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000012459 smallint saveprompt = 0;
12460
Eric Andersenc470f442003-07-28 09:56:35 +000012461 str = NULL;
12462 savelen = out - (char *)stackblock();
12463 if (savelen > 0) {
Denys Vlasenko7bc3d392016-09-17 20:53:47 +020012464 /*
12465 * FIXME: this can allocate very large block on stack and SEGV.
12466 * Example:
12467 * echo "..<100kbytes>..`true` $(true) `true` ..."
Denys Vlasenko73737592016-09-17 20:58:22 +020012468 * allocates 100kb for every command subst. With about
Denys Vlasenko7bc3d392016-09-17 20:53:47 +020012469 * a hundred command substitutions stack overflows.
12470 * With larger prepended string, SEGV happens sooner.
12471 */
Ron Yorston072fc602015-07-01 16:46:18 +010012472 str = alloca(savelen);
Eric Andersenc470f442003-07-28 09:56:35 +000012473 memcpy(str, stackblock(), savelen);
12474 }
Denys Vlasenko7bc3d392016-09-17 20:53:47 +020012475
Eric Andersenc470f442003-07-28 09:56:35 +000012476 if (oldstyle) {
12477 /* We must read until the closing backquote, giving special
Denys Vlasenko60cb48c2013-01-14 15:57:44 +010012478 * treatment to some slashes, and then push the string and
12479 * reread it as input, interpreting it normally.
12480 */
Eric Andersenc470f442003-07-28 09:56:35 +000012481 char *pout;
Eric Andersenc470f442003-07-28 09:56:35 +000012482 size_t psavelen;
12483 char *pstr;
12484
Eric Andersenc470f442003-07-28 09:56:35 +000012485 STARTSTACKSTR(pout);
12486 for (;;) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020012487 int pc;
12488
12489 setprompt_if(needprompt, 2);
Denys Vlasenko220be532018-03-31 19:21:31 +020012490 pc = pgetc_eatbnl();
Denis Vlasenko5cedb752007-02-18 19:56:41 +000012491 switch (pc) {
Eric Andersenc470f442003-07-28 09:56:35 +000012492 case '`':
12493 goto done;
12494
12495 case '\\':
Denys Vlasenko220be532018-03-31 19:21:31 +020012496 pc = pgetc(); /* or pgetc_eatbnl()? why (example)? */
Eric Andersenc470f442003-07-28 09:56:35 +000012497 if (pc != '\\' && pc != '`' && pc != '$'
Denys Vlasenko76bc2d62009-11-29 01:37:46 +010012498 && (!dblquote || pc != '"')
12499 ) {
Eric Andersenc470f442003-07-28 09:56:35 +000012500 STPUTC('\\', pout);
Denys Vlasenko76bc2d62009-11-29 01:37:46 +010012501 }
Denys Vlasenkocd716832009-11-28 22:14:02 +010012502 if (pc <= 255 /* not PEOA or PEOF */) {
Eric Andersenc470f442003-07-28 09:56:35 +000012503 break;
12504 }
12505 /* fall through */
12506
12507 case PEOF:
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010012508 IF_ASH_ALIAS(case PEOA:)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000012509 raise_error_syntax("EOF in backquote substitution");
Eric Andersenc470f442003-07-28 09:56:35 +000012510
12511 case '\n':
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012512 nlnoprompt();
Eric Andersenc470f442003-07-28 09:56:35 +000012513 break;
12514
12515 default:
12516 break;
12517 }
12518 STPUTC(pc, pout);
12519 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +000012520 done:
Eric Andersenc470f442003-07-28 09:56:35 +000012521 STPUTC('\0', pout);
12522 psavelen = pout - (char *)stackblock();
12523 if (psavelen > 0) {
12524 pstr = grabstackstr(pout);
12525 setinputstring(pstr);
12526 }
12527 }
12528 nlpp = &bqlist;
12529 while (*nlpp)
12530 nlpp = &(*nlpp)->next;
Denis Vlasenko597906c2008-02-20 16:38:54 +000012531 *nlpp = stzalloc(sizeof(**nlpp));
12532 /* (*nlpp)->next = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000012533
12534 if (oldstyle) {
12535 saveprompt = doprompt;
12536 doprompt = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000012537 }
12538
Eric Andersenc470f442003-07-28 09:56:35 +000012539 n = list(2);
12540
12541 if (oldstyle)
12542 doprompt = saveprompt;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012543 else if (readtoken() != TRP)
12544 raise_error_unexpected_syntax(TRP);
Eric Andersenc470f442003-07-28 09:56:35 +000012545
12546 (*nlpp)->n = n;
12547 if (oldstyle) {
12548 /*
12549 * Start reading from old file again, ignoring any pushed back
12550 * tokens left from the backquote parsing
12551 */
12552 popfile();
12553 tokpushback = 0;
12554 }
12555 while (stackblocksize() <= savelen)
12556 growstackblock();
12557 STARTSTACKSTR(out);
12558 if (str) {
12559 memcpy(out, str, savelen);
12560 STADJUST(savelen, out);
Eric Andersenc470f442003-07-28 09:56:35 +000012561 }
Ron Yorston549deab2015-05-18 09:57:51 +020012562 USTPUTC(CTLBACKQ, out);
Eric Andersenc470f442003-07-28 09:56:35 +000012563 if (oldstyle)
12564 goto parsebackq_oldreturn;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000012565 goto parsebackq_newreturn;
Eric Andersenc470f442003-07-28 09:56:35 +000012566}
12567
Denys Vlasenko0b883582016-12-23 16:49:07 +010012568#if ENABLE_FEATURE_SH_MATH
Eric Andersencb57d552001-06-28 07:25:16 +000012569/*
12570 * Parse an arithmetic expansion (indicate start of one and set state)
12571 */
Eric Andersenc470f442003-07-28 09:56:35 +000012572parsearith: {
Eric Andersenc470f442003-07-28 09:56:35 +000012573 if (++arinest == 1) {
12574 prevsyntax = syntax;
12575 syntax = ARISYNTAX;
Eric Andersencb57d552001-06-28 07:25:16 +000012576 }
Ron Yorstonad88bde2015-05-18 09:56:16 +020012577 USTPUTC(CTLARI, out);
Eric Andersenc470f442003-07-28 09:56:35 +000012578 goto parsearith_return;
12579}
12580#endif
Eric Andersenc470f442003-07-28 09:56:35 +000012581} /* end of readtoken */
12582
Eric Andersencb57d552001-06-28 07:25:16 +000012583/*
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012584 * Read the next input token.
12585 * If the token is a word, we set backquotelist to the list of cmds in
12586 * backquotes. We set quoteflag to true if any part of the word was
12587 * quoted.
12588 * If the token is TREDIR, then we set redirnode to a structure containing
12589 * the redirection.
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012590 *
12591 * [Change comment: here documents and internal procedures]
12592 * [Readtoken shouldn't have any arguments. Perhaps we should make the
12593 * word parsing code into a separate routine. In this case, readtoken
12594 * doesn't need to have any internal procedures, but parseword does.
12595 * We could also make parseoperator in essence the main routine, and
12596 * have parseword (readtoken1?) handle both words and redirection.]
Eric Andersencb57d552001-06-28 07:25:16 +000012597 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012598#define NEW_xxreadtoken
12599#ifdef NEW_xxreadtoken
12600/* singles must be first! */
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000012601static const char xxreadtoken_chars[7] ALIGN1 = {
Denis Vlasenko834dee72008-10-07 09:18:30 +000012602 '\n', '(', ')', /* singles */
12603 '&', '|', ';', /* doubles */
12604 0
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000012605};
Eric Andersencb57d552001-06-28 07:25:16 +000012606
Denis Vlasenko834dee72008-10-07 09:18:30 +000012607#define xxreadtoken_singles 3
12608#define xxreadtoken_doubles 3
12609
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000012610static const char xxreadtoken_tokens[] ALIGN1 = {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012611 TNL, TLP, TRP, /* only single occurrence allowed */
12612 TBACKGND, TPIPE, TSEMI, /* if single occurrence */
12613 TEOF, /* corresponds to trailing nul */
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000012614 TAND, TOR, TENDCASE /* if double occurrence */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012615};
12616
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012617static int
12618xxreadtoken(void)
12619{
12620 int c;
12621
12622 if (tokpushback) {
12623 tokpushback = 0;
12624 return lasttoken;
Eric Andersencb57d552001-06-28 07:25:16 +000012625 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020012626 setprompt_if(needprompt, 2);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012627 for (;;) { /* until token or start of word found */
Denys Vlasenko220be532018-03-31 19:21:31 +020012628 c = pgetc_eatbnl();
Denis Vlasenko5e34ff22009-04-21 11:09:40 +000012629 if (c == ' ' || c == '\t' IF_ASH_ALIAS( || c == PEOA))
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012630 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012631
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012632 if (c == '#') {
12633 while ((c = pgetc()) != '\n' && c != PEOF)
12634 continue;
12635 pungetc();
12636 } else if (c == '\\') {
Denys Vlasenko220be532018-03-31 19:21:31 +020012637 break; /* return readtoken1(...) */
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012638 } else {
12639 const char *p;
12640
12641 p = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
12642 if (c != PEOF) {
12643 if (c == '\n') {
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012644 nlnoprompt();
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012645 }
12646
12647 p = strchr(xxreadtoken_chars, c);
Denis Vlasenko834dee72008-10-07 09:18:30 +000012648 if (p == NULL)
12649 break; /* return readtoken1(...) */
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012650
Denis Vlasenko834dee72008-10-07 09:18:30 +000012651 if ((int)(p - xxreadtoken_chars) >= xxreadtoken_singles) {
12652 int cc = pgetc();
12653 if (cc == c) { /* double occurrence? */
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012654 p += xxreadtoken_doubles + 1;
12655 } else {
12656 pungetc();
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010012657#if BASH_REDIR_OUTPUT
Denis Vlasenko834dee72008-10-07 09:18:30 +000012658 if (c == '&' && cc == '>') /* &> */
12659 break; /* return readtoken1(...) */
12660#endif
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012661 }
12662 }
12663 }
12664 lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
12665 return lasttoken;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012666 }
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012667 } /* for (;;) */
Denis Vlasenko834dee72008-10-07 09:18:30 +000012668
12669 return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012670}
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012671#else /* old xxreadtoken */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012672#define RETURN(token) return lasttoken = token
12673static int
12674xxreadtoken(void)
12675{
12676 int c;
12677
12678 if (tokpushback) {
12679 tokpushback = 0;
12680 return lasttoken;
12681 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020012682 setprompt_if(needprompt, 2);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012683 for (;;) { /* until token or start of word found */
Denys Vlasenko220be532018-03-31 19:21:31 +020012684 c = pgetc_eatbnl();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012685 switch (c) {
12686 case ' ': case '\t':
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010012687 IF_ASH_ALIAS(case PEOA:)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012688 continue;
12689 case '#':
Denis Vlasenkof7d56652008-03-25 05:51:41 +000012690 while ((c = pgetc()) != '\n' && c != PEOF)
12691 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012692 pungetc();
12693 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012694 case '\n':
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012695 nlnoprompt();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012696 RETURN(TNL);
12697 case PEOF:
12698 RETURN(TEOF);
12699 case '&':
Denys Vlasenko220be532018-03-31 19:21:31 +020012700 if (pgetc_eatbnl() == '&')
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012701 RETURN(TAND);
12702 pungetc();
12703 RETURN(TBACKGND);
12704 case '|':
Denys Vlasenko220be532018-03-31 19:21:31 +020012705 if (pgetc_eatbnl() == '|')
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012706 RETURN(TOR);
12707 pungetc();
12708 RETURN(TPIPE);
12709 case ';':
Denys Vlasenko220be532018-03-31 19:21:31 +020012710 if (pgetc_eatbnl() == ';')
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012711 RETURN(TENDCASE);
12712 pungetc();
12713 RETURN(TSEMI);
12714 case '(':
12715 RETURN(TLP);
12716 case ')':
12717 RETURN(TRP);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012718 }
Denys Vlasenko220be532018-03-31 19:21:31 +020012719 break;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012720 }
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012721 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
12722#undef RETURN
12723}
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012724#endif /* old xxreadtoken */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012725
12726static int
12727readtoken(void)
12728{
12729 int t;
Ron Yorston713f07d2015-10-29 16:44:56 +000012730 int kwd = checkkwd;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012731#if DEBUG
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000012732 smallint alreadyseen = tokpushback;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012733#endif
12734
12735#if ENABLE_ASH_ALIAS
12736 top:
12737#endif
12738
12739 t = xxreadtoken();
12740
12741 /*
12742 * eat newlines
12743 */
Ron Yorston713f07d2015-10-29 16:44:56 +000012744 if (kwd & CHKNL) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012745 while (t == TNL) {
12746 parseheredoc();
12747 t = xxreadtoken();
12748 }
12749 }
12750
12751 if (t != TWORD || quoteflag) {
12752 goto out;
12753 }
12754
12755 /*
12756 * check for keywords
12757 */
Ron Yorston713f07d2015-10-29 16:44:56 +000012758 if (kwd & CHKKWD) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012759 const char *const *pp;
12760
12761 pp = findkwd(wordtext);
12762 if (pp) {
12763 lasttoken = t = pp - tokname_array;
Denys Vlasenko888527c2016-10-02 16:54:17 +020012764 TRACE(("keyword '%s' recognized\n", tokname_array[t]));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012765 goto out;
12766 }
12767 }
12768
12769 if (checkkwd & CHKALIAS) {
12770#if ENABLE_ASH_ALIAS
12771 struct alias *ap;
12772 ap = lookupalias(wordtext, 1);
12773 if (ap != NULL) {
12774 if (*ap->val) {
12775 pushstring(ap->val, ap);
12776 }
12777 goto top;
12778 }
12779#endif
12780 }
12781 out:
12782 checkkwd = 0;
12783#if DEBUG
12784 if (!alreadyseen)
Denys Vlasenko888527c2016-10-02 16:54:17 +020012785 TRACE(("token '%s' %s\n", tokname_array[t], t == TWORD ? wordtext : ""));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012786 else
Denys Vlasenko888527c2016-10-02 16:54:17 +020012787 TRACE(("reread token '%s' %s\n", tokname_array[t], t == TWORD ? wordtext : ""));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012788#endif
12789 return t;
Eric Andersencb57d552001-06-28 07:25:16 +000012790}
12791
Ron Yorstonc0e00762015-10-29 11:30:55 +000012792static int
Ron Yorston6bd2fab2015-10-29 11:30:22 +000012793peektoken(void)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012794{
12795 int t;
12796
12797 t = readtoken();
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000012798 tokpushback = 1;
Ron Yorstonc0e00762015-10-29 11:30:55 +000012799 return t;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012800}
Eric Andersencb57d552001-06-28 07:25:16 +000012801
12802/*
Denys Vlasenko86e83ec2009-07-23 22:07:07 +020012803 * Read and parse a command. Returns NODE_EOF on end of file.
12804 * (NULL is a valid parse tree indicating a blank line.)
Eric Andersencb57d552001-06-28 07:25:16 +000012805 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012806static union node *
12807parsecmd(int interact)
Eric Andersen90898442003-08-06 11:20:52 +000012808{
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012809 tokpushback = 0;
Ron Yorstonc0e00762015-10-29 11:30:55 +000012810 checkkwd = 0;
12811 heredoclist = 0;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012812 doprompt = interact;
Denys Vlasenko958581a2010-09-12 15:04:27 +020012813 setprompt_if(doprompt, doprompt);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012814 needprompt = 0;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012815 return list(1);
12816}
12817
12818/*
12819 * Input any here documents.
12820 */
12821static void
12822parseheredoc(void)
12823{
12824 struct heredoc *here;
12825 union node *n;
12826
12827 here = heredoclist;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000012828 heredoclist = NULL;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012829
12830 while (here) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020012831 setprompt_if(needprompt, 2);
12832 readtoken1(pgetc(), here->here->type == NHERE ? SQSYNTAX : DQSYNTAX,
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012833 here->eofmark, here->striptabs);
Denis Vlasenko597906c2008-02-20 16:38:54 +000012834 n = stzalloc(sizeof(struct narg));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012835 n->narg.type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000012836 /*n->narg.next = NULL; - stzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012837 n->narg.text = wordtext;
12838 n->narg.backquote = backquotelist;
12839 here->here->nhere.doc = n;
12840 here = here->next;
Eric Andersencb57d552001-06-28 07:25:16 +000012841 }
Eric Andersencb57d552001-06-28 07:25:16 +000012842}
12843
12844
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012845static const char *
Denys Vlasenko46999802017-07-29 21:12:29 +020012846expandstr(const char *ps, int syntax_type)
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012847{
12848 union node n;
Denys Vlasenko2a6d29a2016-10-25 21:17:52 +020012849 int saveprompt;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012850
Denys Vlasenko46999802017-07-29 21:12:29 +020012851 /* XXX Fix (char *) cast. */
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012852 setinputstring((char *)ps);
Denys Vlasenko2a6d29a2016-10-25 21:17:52 +020012853
12854 saveprompt = doprompt;
12855 doprompt = 0;
Denys Vlasenkoa2e32b32017-10-12 19:20:13 +020012856
12857 /* readtoken1() might die horribly.
Denys Vlasenko3c183a82017-10-12 19:35:42 +020012858 * Try a prompt with syntactically wrong command:
Denys Vlasenkoa2e32b32017-10-12 19:20:13 +020012859 * PS1='$(date "+%H:%M:%S) > '
12860 */
12861 {
12862 volatile int saveint;
12863 struct jmploc *volatile savehandler = exception_handler;
12864 struct jmploc jmploc;
12865 SAVE_INT(saveint);
12866 if (setjmp(jmploc.loc) == 0) {
12867 exception_handler = &jmploc;
12868 readtoken1(pgetc(), syntax_type, FAKEEOFMARK, 0);
12869 }
12870 exception_handler = savehandler;
12871 RESTORE_INT(saveint);
12872 }
12873
Denys Vlasenko2a6d29a2016-10-25 21:17:52 +020012874 doprompt = saveprompt;
12875
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012876 popfile();
12877
12878 n.narg.type = NARG;
12879 n.narg.next = NULL;
12880 n.narg.text = wordtext;
12881 n.narg.backquote = backquotelist;
12882
Ron Yorston549deab2015-05-18 09:57:51 +020012883 expandarg(&n, NULL, EXP_QUOTED);
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012884 return stackblock();
12885}
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012886
Denys Vlasenko1e3e2cc2017-07-25 20:31:14 +020012887static inline int
12888parser_eof(void)
12889{
12890 return tokpushback && lasttoken == TEOF;
12891}
12892
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012893/*
12894 * Execute a command or commands contained in a string.
12895 */
12896static int
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020012897evalstring(char *s, int flags)
Eric Andersenc470f442003-07-28 09:56:35 +000012898{
Denys Vlasenko493b9ca2016-10-30 18:27:14 +010012899 struct jmploc *volatile savehandler;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012900 struct jmploc jmploc;
12901 int ex;
12902
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012903 union node *n;
12904 struct stackmark smark;
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012905 int status;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012906
Denys Vlasenko8e2bc472016-09-28 23:02:57 +020012907 s = sstrdup(s);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012908 setinputstring(s);
12909 setstackmark(&smark);
12910
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012911 status = 0;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012912 /* On exception inside execution loop, we must popfile().
12913 * Try interactively:
12914 * readonly a=a
12915 * command eval "a=b" # throws "is read only" error
12916 * "command BLTIN" is not supposed to abort (even in non-interactive use).
12917 * But if we skip popfile(), we hit EOF in eval's string, and exit.
12918 */
12919 savehandler = exception_handler;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012920 ex = setjmp(jmploc.loc);
12921 if (ex)
12922 goto out;
Denys Vlasenko493b9ca2016-10-30 18:27:14 +010012923 exception_handler = &jmploc;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012924
Denys Vlasenko86e83ec2009-07-23 22:07:07 +020012925 while ((n = parsecmd(0)) != NODE_EOF) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020012926 int i;
12927
Denys Vlasenko1e3e2cc2017-07-25 20:31:14 +020012928 i = evaltree(n, flags & ~(parser_eof() ? 0 : EV_EXIT));
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012929 if (n)
12930 status = i;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012931 popstackmark(&smark);
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012932 if (evalskip)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012933 break;
12934 }
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012935 out:
Denys Vlasenko8e2bc472016-09-28 23:02:57 +020012936 popstackmark(&smark);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012937 popfile();
Denys Vlasenko8e2bc472016-09-28 23:02:57 +020012938 stunalloc(s);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012939
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012940 exception_handler = savehandler;
12941 if (ex)
Denys Vlasenko14c85eb2017-10-12 19:40:47 +020012942 longjmp(exception_handler->loc, ex);
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012943
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012944 return status;
Eric Andersenc470f442003-07-28 09:56:35 +000012945}
12946
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012947/*
12948 * The eval command.
12949 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012950static int FAST_FUNC
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020012951evalcmd(int argc UNUSED_PARAM, char **argv, int flags)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012952{
12953 char *p;
12954 char *concat;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012955
Denis Vlasenko68404f12008-03-17 09:00:54 +000012956 if (argv[1]) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012957 p = argv[1];
Denis Vlasenko68404f12008-03-17 09:00:54 +000012958 argv += 2;
12959 if (argv[0]) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012960 STARTSTACKSTR(concat);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012961 for (;;) {
12962 concat = stack_putstr(p, concat);
Denis Vlasenko68404f12008-03-17 09:00:54 +000012963 p = *argv++;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012964 if (p == NULL)
12965 break;
12966 STPUTC(' ', concat);
12967 }
12968 STPUTC('\0', concat);
12969 p = grabstackstr(concat);
12970 }
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020012971 return evalstring(p, flags & EV_TESTED);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012972 }
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012973 return 0;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012974}
12975
12976/*
Denys Vlasenko285ad152009-12-04 23:02:27 +010012977 * Read and execute commands.
12978 * "Top" is nonzero for the top level command loop;
12979 * it turns on prompting if the shell is interactive.
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012980 */
12981static int
12982cmdloop(int top)
12983{
12984 union node *n;
12985 struct stackmark smark;
12986 int inter;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020012987 int status = 0;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012988 int numeof = 0;
12989
12990 TRACE(("cmdloop(%d) called\n", top));
12991 for (;;) {
12992 int skip;
12993
12994 setstackmark(&smark);
12995#if JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +000012996 if (doing_jobctl)
Denys Vlasenko9c541002015-10-07 15:44:36 +020012997 showjobs(SHOW_CHANGED|SHOW_STDERR);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012998#endif
12999 inter = 0;
13000 if (iflag && top) {
13001 inter++;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013002 chkmail();
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013003 }
13004 n = parsecmd(inter);
Denys Vlasenko7cee00e2009-07-24 01:08:03 +020013005#if DEBUG
13006 if (DEBUG > 2 && debug && (n != NODE_EOF))
Denys Vlasenko883cea42009-07-11 15:31:59 +020013007 showtree(n);
Denis Vlasenko135cecb2009-04-12 00:00:57 +000013008#endif
Denys Vlasenko86e83ec2009-07-23 22:07:07 +020013009 if (n == NODE_EOF) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013010 if (!top || numeof >= 50)
13011 break;
13012 if (!stoppedjobs()) {
13013 if (!Iflag)
13014 break;
13015 out2str("\nUse \"exit\" to leave shell.\n");
13016 }
13017 numeof++;
13018 } else if (nflag == 0) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020013019 int i;
13020
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +000013021 /* job_warning can only be 2,1,0. Here 2->1, 1/0->0 */
13022 job_warning >>= 1;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013023 numeof = 0;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020013024 i = evaltree(n, 0);
13025 if (n)
13026 status = i;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013027 }
13028 popstackmark(&smark);
13029 skip = evalskip;
13030
13031 if (skip) {
Denys Vlasenko6a0710e2016-09-30 14:18:34 +020013032 evalskip &= ~SKIPFUNC;
Denys Vlasenko0840c912016-10-01 15:27:44 +020013033 break;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013034 }
13035 }
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020013036 return status;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013037}
13038
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000013039/*
13040 * Take commands from a file. To be compatible we should do a path
13041 * search for the file, which is necessary to find sub-commands.
13042 */
13043static char *
13044find_dot_file(char *name)
13045{
13046 char *fullname;
13047 const char *path = pathval();
13048 struct stat statb;
13049
13050 /* don't try this for absolute or relative paths */
13051 if (strchr(name, '/'))
13052 return name;
13053
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020013054 while ((fullname = path_advance(&path, name)) != NULL) {
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000013055 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
13056 /*
13057 * Don't bother freeing here, since it will
13058 * be freed by the caller.
13059 */
13060 return fullname;
13061 }
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020013062 if (fullname != name)
13063 stunalloc(fullname);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000013064 }
Denys Vlasenko01f7b9e2018-01-26 15:15:43 +010013065 /* not found in PATH */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000013066
Denys Vlasenko01f7b9e2018-01-26 15:15:43 +010013067#if ENABLE_ASH_BASH_SOURCE_CURDIR
13068 return name;
13069#else
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000013070 ash_msg_and_raise_error("%s: not found", name);
13071 /* NOTREACHED */
Denys Vlasenko01f7b9e2018-01-26 15:15:43 +010013072#endif
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000013073}
13074
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013075static int FAST_FUNC
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020013076dotcmd(int argc_ UNUSED_PARAM, char **argv_ UNUSED_PARAM)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013077{
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020013078 /* "false; . empty_file; echo $?" should print 0, not 1: */
13079 int status = 0;
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020013080 char *fullname;
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020013081 char **argv;
Denys Vlasenkofb87d932017-01-09 08:22:06 +010013082 char *args_need_save;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013083 volatile struct shparam saveparam;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013084
Denys Vlasenko981a0562017-07-26 19:53:11 +020013085//???
13086// struct strlist *sp;
13087// for (sp = cmdenviron; sp; sp = sp->next)
13088// setvareq(ckstrdup(sp->text), VSTRFIXED | VTEXTFIXED);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013089
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020013090 nextopt(nullstr); /* handle possible "--" */
13091 argv = argptr;
13092
13093 if (!argv[0]) {
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020013094 /* bash says: "bash: .: filename argument required" */
13095 return 2; /* bash compat */
13096 }
13097
Denys Vlasenko091f8312013-03-17 14:25:22 +010013098 /* This aborts if file isn't found, which is POSIXly correct.
13099 * bash returns exitcode 1 instead.
13100 */
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020013101 fullname = find_dot_file(argv[0]);
13102 argv++;
Denys Vlasenkofb87d932017-01-09 08:22:06 +010013103 args_need_save = argv[0];
Denys Vlasenko5f7c82b2017-02-03 13:00:06 +010013104 if (args_need_save) { /* ". FILE ARGS", and ARGS are not empty */
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020013105 int argc;
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020013106 saveparam = shellparam;
13107 shellparam.malloced = 0;
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020013108 argc = 1;
13109 while (argv[argc])
13110 argc++;
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020013111 shellparam.nparam = argc;
13112 shellparam.p = argv;
13113 };
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013114
Denys Vlasenko091f8312013-03-17 14:25:22 +010013115 /* This aborts if file can't be opened, which is POSIXly correct.
13116 * bash returns exitcode 1 instead.
13117 */
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020013118 setinputfile(fullname, INPUT_PUSH_FILE);
13119 commandname = fullname;
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020013120 status = cmdloop(0);
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020013121 popfile();
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013122
Denys Vlasenkofb87d932017-01-09 08:22:06 +010013123 if (args_need_save) {
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020013124 freeparam(&shellparam);
13125 shellparam = saveparam;
13126 };
13127
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020013128 return status;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013129}
13130
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013131static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013132exitcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013133{
13134 if (stoppedjobs())
13135 return 0;
Denis Vlasenko68404f12008-03-17 09:00:54 +000013136 if (argv[1])
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013137 exitstatus = number(argv[1]);
13138 raise_exception(EXEXIT);
13139 /* NOTREACHED */
13140}
13141
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013142/*
13143 * Read a file containing shell functions.
13144 */
13145static void
13146readcmdfile(char *name)
13147{
13148 setinputfile(name, INPUT_PUSH_FILE);
13149 cmdloop(0);
13150 popfile();
13151}
13152
13153
Denis Vlasenkocc571512007-02-23 21:10:35 +000013154/* ============ find_command inplementation */
13155
13156/*
13157 * Resolve a command name. If you change this routine, you may have to
13158 * change the shellexec routine as well.
13159 */
13160static void
13161find_command(char *name, struct cmdentry *entry, int act, const char *path)
13162{
13163 struct tblentry *cmdp;
13164 int idx;
13165 int prev;
13166 char *fullname;
13167 struct stat statb;
13168 int e;
13169 int updatetbl;
13170 struct builtincmd *bcmd;
13171
13172 /* If name contains a slash, don't use PATH or hash table */
13173 if (strchr(name, '/') != NULL) {
13174 entry->u.index = -1;
13175 if (act & DO_ABS) {
13176 while (stat(name, &statb) < 0) {
13177#ifdef SYSV
13178 if (errno == EINTR)
13179 continue;
13180#endif
13181 entry->cmdtype = CMDUNKNOWN;
13182 return;
13183 }
13184 }
13185 entry->cmdtype = CMDNORMAL;
13186 return;
13187 }
13188
Denis Vlasenkof20de5b2007-04-29 23:42:54 +000013189/* #if ENABLE_FEATURE_SH_STANDALONE... moved after builtin check */
Denis Vlasenkocc571512007-02-23 21:10:35 +000013190
13191 updatetbl = (path == pathval());
13192 if (!updatetbl) {
13193 act |= DO_ALTPATH;
13194 if (strstr(path, "%builtin") != NULL)
13195 act |= DO_ALTBLTIN;
13196 }
13197
13198 /* If name is in the table, check answer will be ok */
13199 cmdp = cmdlookup(name, 0);
13200 if (cmdp != NULL) {
13201 int bit;
13202
13203 switch (cmdp->cmdtype) {
13204 default:
13205#if DEBUG
13206 abort();
13207#endif
13208 case CMDNORMAL:
13209 bit = DO_ALTPATH;
13210 break;
13211 case CMDFUNCTION:
13212 bit = DO_NOFUNC;
13213 break;
13214 case CMDBUILTIN:
13215 bit = DO_ALTBLTIN;
13216 break;
13217 }
13218 if (act & bit) {
13219 updatetbl = 0;
13220 cmdp = NULL;
13221 } else if (cmdp->rehash == 0)
13222 /* if not invalidated by cd, we're done */
13223 goto success;
13224 }
13225
13226 /* If %builtin not in path, check for builtin next */
13227 bcmd = find_builtin(name);
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000013228 if (bcmd) {
13229 if (IS_BUILTIN_REGULAR(bcmd))
13230 goto builtin_success;
13231 if (act & DO_ALTPATH) {
13232 if (!(act & DO_ALTBLTIN))
13233 goto builtin_success;
13234 } else if (builtinloc <= 0) {
13235 goto builtin_success;
Denis Vlasenko8e858e22007-03-07 09:35:43 +000013236 }
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000013237 }
Denis Vlasenkocc571512007-02-23 21:10:35 +000013238
Denis Vlasenkof20de5b2007-04-29 23:42:54 +000013239#if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko7465dbc2008-04-13 02:25:53 +000013240 {
13241 int applet_no = find_applet_by_name(name);
13242 if (applet_no >= 0) {
13243 entry->cmdtype = CMDNORMAL;
13244 entry->u.index = -2 - applet_no;
13245 return;
13246 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +000013247 }
13248#endif
13249
Denis Vlasenkocc571512007-02-23 21:10:35 +000013250 /* We have to search path. */
13251 prev = -1; /* where to start */
13252 if (cmdp && cmdp->rehash) { /* doing a rehash */
13253 if (cmdp->cmdtype == CMDBUILTIN)
13254 prev = builtinloc;
13255 else
13256 prev = cmdp->param.index;
13257 }
13258
13259 e = ENOENT;
13260 idx = -1;
13261 loop:
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020013262 while ((fullname = path_advance(&path, name)) != NULL) {
Denis Vlasenkocc571512007-02-23 21:10:35 +000013263 stunalloc(fullname);
Denis Vlasenkodee82b62007-07-29 14:05:27 +000013264 /* NB: code below will still use fullname
13265 * despite it being "unallocated" */
Denis Vlasenkocc571512007-02-23 21:10:35 +000013266 idx++;
13267 if (pathopt) {
13268 if (prefix(pathopt, "builtin")) {
13269 if (bcmd)
13270 goto builtin_success;
13271 continue;
Denis Vlasenko4a9ca132008-04-12 20:07:08 +000013272 }
13273 if ((act & DO_NOFUNC)
13274 || !prefix(pathopt, "func")
Denys Vlasenkoe4dcba12010-10-28 18:57:19 +020013275 ) { /* ignore unimplemented options */
Denis Vlasenkocc571512007-02-23 21:10:35 +000013276 continue;
13277 }
13278 }
13279 /* if rehash, don't redo absolute path names */
13280 if (fullname[0] == '/' && idx <= prev) {
13281 if (idx < prev)
13282 continue;
13283 TRACE(("searchexec \"%s\": no change\n", name));
13284 goto success;
13285 }
13286 while (stat(fullname, &statb) < 0) {
13287#ifdef SYSV
13288 if (errno == EINTR)
13289 continue;
13290#endif
13291 if (errno != ENOENT && errno != ENOTDIR)
13292 e = errno;
13293 goto loop;
13294 }
13295 e = EACCES; /* if we fail, this will be the error */
13296 if (!S_ISREG(statb.st_mode))
13297 continue;
13298 if (pathopt) { /* this is a %func directory */
13299 stalloc(strlen(fullname) + 1);
Denis Vlasenkodee82b62007-07-29 14:05:27 +000013300 /* NB: stalloc will return space pointed by fullname
13301 * (because we don't have any intervening allocations
13302 * between stunalloc above and this stalloc) */
Denis Vlasenkocc571512007-02-23 21:10:35 +000013303 readcmdfile(fullname);
13304 cmdp = cmdlookup(name, 0);
13305 if (cmdp == NULL || cmdp->cmdtype != CMDFUNCTION)
13306 ash_msg_and_raise_error("%s not defined in %s", name, fullname);
13307 stunalloc(fullname);
13308 goto success;
13309 }
13310 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
13311 if (!updatetbl) {
13312 entry->cmdtype = CMDNORMAL;
13313 entry->u.index = idx;
13314 return;
13315 }
13316 INT_OFF;
13317 cmdp = cmdlookup(name, 1);
13318 cmdp->cmdtype = CMDNORMAL;
13319 cmdp->param.index = idx;
13320 INT_ON;
13321 goto success;
13322 }
13323
13324 /* We failed. If there was an entry for this command, delete it */
13325 if (cmdp && updatetbl)
13326 delete_cmd_entry();
William Pitcockd8fd88a2018-01-24 18:33:18 +010013327 if (act & DO_ERR) {
13328#if ENABLE_ASH_BASH_NOT_FOUND_HOOK
13329 struct tblentry *hookp = cmdlookup("command_not_found_handle", 0);
13330 if (hookp && hookp->cmdtype == CMDFUNCTION) {
13331 char *argv[3];
13332 argv[0] = (char*) "command_not_found_handle";
13333 argv[1] = name;
13334 argv[2] = NULL;
13335 evalfun(hookp->param.func, 2, argv, 0);
13336 entry->cmdtype = CMDUNKNOWN;
13337 return;
13338 }
13339#endif
Denis Vlasenkocc571512007-02-23 21:10:35 +000013340 ash_msg("%s: %s", name, errmsg(e, "not found"));
William Pitcockd8fd88a2018-01-24 18:33:18 +010013341 }
Denis Vlasenkocc571512007-02-23 21:10:35 +000013342 entry->cmdtype = CMDUNKNOWN;
13343 return;
13344
13345 builtin_success:
13346 if (!updatetbl) {
13347 entry->cmdtype = CMDBUILTIN;
13348 entry->u.cmd = bcmd;
13349 return;
13350 }
13351 INT_OFF;
13352 cmdp = cmdlookup(name, 1);
13353 cmdp->cmdtype = CMDBUILTIN;
13354 cmdp->param.cmd = bcmd;
13355 INT_ON;
13356 success:
13357 cmdp->rehash = 0;
13358 entry->cmdtype = cmdp->cmdtype;
13359 entry->u = cmdp->param;
13360}
13361
13362
Eric Andersencb57d552001-06-28 07:25:16 +000013363/*
Eric Andersencb57d552001-06-28 07:25:16 +000013364 * The trap builtin.
13365 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013366static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013367trapcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +000013368{
13369 char *action;
13370 char **ap;
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010013371 int signo, exitcode;
Eric Andersencb57d552001-06-28 07:25:16 +000013372
Eric Andersenc470f442003-07-28 09:56:35 +000013373 nextopt(nullstr);
13374 ap = argptr;
13375 if (!*ap) {
Denis Vlasenko2da584f2007-02-19 22:44:05 +000013376 for (signo = 0; signo < NSIG; signo++) {
Denys Vlasenko21d87d42009-09-25 00:06:51 +020013377 char *tr = trap_ptr[signo];
13378 if (tr) {
Denys Vlasenkoe74aaf92009-09-27 02:05:45 +020013379 /* note: bash adds "SIG", but only if invoked
13380 * as "bash". If called as "sh", or if set -o posix,
13381 * then it prints short signal names.
13382 * We are printing short names: */
13383 out1fmt("trap -- %s %s\n",
Denys Vlasenko21d87d42009-09-25 00:06:51 +020013384 single_quote(tr),
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +000013385 get_signame(signo));
Denys Vlasenko726e1a02009-09-25 02:58:20 +020013386 /* trap_ptr != trap only if we are in special-cased `trap` code.
13387 * In this case, we will exit very soon, no need to free(). */
Denys Vlasenkoe74aaf92009-09-27 02:05:45 +020013388 /* if (trap_ptr != trap && tp[0]) */
Denys Vlasenko726e1a02009-09-25 02:58:20 +020013389 /* free(tr); */
Eric Andersencb57d552001-06-28 07:25:16 +000013390 }
13391 }
Denys Vlasenko726e1a02009-09-25 02:58:20 +020013392 /*
Denys Vlasenko21d87d42009-09-25 00:06:51 +020013393 if (trap_ptr != trap) {
13394 free(trap_ptr);
13395 trap_ptr = trap;
13396 }
Denys Vlasenko726e1a02009-09-25 02:58:20 +020013397 */
Eric Andersencb57d552001-06-28 07:25:16 +000013398 return 0;
13399 }
Denys Vlasenko21d87d42009-09-25 00:06:51 +020013400
Denys Vlasenko86981e32017-07-25 20:06:17 +020013401 /* Why the second check?
13402 * "trap NUM [sig2]..." is the same as "trap - NUM [sig2]..."
13403 * In this case, NUM is signal no, not an action.
13404 */
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +000013405 action = NULL;
Denys Vlasenko86981e32017-07-25 20:06:17 +020013406 if (ap[1] && !is_number(ap[0]))
Eric Andersencb57d552001-06-28 07:25:16 +000013407 action = *ap++;
Denys Vlasenko86981e32017-07-25 20:06:17 +020013408
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010013409 exitcode = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000013410 while (*ap) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000013411 signo = get_signum(*ap);
Denys Vlasenko86981e32017-07-25 20:06:17 +020013412 if (signo < 0) {
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010013413 /* Mimic bash message exactly */
13414 ash_msg("%s: invalid signal specification", *ap);
13415 exitcode = 1;
13416 goto next;
13417 }
Denis Vlasenkob012b102007-02-19 22:43:01 +000013418 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +000013419 if (action) {
Denis Vlasenko9f739442006-12-16 23:49:13 +000013420 if (LONE_DASH(action))
Eric Andersencb57d552001-06-28 07:25:16 +000013421 action = NULL;
Denys Vlasenkob4f51d32016-10-27 12:55:09 +020013422 else {
13423 if (action[0]) /* not NULL and not "" and not "-" */
13424 may_have_traps = 1;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013425 action = ckstrdup(action);
Denys Vlasenkob4f51d32016-10-27 12:55:09 +020013426 }
Eric Andersencb57d552001-06-28 07:25:16 +000013427 }
Denis Vlasenko60818682007-09-28 22:07:23 +000013428 free(trap[signo]);
Eric Andersencb57d552001-06-28 07:25:16 +000013429 trap[signo] = action;
13430 if (signo != 0)
13431 setsignal(signo);
Denis Vlasenkob012b102007-02-19 22:43:01 +000013432 INT_ON;
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010013433 next:
Eric Andersencb57d552001-06-28 07:25:16 +000013434 ap++;
13435 }
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010013436 return exitcode;
Eric Andersencb57d552001-06-28 07:25:16 +000013437}
13438
Eric Andersenc470f442003-07-28 09:56:35 +000013439
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013440/* ============ Builtins */
Eric Andersenc470f442003-07-28 09:56:35 +000013441
Denys Vlasenko2ec34962014-09-08 16:52:39 +020013442#if ENABLE_ASH_HELP
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013443static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013444helpcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000013445{
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000013446 unsigned col;
13447 unsigned i;
Eric Andersenc470f442003-07-28 09:56:35 +000013448
Denys Vlasenkod6b05eb2009-06-06 20:59:55 +020013449 out1fmt(
Denis Vlasenko34d4d892009-04-04 20:24:37 +000013450 "Built-in commands:\n"
13451 "------------------\n");
Denis Vlasenkob71c6682007-07-21 15:08:09 +000013452 for (col = 0, i = 0; i < ARRAY_SIZE(builtintab); i++) {
Eric Andersenc470f442003-07-28 09:56:35 +000013453 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
Denis Vlasenko52764022007-02-24 13:42:56 +000013454 builtintab[i].name + 1);
Eric Andersenc470f442003-07-28 09:56:35 +000013455 if (col > 60) {
13456 out1fmt("\n");
13457 col = 0;
13458 }
13459 }
Denys Vlasenko2ec34962014-09-08 16:52:39 +020013460# if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko1aa7e472007-11-28 06:49:03 +000013461 {
13462 const char *a = applet_names;
13463 while (*a) {
13464 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), a);
13465 if (col > 60) {
13466 out1fmt("\n");
13467 col = 0;
13468 }
Ron Yorston2b919582016-04-08 11:57:20 +010013469 while (*a++ != '\0')
13470 continue;
Eric Andersenc470f442003-07-28 09:56:35 +000013471 }
13472 }
Denys Vlasenko2ec34962014-09-08 16:52:39 +020013473# endif
Denys Vlasenkoebedb942016-10-02 18:45:09 +020013474 newline_and_flush(stdout);
Eric Andersenc470f442003-07-28 09:56:35 +000013475 return EXIT_SUCCESS;
13476}
Denys Vlasenko2ec34962014-09-08 16:52:39 +020013477#endif
Eric Andersenc470f442003-07-28 09:56:35 +000013478
Flemming Madsend96ffda2013-04-07 18:47:24 +020013479#if MAX_HISTORY
13480static int FAST_FUNC
13481historycmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
13482{
13483 show_history(line_input_state);
13484 return EXIT_SUCCESS;
13485}
13486#endif
13487
Eric Andersencb57d552001-06-28 07:25:16 +000013488/*
Eric Andersencb57d552001-06-28 07:25:16 +000013489 * The export and readonly commands.
13490 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013491static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013492exportcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000013493{
13494 struct var *vp;
13495 char *name;
13496 const char *p;
Eric Andersenc470f442003-07-28 09:56:35 +000013497 char **aptr;
Denys Vlasenkod5275882012-10-01 13:41:17 +020013498 char opt;
13499 int flag;
13500 int flag_off;
Eric Andersencb57d552001-06-28 07:25:16 +000013501
Denys Vlasenkod5275882012-10-01 13:41:17 +020013502 /* "readonly" in bash accepts, but ignores -n.
13503 * We do the same: it saves a conditional in nextopt's param.
13504 */
13505 flag_off = 0;
13506 while ((opt = nextopt("np")) != '\0') {
13507 if (opt == 'n')
13508 flag_off = VEXPORT;
13509 }
13510 flag = VEXPORT;
13511 if (argv[0][0] == 'r') {
13512 flag = VREADONLY;
13513 flag_off = 0; /* readonly ignores -n */
13514 }
13515 flag_off = ~flag_off;
13516
Denys Vlasenko10ad6222017-04-17 16:13:32 +020013517 /*if (opt_p_not_specified) - bash doesn't check this. Try "export -p NAME" */
Denys Vlasenkod5275882012-10-01 13:41:17 +020013518 {
Denis Vlasenko2da584f2007-02-19 22:44:05 +000013519 aptr = argptr;
13520 name = *aptr;
13521 if (name) {
13522 do {
13523 p = strchr(name, '=');
13524 if (p != NULL) {
13525 p++;
13526 } else {
13527 vp = *findvar(hashvar(name), name);
13528 if (vp) {
Denys Vlasenkod5275882012-10-01 13:41:17 +020013529 vp->flags = ((vp->flags | flag) & flag_off);
Denis Vlasenko2da584f2007-02-19 22:44:05 +000013530 continue;
13531 }
Eric Andersencb57d552001-06-28 07:25:16 +000013532 }
Denys Vlasenkod5275882012-10-01 13:41:17 +020013533 setvar(name, p, (flag & flag_off));
Denis Vlasenko2da584f2007-02-19 22:44:05 +000013534 } while ((name = *++aptr) != NULL);
13535 return 0;
13536 }
Eric Andersencb57d552001-06-28 07:25:16 +000013537 }
Denys Vlasenkod5275882012-10-01 13:41:17 +020013538
13539 /* No arguments. Show the list of exported or readonly vars.
13540 * -n is ignored.
13541 */
Denis Vlasenko2da584f2007-02-19 22:44:05 +000013542 showvars(argv[0], flag, 0);
Eric Andersencb57d552001-06-28 07:25:16 +000013543 return 0;
13544}
13545
Eric Andersencb57d552001-06-28 07:25:16 +000013546/*
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000013547 * Delete a function if it exists.
Eric Andersencb57d552001-06-28 07:25:16 +000013548 */
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +000013549static void
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000013550unsetfunc(const char *name)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000013551{
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000013552 struct tblentry *cmdp;
Eric Andersencb57d552001-06-28 07:25:16 +000013553
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000013554 cmdp = cmdlookup(name, 0);
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020013555 if (cmdp != NULL && cmdp->cmdtype == CMDFUNCTION)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000013556 delete_cmd_entry();
Eric Andersenc470f442003-07-28 09:56:35 +000013557}
13558
Eric Andersencb57d552001-06-28 07:25:16 +000013559/*
Eric Andersencb57d552001-06-28 07:25:16 +000013560 * The unset builtin command. We unset the function before we unset the
13561 * variable to allow a function to be unset when there is a readonly variable
13562 * with the same name.
13563 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013564static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013565unsetcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +000013566{
13567 char **ap;
13568 int i;
Eric Andersenc470f442003-07-28 09:56:35 +000013569 int flag = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000013570
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020013571 while ((i = nextopt("vf")) != 0) {
Eric Andersenc470f442003-07-28 09:56:35 +000013572 flag = i;
Eric Andersencb57d552001-06-28 07:25:16 +000013573 }
Eric Andersencb57d552001-06-28 07:25:16 +000013574
Denis Vlasenko2da584f2007-02-19 22:44:05 +000013575 for (ap = argptr; *ap; ap++) {
Eric Andersenc470f442003-07-28 09:56:35 +000013576 if (flag != 'f') {
Denys Vlasenkob28d4c32017-07-25 16:29:36 +020013577 unsetvar(*ap);
13578 continue;
Eric Andersenc470f442003-07-28 09:56:35 +000013579 }
13580 if (flag != 'v')
Eric Andersencb57d552001-06-28 07:25:16 +000013581 unsetfunc(*ap);
Eric Andersencb57d552001-06-28 07:25:16 +000013582 }
Denys Vlasenkob28d4c32017-07-25 16:29:36 +020013583 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +000013584}
13585
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000013586static const unsigned char timescmd_str[] ALIGN1 = {
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013587 ' ', offsetof(struct tms, tms_utime),
13588 '\n', offsetof(struct tms, tms_stime),
13589 ' ', offsetof(struct tms, tms_cutime),
13590 '\n', offsetof(struct tms, tms_cstime),
13591 0
13592};
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013593static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013594timescmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013595{
Denys Vlasenko11f2e992017-08-10 16:34:03 +020013596 unsigned clk_tck;
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013597 const unsigned char *p;
13598 struct tms buf;
13599
Bartosz Golaszewski5d2e4092014-06-22 14:01:13 +020013600 clk_tck = bb_clk_tck();
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013601
Denys Vlasenko11f2e992017-08-10 16:34:03 +020013602 times(&buf);
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013603 p = timescmd_str;
13604 do {
Denys Vlasenko11f2e992017-08-10 16:34:03 +020013605 unsigned sec, frac;
13606 unsigned long t;
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013607 t = *(clock_t *)(((char *) &buf) + p[1]);
Denys Vlasenko11f2e992017-08-10 16:34:03 +020013608 sec = t / clk_tck;
13609 frac = t % clk_tck;
13610 out1fmt("%um%u.%03us%c",
13611 sec / 60, sec % 60,
13612 (frac * 1000) / clk_tck,
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013613 p[0]);
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020013614 p += 2;
13615 } while (*p);
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013616
Eric Andersencb57d552001-06-28 07:25:16 +000013617 return 0;
13618}
13619
Denys Vlasenko0b883582016-12-23 16:49:07 +010013620#if ENABLE_FEATURE_SH_MATH
Eric Andersenc470f442003-07-28 09:56:35 +000013621/*
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020013622 * The let builtin. Partially stolen from GNU Bash, the Bourne Again SHell.
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +000013623 * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
Eric Andersen90898442003-08-06 11:20:52 +000013624 *
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +000013625 * Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
Eric Andersenc470f442003-07-28 09:56:35 +000013626 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013627static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013628letcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersenc470f442003-07-28 09:56:35 +000013629{
Denis Vlasenko68404f12008-03-17 09:00:54 +000013630 arith_t i;
Eric Andersenc470f442003-07-28 09:56:35 +000013631
Denis Vlasenko68404f12008-03-17 09:00:54 +000013632 argv++;
13633 if (!*argv)
Denis Vlasenkob012b102007-02-19 22:43:01 +000013634 ash_msg_and_raise_error("expression expected");
Denis Vlasenko68404f12008-03-17 09:00:54 +000013635 do {
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +000013636 i = ash_arith(*argv);
Denis Vlasenko68404f12008-03-17 09:00:54 +000013637 } while (*++argv);
Eric Andersenc470f442003-07-28 09:56:35 +000013638
Denis Vlasenkod9e15f22006-11-27 16:49:55 +000013639 return !i;
Eric Andersenc470f442003-07-28 09:56:35 +000013640}
Eric Andersenc470f442003-07-28 09:56:35 +000013641#endif
Eric Andersen74bcd162001-07-30 21:41:37 +000013642
Eric Andersenc470f442003-07-28 09:56:35 +000013643/*
Denis Vlasenko59f351c2008-03-25 00:07:12 +000013644 * The read builtin. Options:
13645 * -r Do not interpret '\' specially
13646 * -s Turn off echo (tty only)
13647 * -n NCHARS Read NCHARS max
13648 * -p PROMPT Display PROMPT on stderr (if input is from tty)
13649 * -t SECONDS Timeout after SECONDS (tty or pipe only)
13650 * -u FD Read from given FD instead of fd 0
Johannes Schindelin3bef5d82017-08-08 16:46:39 +020013651 * -d DELIM End on DELIM char, not newline
Eric Andersenc470f442003-07-28 09:56:35 +000013652 * This uses unbuffered input, which may be avoidable in some cases.
Denis Vlasenko59f351c2008-03-25 00:07:12 +000013653 * TODO: bash also has:
13654 * -a ARRAY Read into array[0],[1],etc
Denis Vlasenko59f351c2008-03-25 00:07:12 +000013655 * -e Use line editing (tty only)
Eric Andersenc470f442003-07-28 09:56:35 +000013656 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013657static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013658readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000013659{
Denys Vlasenko73067272010-01-12 22:11:24 +010013660 char *opt_n = NULL;
13661 char *opt_p = NULL;
13662 char *opt_t = NULL;
13663 char *opt_u = NULL;
Johannes Schindelin3bef5d82017-08-08 16:46:39 +020013664 char *opt_d = NULL; /* optimized out if !BASH */
Denys Vlasenko73067272010-01-12 22:11:24 +010013665 int read_flags = 0;
13666 const char *r;
Eric Andersenc470f442003-07-28 09:56:35 +000013667 int i;
13668
Johannes Schindelin3bef5d82017-08-08 16:46:39 +020013669 while ((i = nextopt("p:u:rt:n:sd:")) != '\0') {
Denis Vlasenkobf0a2012006-12-26 10:42:51 +000013670 switch (i) {
Paul Fox02eb9342005-09-07 16:56:02 +000013671 case 'p':
Denys Vlasenko73067272010-01-12 22:11:24 +010013672 opt_p = optionarg;
Paul Fox02eb9342005-09-07 16:56:02 +000013673 break;
Paul Fox02eb9342005-09-07 16:56:02 +000013674 case 'n':
Denys Vlasenko73067272010-01-12 22:11:24 +010013675 opt_n = optionarg;
Paul Fox02eb9342005-09-07 16:56:02 +000013676 break;
13677 case 's':
Denys Vlasenko73067272010-01-12 22:11:24 +010013678 read_flags |= BUILTIN_READ_SILENT;
Paul Fox02eb9342005-09-07 16:56:02 +000013679 break;
Paul Fox02eb9342005-09-07 16:56:02 +000013680 case 't':
Denys Vlasenko73067272010-01-12 22:11:24 +010013681 opt_t = optionarg;
Paul Fox02eb9342005-09-07 16:56:02 +000013682 break;
Paul Fox02eb9342005-09-07 16:56:02 +000013683 case 'r':
Denys Vlasenko73067272010-01-12 22:11:24 +010013684 read_flags |= BUILTIN_READ_RAW;
Paul Fox02eb9342005-09-07 16:56:02 +000013685 break;
Denis Vlasenko59f351c2008-03-25 00:07:12 +000013686 case 'u':
Denys Vlasenko73067272010-01-12 22:11:24 +010013687 opt_u = optionarg;
Denis Vlasenko59f351c2008-03-25 00:07:12 +000013688 break;
Johannes Schindelin3bef5d82017-08-08 16:46:39 +020013689#if BASH_READ_D
13690 case 'd':
13691 opt_d = optionarg;
13692 break;
13693#endif
Paul Fox02eb9342005-09-07 16:56:02 +000013694 default:
13695 break;
13696 }
Eric Andersenc470f442003-07-28 09:56:35 +000013697 }
Paul Fox02eb9342005-09-07 16:56:02 +000013698
Denys Vlasenko9e71e3c2012-09-06 13:28:10 +020013699 /* "read -s" needs to save/restore termios, can't allow ^C
13700 * to jump out of it.
13701 */
Denys Vlasenkof5470412017-05-22 19:34:45 +020013702 again:
Denys Vlasenko9e71e3c2012-09-06 13:28:10 +020013703 INT_OFF;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020013704 r = shell_builtin_read(setvar0,
Denys Vlasenko73067272010-01-12 22:11:24 +010013705 argptr,
13706 bltinlookup("IFS"), /* can be NULL */
13707 read_flags,
13708 opt_n,
13709 opt_p,
13710 opt_t,
Johannes Schindelin3bef5d82017-08-08 16:46:39 +020013711 opt_u,
13712 opt_d
Denys Vlasenko73067272010-01-12 22:11:24 +010013713 );
Denys Vlasenko9e71e3c2012-09-06 13:28:10 +020013714 INT_ON;
Denis Vlasenko46aeab92009-03-31 19:18:17 +000013715
Denys Vlasenkof5470412017-05-22 19:34:45 +020013716 if ((uintptr_t)r == 1 && errno == EINTR) {
Denys Vlasenko49e6bf22017-08-04 14:28:16 +020013717 /* To get SIGCHLD: sleep 1 & read x; echo $x
13718 * Correct behavior is to not exit "read"
13719 */
Denys Vlasenkof5470412017-05-22 19:34:45 +020013720 if (pending_sig == 0)
13721 goto again;
13722 }
13723
Denys Vlasenko73067272010-01-12 22:11:24 +010013724 if ((uintptr_t)r > 1)
13725 ash_msg_and_raise_error(r);
Denis Vlasenko037576d2007-10-20 18:30:38 +000013726
Denys Vlasenko73067272010-01-12 22:11:24 +010013727 return (uintptr_t)r;
Eric Andersenc470f442003-07-28 09:56:35 +000013728}
13729
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013730static int FAST_FUNC
Denys Vlasenko6283f982015-10-07 16:56:20 +020013731umaskcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000013732{
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013733 static const char permuser[3] ALIGN1 = "ogu";
Eric Andersenc470f442003-07-28 09:56:35 +000013734
Eric Andersenc470f442003-07-28 09:56:35 +000013735 mode_t mask;
Eric Andersenc470f442003-07-28 09:56:35 +000013736 int symbolic_mode = 0;
13737
13738 while (nextopt("S") != '\0') {
13739 symbolic_mode = 1;
13740 }
13741
Denis Vlasenkob012b102007-02-19 22:43:01 +000013742 INT_OFF;
Eric Andersenc470f442003-07-28 09:56:35 +000013743 mask = umask(0);
13744 umask(mask);
Denis Vlasenkob012b102007-02-19 22:43:01 +000013745 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +000013746
Denys Vlasenko6283f982015-10-07 16:56:20 +020013747 if (*argptr == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +000013748 if (symbolic_mode) {
Denys Vlasenko005c4922015-10-10 20:17:12 +020013749 char buf[sizeof(",u=rwx,g=rwx,o=rwx")];
Eric Andersenc470f442003-07-28 09:56:35 +000013750 char *p = buf;
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013751 int i;
Eric Andersenc470f442003-07-28 09:56:35 +000013752
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013753 i = 2;
13754 for (;;) {
Denys Vlasenko005c4922015-10-10 20:17:12 +020013755 *p++ = ',';
Eric Andersenc470f442003-07-28 09:56:35 +000013756 *p++ = permuser[i];
13757 *p++ = '=';
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013758 /* mask is 0..0uuugggooo. i=2 selects uuu bits */
Denys Vlasenko005c4922015-10-10 20:17:12 +020013759 if (!(mask & 0400)) *p++ = 'r';
13760 if (!(mask & 0200)) *p++ = 'w';
13761 if (!(mask & 0100)) *p++ = 'x';
13762 mask <<= 3;
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013763 if (--i < 0)
13764 break;
Eric Andersenc470f442003-07-28 09:56:35 +000013765 }
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013766 *p = '\0';
Denys Vlasenko005c4922015-10-10 20:17:12 +020013767 puts(buf + 1);
Eric Andersenc470f442003-07-28 09:56:35 +000013768 } else {
Denys Vlasenkoec046f72015-10-07 17:57:53 +020013769 out1fmt("%04o\n", mask);
Eric Andersenc470f442003-07-28 09:56:35 +000013770 }
13771 } else {
Denys Vlasenko6283f982015-10-07 16:56:20 +020013772 char *modestr = *argptr;
Denys Vlasenko14c85eb2017-10-12 19:40:47 +020013773 /* numeric umasks are taken as-is */
13774 /* symbolic umasks are inverted: "umask a=rx" calls umask(222) */
Denys Vlasenko6283f982015-10-07 16:56:20 +020013775 if (!isdigit(modestr[0]))
13776 mask ^= 0777;
Denys Vlasenko5711a2a2015-10-07 17:55:33 +020013777 mask = bb_parse_mode(modestr, mask);
13778 if ((unsigned)mask > 0777) {
Denys Vlasenko6283f982015-10-07 16:56:20 +020013779 ash_msg_and_raise_error("illegal mode: %s", modestr);
Eric Andersenc470f442003-07-28 09:56:35 +000013780 }
Denys Vlasenko6283f982015-10-07 16:56:20 +020013781 if (!isdigit(modestr[0]))
13782 mask ^= 0777;
13783 umask(mask);
Eric Andersenc470f442003-07-28 09:56:35 +000013784 }
13785 return 0;
13786}
13787
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013788static int FAST_FUNC
Denys Vlasenkof3c742f2010-03-06 20:12:00 +010013789ulimitcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersenc470f442003-07-28 09:56:35 +000013790{
Denys Vlasenkof3c742f2010-03-06 20:12:00 +010013791 return shell_builtin_ulimit(argv);
Eric Andersenc470f442003-07-28 09:56:35 +000013792}
13793
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013794/* ============ main() and helpers */
13795
13796/*
13797 * Called to exit the shell.
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013798 */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013799static void
13800exitshell(void)
13801{
13802 struct jmploc loc;
13803 char *p;
13804 int status;
13805
Denys Vlasenkobede2152011-09-04 16:12:33 +020013806#if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT
13807 save_history(line_input_state);
13808#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013809 status = exitstatus;
13810 TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
13811 if (setjmp(loc.loc)) {
Denis Vlasenko7f88e342009-03-19 03:36:18 +000013812 if (exception_type == EXEXIT)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013813 status = exitstatus;
13814 goto out;
13815 }
13816 exception_handler = &loc;
13817 p = trap[0];
13818 if (p) {
13819 trap[0] = NULL;
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020013820 evalskip = 0;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013821 evalstring(p, 0);
Denys Vlasenkof37e1152016-10-07 03:17:28 +020013822 /*free(p); - we'll exit soon */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013823 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013824 out:
Denys Vlasenkof37e1152016-10-07 03:17:28 +020013825 /* dash wraps setjobctl(0) in "if (setjmp(loc.loc) == 0) {...}".
13826 * our setjobctl(0) does not panic if tcsetpgrp fails inside it.
13827 */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013828 setjobctl(0);
Denys Vlasenkocaee80c2016-10-25 20:49:53 +020013829 flush_stdout_stderr();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013830 _exit(status);
13831 /* NOTREACHED */
13832}
13833
Denys Vlasenko49e6bf22017-08-04 14:28:16 +020013834/* Don't inline: conserve stack of caller from having our locals too */
13835static NOINLINE void
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +000013836init(void)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013837{
Denys Vlasenko82dd14a2010-05-17 10:10:01 +020013838 /* we will never free this */
13839 basepf.next_to_pgetc = basepf.buf = ckmalloc(IBUFSIZ);
Denys Vlasenko0485b672017-08-14 19:46:56 +020013840 basepf.linno = 1;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013841
Denys Vlasenko49e6bf22017-08-04 14:28:16 +020013842 sigmode[SIGCHLD - 1] = S_DFL; /* ensure we install handler even if it is SIG_IGNed */
Denys Vlasenko458c1f22016-10-27 23:51:19 +020013843 setsignal(SIGCHLD);
13844
Denys Vlasenko7a7b0342009-12-04 04:18:31 +010013845 /* bash re-enables SIGHUP which is SIG_IGNed on entry.
13846 * Try: "trap '' HUP; bash; echo RET" and type "kill -HUP $$"
13847 */
Denys Vlasenkocacb2cd2010-10-05 00:13:02 +020013848 signal(SIGHUP, SIG_DFL);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013849
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013850 {
13851 char **envp;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013852 const char *p;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013853
13854 initvar();
13855 for (envp = environ; envp && *envp; envp++) {
Denys Vlasenko9c143ce2017-11-02 12:56:24 +010013856/* Used to have
13857 * p = endofname(*envp);
13858 * if (p != *envp && *p == '=') {
13859 * here to weed out badly-named variables, but this breaks
13860 * scenarios where people do want them passed to children:
13861 * import os
13862 * os.environ["test-test"]="test"
13863 * if os.fork() == 0:
13864 * os.execv("ash", [ 'ash', '-c', 'eval $(export -p); echo OK' ]) # fixes this
13865 * os.execv("ash", [ 'ash', '-c', 'env | grep test-test' ]) # breaks this
13866 */
13867 if (strchr(*envp, '=')) {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013868 setvareq(*envp, VEXPORT|VTEXTFIXED);
13869 }
13870 }
13871
Denys Vlasenkoe627ac92016-09-30 14:36:59 +020013872 setvareq((char*)defoptindvar, VTEXTFIXED);
13873
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020013874 setvar0("PPID", utoa(getppid()));
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010013875#if BASH_SHLVL_VAR
Bernhard Reutner-Fischer80f8cdf2013-11-08 14:25:24 +010013876 p = lookupvar("SHLVL");
Denys Vlasenko5680e982014-01-07 16:12:48 +010013877 setvar("SHLVL", utoa((p ? atoi(p) : 0) + 1), VEXPORT);
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010013878#endif
13879#if BASH_HOSTNAME_VAR
Denys Vlasenko3fa97af2014-04-15 11:43:29 +020013880 if (!lookupvar("HOSTNAME")) {
13881 struct utsname uts;
13882 uname(&uts);
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020013883 setvar0("HOSTNAME", uts.nodename);
Denys Vlasenko3fa97af2014-04-15 11:43:29 +020013884 }
Bernhard Reutner-Fischer80f8cdf2013-11-08 14:25:24 +010013885#endif
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013886 p = lookupvar("PWD");
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013887 if (p) {
Denys Vlasenko49e6bf22017-08-04 14:28:16 +020013888 struct stat st1, st2;
Denys Vlasenkoef159702016-09-01 11:16:22 +020013889 if (p[0] != '/' || stat(p, &st1) || stat(".", &st2)
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013890 || st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino
13891 ) {
Denys Vlasenkoef159702016-09-01 11:16:22 +020013892 p = NULL;
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013893 }
13894 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013895 setpwd(p, 0);
13896 }
13897}
13898
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013899
13900//usage:#define ash_trivial_usage
Denys Vlasenko6b6af532011-03-08 10:24:17 +010013901//usage: "[-/+OPTIONS] [-/+o OPT]... [-c 'SCRIPT' [ARG0 [ARGS]] / FILE [ARGS]]"
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013902//usage:#define ash_full_usage "\n\n"
13903//usage: "Unix shell interpreter"
13904
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013905/*
13906 * Process the shell command line arguments.
13907 */
Denys Vlasenkoec05df12017-07-31 19:43:47 +020013908static int
Denis Vlasenko68404f12008-03-17 09:00:54 +000013909procargs(char **argv)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013910{
13911 int i;
13912 const char *xminusc;
13913 char **xargv;
Denys Vlasenkoec05df12017-07-31 19:43:47 +020013914 int login_sh;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013915
13916 xargv = argv;
Denys Vlasenkoec05df12017-07-31 19:43:47 +020013917 login_sh = xargv[0] && xargv[0][0] == '-';
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013918 arg0 = xargv[0];
Denis Vlasenko68404f12008-03-17 09:00:54 +000013919 /* if (xargv[0]) - mmm, this is always true! */
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013920 xargv++;
13921 for (i = 0; i < NOPTS; i++)
13922 optlist[i] = 2;
13923 argptr = xargv;
Denys Vlasenkoec05df12017-07-31 19:43:47 +020013924 if (options(/*cmdline:*/ 1, &login_sh)) {
Denis Vlasenko28bf6712008-02-14 15:01:47 +000013925 /* it already printed err message */
13926 raise_exception(EXERROR);
13927 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013928 xargv = argptr;
13929 xminusc = minusc;
13930 if (*xargv == NULL) {
13931 if (xminusc)
13932 ash_msg_and_raise_error(bb_msg_requires_arg, "-c");
13933 sflag = 1;
13934 }
13935 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
13936 iflag = 1;
13937 if (mflag == 2)
13938 mflag = iflag;
13939 for (i = 0; i < NOPTS; i++)
13940 if (optlist[i] == 2)
13941 optlist[i] = 0;
13942#if DEBUG == 2
13943 debug = 1;
13944#endif
Denys Vlasenko5f7c82b2017-02-03 13:00:06 +010013945 /* POSIX 1003.2: first arg after "-c CMD" is $0, remainder $1... */
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013946 if (xminusc) {
13947 minusc = *xargv++;
13948 if (*xargv)
13949 goto setarg0;
13950 } else if (!sflag) {
13951 setinputfile(*xargv, 0);
13952 setarg0:
13953 arg0 = *xargv++;
13954 commandname = arg0;
13955 }
13956
13957 shellparam.p = xargv;
13958#if ENABLE_ASH_GETOPTS
13959 shellparam.optind = 1;
13960 shellparam.optoff = -1;
13961#endif
Denis Vlasenko01631112007-12-16 17:20:38 +000013962 /* assert(shellparam.malloced == 0 && shellparam.nparam == 0); */
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013963 while (*xargv) {
13964 shellparam.nparam++;
13965 xargv++;
13966 }
13967 optschanged();
Denys Vlasenkoec05df12017-07-31 19:43:47 +020013968
13969 return login_sh;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013970}
13971
13972/*
Denys Vlasenko2eb0a7e2016-10-27 11:28:59 +020013973 * Read /etc/profile, ~/.profile, $ENV.
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013974 */
13975static void
13976read_profile(const char *name)
13977{
Denys Vlasenko46999802017-07-29 21:12:29 +020013978 name = expandstr(name, DQSYNTAX);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013979 if (setinputfile(name, INPUT_PUSH_FILE | INPUT_NOFILE_OK) < 0)
13980 return;
Denys Vlasenko0840c912016-10-01 15:27:44 +020013981 cmdloop(0);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013982 popfile();
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013983}
13984
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013985/*
13986 * This routine is called when an error or an interrupt occurs in an
13987 * interactive shell and control is returned to the main command loop.
Denys Vlasenko5ac04f22016-10-27 14:46:50 +020013988 * (In dash, this function is auto-generated by build machinery).
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013989 */
13990static void
13991reset(void)
13992{
13993 /* from eval.c: */
13994 evalskip = 0;
13995 loopnest = 0;
Denys Vlasenko5ac04f22016-10-27 14:46:50 +020013996
13997 /* from expand.c: */
13998 ifsfree();
13999
Denis Vlasenko0c032a42007-02-23 01:03:40 +000014000 /* from input.c: */
Denis Vlasenko41eb3002008-11-28 03:42:31 +000014001 g_parsefile->left_in_buffer = 0;
14002 g_parsefile->left_in_line = 0; /* clear input buffer */
Denis Vlasenko0c032a42007-02-23 01:03:40 +000014003 popallfiles();
Denys Vlasenko5ac04f22016-10-27 14:46:50 +020014004
Denis Vlasenko0c032a42007-02-23 01:03:40 +000014005 /* from redir.c: */
Denys Vlasenko1c79aeb2017-07-29 22:51:52 +020014006 unwindredir(NULL);
Denys Vlasenkob8ab27b2017-07-26 19:22:34 +020014007
14008 /* from var.c: */
Denys Vlasenko484fc202017-07-26 19:55:31 +020014009 unwindlocalvars(NULL);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000014010}
14011
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014012#if PROFILE
14013static short profile_buf[16384];
14014extern int etext();
14015#endif
14016
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000014017/*
14018 * Main routine. We initialize things, parse the arguments, execute
14019 * profiles if we're a login shell, and then call cmdloop to execute
14020 * commands. The setjmp call sets up the location to jump to when an
14021 * exception occurs. When an exception occurs the variable "state"
14022 * is used to figure out how far we had gotten.
14023 */
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +000014024int ash_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000014025int ash_main(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014026{
Denis Vlasenko4e12b1a2008-12-23 23:36:47 +000014027 volatile smallint state;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014028 struct jmploc jmploc;
14029 struct stackmark smark;
Denys Vlasenkoec05df12017-07-31 19:43:47 +020014030 int login_sh;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014031
Denis Vlasenko01631112007-12-16 17:20:38 +000014032 /* Initialize global data */
14033 INIT_G_misc();
14034 INIT_G_memstack();
14035 INIT_G_var();
Denis Vlasenkoee87ebf2007-12-21 22:18:16 +000014036#if ENABLE_ASH_ALIAS
Denis Vlasenko01631112007-12-16 17:20:38 +000014037 INIT_G_alias();
Denis Vlasenkoee87ebf2007-12-21 22:18:16 +000014038#endif
Denis Vlasenko01631112007-12-16 17:20:38 +000014039 INIT_G_cmdtable();
14040
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014041#if PROFILE
14042 monitor(4, etext, profile_buf, sizeof(profile_buf), 50);
14043#endif
14044
14045#if ENABLE_FEATURE_EDITING
14046 line_input_state = new_line_input_t(FOR_SHELL | WITH_PATH_LOOKUP);
14047#endif
14048 state = 0;
14049 if (setjmp(jmploc.loc)) {
Denis Vlasenko7f88e342009-03-19 03:36:18 +000014050 smallint e;
Denis Vlasenko4e12b1a2008-12-23 23:36:47 +000014051 smallint s;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014052
14053 reset();
14054
Denis Vlasenko7f88e342009-03-19 03:36:18 +000014055 e = exception_type;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014056 s = state;
Denys Vlasenkob563f622010-09-25 17:15:13 +020014057 if (e == EXEXIT || s == 0 || iflag == 0 || shlvl) {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014058 exitshell();
Denys Vlasenkob563f622010-09-25 17:15:13 +020014059 }
14060 if (e == EXINT) {
Denys Vlasenko9c541002015-10-07 15:44:36 +020014061 newline_and_flush(stderr);
Denys Vlasenkob563f622010-09-25 17:15:13 +020014062 }
Denis Vlasenko7f88e342009-03-19 03:36:18 +000014063
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014064 popstackmark(&smark);
14065 FORCE_INT_ON; /* enable interrupts */
14066 if (s == 1)
14067 goto state1;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000014068 if (s == 2)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014069 goto state2;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000014070 if (s == 3)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014071 goto state3;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000014072 goto state4;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014073 }
14074 exception_handler = &jmploc;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014075 rootpid = getpid();
14076
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014077 init();
14078 setstackmark(&smark);
Denys Vlasenkoec05df12017-07-31 19:43:47 +020014079 login_sh = procargs(argv);
Denys Vlasenko474ed062016-10-30 18:30:29 +010014080#if DEBUG
14081 TRACE(("Shell args: "));
14082 trace_puts_args(argv);
14083#endif
Denis Vlasenko68404f12008-03-17 09:00:54 +000014084
Denys Vlasenkoec05df12017-07-31 19:43:47 +020014085 if (login_sh) {
Stefan Hellermann4ef14392013-03-15 02:45:50 +010014086 const char *hp;
14087
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014088 state = 1;
14089 read_profile("/etc/profile");
14090 state1:
14091 state = 2;
Stefan Hellermann4ef14392013-03-15 02:45:50 +010014092 hp = lookupvar("HOME");
Denys Vlasenko2eb0a7e2016-10-27 11:28:59 +020014093 if (hp)
14094 read_profile("$HOME/.profile");
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014095 }
14096 state2:
14097 state = 3;
14098 if (
14099#ifndef linux
Denis Vlasenko0c032a42007-02-23 01:03:40 +000014100 getuid() == geteuid() && getgid() == getegid() &&
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014101#endif
Denis Vlasenko0c032a42007-02-23 01:03:40 +000014102 iflag
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014103 ) {
Denys Vlasenko2eb0a7e2016-10-27 11:28:59 +020014104 const char *shinit = lookupvar("ENV");
14105 if (shinit != NULL && *shinit != '\0')
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014106 read_profile(shinit);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014107 }
Denys Vlasenko2eb0a7e2016-10-27 11:28:59 +020014108 popstackmark(&smark);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014109 state3:
14110 state = 4;
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000014111 if (minusc) {
14112 /* evalstring pushes parsefile stack.
14113 * Ensure we don't falsely claim that 0 (stdin)
Denis Vlasenko5368ad52009-03-20 10:20:08 +000014114 * is one of stacked source fds.
14115 * Testcase: ash -c 'exec 1>&0' must not complain. */
Denys Vlasenko79b3d422010-06-03 04:29:08 +020014116 // if (!sflag) g_parsefile->pf_fd = -1;
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +020014117 // ^^ not necessary since now we special-case fd 0
Denys Vlasenko035486c2017-07-31 04:09:19 +020014118 // in save_fd_on_redirect()
Denys Vlasenko1e3e2cc2017-07-25 20:31:14 +020014119 evalstring(minusc, sflag ? 0 : EV_EXIT);
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000014120 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014121
14122 if (sflag || minusc == NULL) {
Denys Vlasenko4840ae82011-09-04 15:28:03 +020014123#if MAX_HISTORY > 0 && ENABLE_FEATURE_EDITING_SAVEHISTORY
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +000014124 if (iflag) {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014125 const char *hp = lookupvar("HISTFILE");
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010014126 if (!hp) {
14127 hp = lookupvar("HOME");
Stefan Hellermann4ef14392013-03-15 02:45:50 +010014128 if (hp) {
Denys Vlasenko5f7c82b2017-02-03 13:00:06 +010014129 INT_OFF;
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010014130 hp = concat_path_file(hp, ".ash_history");
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020014131 setvar0("HISTFILE", hp);
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010014132 free((char*)hp);
Denys Vlasenko5f7c82b2017-02-03 13:00:06 +010014133 INT_ON;
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010014134 hp = lookupvar("HISTFILE");
14135 }
14136 }
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000014137 if (hp)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014138 line_input_state->hist_file = hp;
Denys Vlasenko2c4de5b2011-03-31 13:16:52 +020014139# if ENABLE_FEATURE_SH_HISTFILESIZE
14140 hp = lookupvar("HISTFILESIZE");
14141 line_input_state->max_history = size_from_HISTFILESIZE(hp);
14142# endif
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014143 }
14144#endif
14145 state4: /* XXX ??? - why isn't this before the "if" statement */
14146 cmdloop(1);
14147 }
14148#if PROFILE
14149 monitor(0);
14150#endif
14151#ifdef GPROF
14152 {
14153 extern void _mcleanup(void);
14154 _mcleanup();
14155 }
14156#endif
Denys Vlasenkob563f622010-09-25 17:15:13 +020014157 TRACE(("End of main reached\n"));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014158 exitshell();
14159 /* NOTREACHED */
14160}
14161
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014162
Eric Andersendf82f612001-06-28 07:46:40 +000014163/*-
14164 * Copyright (c) 1989, 1991, 1993, 1994
Eric Andersen2870d962001-07-02 17:27:21 +000014165 * The Regents of the University of California. All rights reserved.
Eric Andersendf82f612001-06-28 07:46:40 +000014166 *
14167 * This code is derived from software contributed to Berkeley by
14168 * Kenneth Almquist.
14169 *
14170 * Redistribution and use in source and binary forms, with or without
14171 * modification, are permitted provided that the following conditions
14172 * are met:
14173 * 1. Redistributions of source code must retain the above copyright
14174 * notice, this list of conditions and the following disclaimer.
14175 * 2. Redistributions in binary form must reproduce the above copyright
14176 * notice, this list of conditions and the following disclaimer in the
14177 * documentation and/or other materials provided with the distribution.
"Vladimir N. Oleynik"ddc280e2005-12-15 12:01:49 +000014178 * 3. Neither the name of the University nor the names of its contributors
Eric Andersendf82f612001-06-28 07:46:40 +000014179 * may be used to endorse or promote products derived from this software
14180 * without specific prior written permission.
14181 *
Denys Vlasenko95f79532017-08-02 14:26:33 +020014182 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND
Eric Andersendf82f612001-06-28 07:46:40 +000014183 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
14184 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
14185 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
14186 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
14187 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
14188 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
14189 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
14190 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
14191 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
14192 * SUCH DAMAGE.
14193 */