blob: 924e17f32d3e9f7d42cea80288e02f766d1853f1 [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 Vlasenkob097a842018-12-28 03:20:17 +010019//config: bool "ash (78 kb)"
Denys Vlasenko771f1992010-07-16 14:31:34 +020020//config: default y
21//config: depends on !NOMMU
22//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +020023//config: The most complete and most pedantically correct shell included with
24//config: busybox. This shell is actually a derivative of the Debian 'dash'
25//config: shell (by Herbert Xu), which was created by porting the 'ash' shell
26//config: (written by Kenneth Almquist) from NetBSD.
Denys Vlasenko771f1992010-07-16 14:31:34 +020027//config:
Kang-Che Sung6cd02942017-01-06 17:02:03 +010028//config:# ash options
29//config:# note: Don't remove !NOMMU part in the next line; it would break
30//config:# menuconfig's indenting.
31//config:if !NOMMU && (ASH || SH_IS_ASH || BASH_IS_ASH)
32//config:
Denys Vlasenko514b51d2016-10-01 14:33:08 +020033//config:config ASH_OPTIMIZE_FOR_SIZE
34//config: bool "Optimize for size instead of speed"
35//config: default y
Denys Vlasenko0b883582016-12-23 16:49:07 +010036//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
Denys Vlasenko514b51d2016-10-01 14:33:08 +020037//config:
38//config:config ASH_INTERNAL_GLOB
39//config: bool "Use internal glob() implementation"
Denys Vlasenko326edc32016-12-22 14:36:49 +010040//config: default y # Y is bigger, but because of uclibc glob() bug, let Y be default for now
Denys Vlasenko0b883582016-12-23 16:49:07 +010041//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
Denys Vlasenko514b51d2016-10-01 14:33:08 +020042//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +020043//config: Do not use glob() function from libc, use internal implementation.
44//config: Use this if you are getting "glob.h: No such file or directory"
45//config: or similar build errors.
46//config: Note that as of now (2017-01), uclibc and musl glob() both have bugs
47//config: which would break ash if you select N here.
Denys Vlasenkof5604222017-01-10 14:58:54 +010048//config:
49//config:config ASH_BASH_COMPAT
50//config: bool "bash-compatible extensions"
51//config: default y
52//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
53//config:
Denys Vlasenko01f7b9e2018-01-26 15:15:43 +010054//config:config ASH_BASH_SOURCE_CURDIR
55//config: bool "'source' and '.' builtins search current directory after $PATH"
56//config: default n # do not encourage non-standard behavior
Denys Vlasenko54c21112018-01-27 20:46:45 +010057//config: depends on ASH_BASH_COMPAT
Denys Vlasenko01f7b9e2018-01-26 15:15:43 +010058//config: help
59//config: This is not compliant with standards. Avoid if possible.
60//config:
William Pitcockd8fd88a2018-01-24 18:33:18 +010061//config:config ASH_BASH_NOT_FOUND_HOOK
62//config: bool "command_not_found_handle hook support"
63//config: default y
Denys Vlasenko54c21112018-01-27 20:46:45 +010064//config: depends on ASH_BASH_COMPAT
William Pitcockd8fd88a2018-01-24 18:33:18 +010065//config: help
66//config: Enable support for the 'command_not_found_handle' hook function,
67//config: from GNU bash, which allows for alternative command not found
68//config: handling.
69//config:
Denys Vlasenkof5604222017-01-10 14:58:54 +010070//config:config ASH_JOB_CONTROL
71//config: bool "Job control"
72//config: default y
73//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
74//config:
75//config:config ASH_ALIAS
76//config: bool "Alias support"
77//config: default y
78//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
Denys Vlasenko514b51d2016-10-01 14:33:08 +020079//config:
80//config:config ASH_RANDOM_SUPPORT
81//config: bool "Pseudorandom generator and $RANDOM variable"
82//config: default y
Denys Vlasenko0b883582016-12-23 16:49:07 +010083//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
Denys Vlasenko514b51d2016-10-01 14:33:08 +020084//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +020085//config: Enable pseudorandom generator and dynamic variable "$RANDOM".
86//config: Each read of "$RANDOM" will generate a new pseudorandom value.
87//config: You can reset the generator by using a specified start value.
88//config: After "unset RANDOM" the generator will switch off and this
89//config: variable will no longer have special treatment.
Denys Vlasenko514b51d2016-10-01 14:33:08 +020090//config:
91//config:config ASH_EXPAND_PRMT
92//config: bool "Expand prompt string"
93//config: default y
Denys Vlasenko0b883582016-12-23 16:49:07 +010094//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
Denys Vlasenko514b51d2016-10-01 14:33:08 +020095//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +020096//config: $PS# may contain volatile content, such as backquote commands.
97//config: This option recreates the prompt string from the environment
98//config: variable each time it is displayed.
Denys Vlasenko514b51d2016-10-01 14:33:08 +020099//config:
Denys Vlasenko046341e2011-02-04 17:53:59 +0100100//config:config ASH_IDLE_TIMEOUT
Denys Vlasenkof5604222017-01-10 14:58:54 +0100101//config: bool "Idle timeout variable $TMOUT"
Denys Vlasenko771f1992010-07-16 14:31:34 +0200102//config: default y
Denys Vlasenko0b883582016-12-23 16:49:07 +0100103//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
Denys Vlasenko771f1992010-07-16 14:31:34 +0200104//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +0200105//config: Enable bash-like auto-logout after $TMOUT seconds of idle time.
Denys Vlasenko771f1992010-07-16 14:31:34 +0200106//config:
Denys Vlasenkof5604222017-01-10 14:58:54 +0100107//config:config ASH_MAIL
108//config: bool "Check for new mail in interactive shell"
Denys Vlasenko771f1992010-07-16 14:31:34 +0200109//config: default y
Denys Vlasenko0b883582016-12-23 16:49:07 +0100110//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
Denys Vlasenko771f1992010-07-16 14:31:34 +0200111//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +0200112//config: Enable "check for new mail" function:
113//config: if set, $MAIL file and $MAILPATH list of files
114//config: are checked for mtime changes, and "you have mail"
115//config: message is printed if change is detected.
Denys Vlasenko771f1992010-07-16 14:31:34 +0200116//config:
Denys Vlasenko265062d2017-01-10 15:13:30 +0100117//config:config ASH_ECHO
Denys Vlasenkof5604222017-01-10 14:58:54 +0100118//config: bool "echo builtin"
Denys Vlasenko771f1992010-07-16 14:31:34 +0200119//config: default y
Denys Vlasenko0b883582016-12-23 16:49:07 +0100120//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
Denys Vlasenko771f1992010-07-16 14:31:34 +0200121//config:
Denys Vlasenko265062d2017-01-10 15:13:30 +0100122//config:config ASH_PRINTF
Denys Vlasenkof5604222017-01-10 14:58:54 +0100123//config: bool "printf builtin"
Denys Vlasenko771f1992010-07-16 14:31:34 +0200124//config: default y
Denys Vlasenko0b883582016-12-23 16:49:07 +0100125//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
Denys Vlasenko771f1992010-07-16 14:31:34 +0200126//config:
Denys Vlasenko265062d2017-01-10 15:13:30 +0100127//config:config ASH_TEST
Denys Vlasenkof5604222017-01-10 14:58:54 +0100128//config: bool "test builtin"
Denys Vlasenko771f1992010-07-16 14:31:34 +0200129//config: default y
Denys Vlasenko0b883582016-12-23 16:49:07 +0100130//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
Denys Vlasenko771f1992010-07-16 14:31:34 +0200131//config:
Denys Vlasenko2ec34962014-09-08 16:52:39 +0200132//config:config ASH_HELP
133//config: bool "help builtin"
134//config: default y
Denys Vlasenko0b883582016-12-23 16:49:07 +0100135//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
Denys Vlasenkof5604222017-01-10 14:58:54 +0100136//config:
137//config:config ASH_GETOPTS
138//config: bool "getopts builtin"
139//config: default y
140//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
Denys Vlasenko2ec34962014-09-08 16:52:39 +0200141//config:
Denys Vlasenko771f1992010-07-16 14:31:34 +0200142//config:config ASH_CMDCMD
Denys Vlasenkof5604222017-01-10 14:58:54 +0100143//config: bool "command builtin"
Denys Vlasenko771f1992010-07-16 14:31:34 +0200144//config: default y
Denys Vlasenko0b883582016-12-23 16:49:07 +0100145//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
Denys Vlasenko771f1992010-07-16 14:31:34 +0200146//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +0200147//config: Enable support for the 'command' builtin, which allows
148//config: you to run the specified command or builtin,
149//config: even when there is a function with the same name.
Kang-Che Sung6cd02942017-01-06 17:02:03 +0100150//config:
151//config:endif # ash options
Denys Vlasenko771f1992010-07-16 14:31:34 +0200152
Denys Vlasenko20704f02011-03-23 17:59:27 +0100153//applet:IF_ASH(APPLET(ash, BB_DIR_BIN, BB_SUID_DROP))
Denys Vlasenko205d48e2017-01-29 14:57:33 +0100154// APPLET_ODDNAME:name main location suid_type help
155//applet:IF_SH_IS_ASH( APPLET_ODDNAME(sh, ash, BB_DIR_BIN, BB_SUID_DROP, ash))
Denys Vlasenko0b883582016-12-23 16:49:07 +0100156//applet:IF_BASH_IS_ASH(APPLET_ODDNAME(bash, ash, BB_DIR_BIN, BB_SUID_DROP, ash))
Denys Vlasenko20704f02011-03-23 17:59:27 +0100157
158//kbuild:lib-$(CONFIG_ASH) += ash.o ash_ptr_hack.o shell_common.o
Denys Vlasenko0b883582016-12-23 16:49:07 +0100159//kbuild:lib-$(CONFIG_SH_IS_ASH) += ash.o ash_ptr_hack.o shell_common.o
160//kbuild:lib-$(CONFIG_BASH_IS_ASH) += ash.o ash_ptr_hack.o shell_common.o
Denys Vlasenko20704f02011-03-23 17:59:27 +0100161//kbuild:lib-$(CONFIG_ASH_RANDOM_SUPPORT) += random.o
162
Denys Vlasenko67047462016-12-22 15:21:58 +0100163/*
Denys Vlasenko7d4aec02017-01-11 14:00:38 +0100164 * DEBUG=1 to compile in debugging ('set -o debug' turns on)
165 * DEBUG=2 to compile in and turn on debugging.
166 * When debugging is on ("set -o debug" was executed, or DEBUG=2),
167 * debugging info is written to ./trace, quit signal generates core dump.
Denys Vlasenko67047462016-12-22 15:21:58 +0100168 */
169#define DEBUG 0
170/* Tweak debug output verbosity here */
171#define DEBUG_TIME 0
172#define DEBUG_PID 1
173#define DEBUG_SIG 1
174#define DEBUG_INTONOFF 0
175
176#define PROFILE 0
177
178#define JOBS ENABLE_ASH_JOB_CONTROL
179
Denys Vlasenko67047462016-12-22 15:21:58 +0100180#include <fnmatch.h>
181#include <sys/times.h>
182#include <sys/utsname.h> /* for setting $HOSTNAME */
Denys Vlasenko67047462016-12-22 15:21:58 +0100183#include "busybox.h" /* for applet_names */
Ron Yorston71df2d32018-11-27 14:34:25 +0000184#if ENABLE_FEATURE_SH_EMBEDDED_SCRIPTS
Denys Vlasenko4f2ef4a2018-11-01 09:53:25 +0100185# include "embedded_scripts.h"
186#else
187# define NUM_SCRIPTS 0
188#endif
Denys Vlasenko67047462016-12-22 15:21:58 +0100189
Denys Vlasenko7d4aec02017-01-11 14:00:38 +0100190/* So far, all bash compat is controlled by one config option */
191/* Separate defines document which part of code implements what */
192/* function keyword */
193#define BASH_FUNCTION ENABLE_ASH_BASH_COMPAT
194#define IF_BASH_FUNCTION IF_ASH_BASH_COMPAT
195/* &>file */
196#define BASH_REDIR_OUTPUT ENABLE_ASH_BASH_COMPAT
197#define IF_BASH_REDIR_OUTPUT IF_ASH_BASH_COMPAT
198/* $'...' */
199#define BASH_DOLLAR_SQUOTE ENABLE_ASH_BASH_COMPAT
200#define IF_BASH_DOLLAR_SQUOTE IF_ASH_BASH_COMPAT
201#define BASH_PATTERN_SUBST ENABLE_ASH_BASH_COMPAT
202#define IF_BASH_PATTERN_SUBST IF_ASH_BASH_COMPAT
203#define BASH_SUBSTR ENABLE_ASH_BASH_COMPAT
204#define IF_BASH_SUBSTR IF_ASH_BASH_COMPAT
Denys Vlasenko3632cb12018-04-10 15:25:41 +0200205/* BASH_TEST2: [[ EXPR ]]
206 * Status of [[ support:
207 * We replace && and || with -a and -o
208 * TODO:
209 * singleword+noglob expansion:
210 * v='a b'; [[ $v = 'a b' ]]; echo 0:$?
Denys Vlasenko89e9d552018-04-11 01:15:33 +0200211 * [[ /bin/n* ]]; echo 0:$?
Denys Vlasenko3632cb12018-04-10 15:25:41 +0200212 * -a/-o are not AND/OR ops! (they are just strings)
213 * quoting needs to be considered (-f is an operator, "-f" and ""-f are not; etc)
214 * = is glob match operator, not equality operator: STR = GLOB
215 * (in GLOB, quoting is significant on char-by-char basis: a*cd"*")
216 * == same as =
217 * add =~ regex match operator: STR =~ REGEX
218 */
Denys Vlasenko7d4aec02017-01-11 14:00:38 +0100219#define BASH_TEST2 (ENABLE_ASH_BASH_COMPAT * ENABLE_ASH_TEST)
220#define BASH_SOURCE ENABLE_ASH_BASH_COMPAT
221#define BASH_PIPEFAIL ENABLE_ASH_BASH_COMPAT
222#define BASH_HOSTNAME_VAR ENABLE_ASH_BASH_COMPAT
Ron Yorston1d371862019-04-15 10:52:05 +0100223#define BASH_EPOCH_VARS ENABLE_ASH_BASH_COMPAT
Denys Vlasenko7d4aec02017-01-11 14:00:38 +0100224#define BASH_SHLVL_VAR ENABLE_ASH_BASH_COMPAT
Denys Vlasenkof8cdc7a2017-08-04 15:24:49 +0200225#define BASH_XTRACEFD ENABLE_ASH_BASH_COMPAT
Johannes Schindelin3bef5d82017-08-08 16:46:39 +0200226#define BASH_READ_D ENABLE_ASH_BASH_COMPAT
227#define IF_BASH_READ_D IF_ASH_BASH_COMPAT
Ron Yorstone48559e2019-03-31 09:27:09 +0100228#define BASH_WAIT_N ENABLE_ASH_BASH_COMPAT
Denys Vlasenko7d4aec02017-01-11 14:00:38 +0100229
Denys Vlasenko67047462016-12-22 15:21:58 +0100230#if defined(__ANDROID_API__) && __ANDROID_API__ <= 24
231/* Bionic at least up to version 24 has no glob() */
232# undef ENABLE_ASH_INTERNAL_GLOB
233# define ENABLE_ASH_INTERNAL_GLOB 1
234#endif
235
236#if !ENABLE_ASH_INTERNAL_GLOB && defined(__UCLIBC__)
237# error uClibc glob() is buggy, use ASH_INTERNAL_GLOB.
238# error The bug is: for "$PWD"/<pattern> ash will escape e.g. dashes in "$PWD"
239# error with backslash, even ones which do not need to be: "/a-b" -> "/a\-b"
240# error glob() should unbackslash them and match. uClibc does not unbackslash,
241# error fails to match dirname, subsequently not expanding <pattern> in it.
242// Testcase:
243// if (glob("/etc/polkit\\-1", 0, NULL, &pglob)) - this returns 0 on uclibc, no bug
244// if (glob("/etc/polkit\\-1/*", 0, NULL, &pglob)) printf("uclibc bug!\n");
245#endif
246
247#if !ENABLE_ASH_INTERNAL_GLOB
248# include <glob.h>
249#endif
250
251#include "unicode.h"
252#include "shell_common.h"
Denys Vlasenko0b883582016-12-23 16:49:07 +0100253#if ENABLE_FEATURE_SH_MATH
Denys Vlasenko67047462016-12-22 15:21:58 +0100254# include "math.h"
Denys Vlasenkocf3a7962017-07-26 14:38:19 +0200255#else
256typedef long arith_t;
257# define ARITH_FMT "%ld"
Denys Vlasenko67047462016-12-22 15:21:58 +0100258#endif
259#if ENABLE_ASH_RANDOM_SUPPORT
260# include "random.h"
261#else
262# define CLEAR_RANDOM_T(rnd) ((void)0)
263#endif
264
265#include "NUM_APPLETS.h"
266#if NUM_APPLETS == 1
267/* STANDALONE does not make sense, and won't compile */
268# undef CONFIG_FEATURE_SH_STANDALONE
269# undef ENABLE_FEATURE_SH_STANDALONE
270# undef IF_FEATURE_SH_STANDALONE
271# undef IF_NOT_FEATURE_SH_STANDALONE
272# define ENABLE_FEATURE_SH_STANDALONE 0
273# define IF_FEATURE_SH_STANDALONE(...)
274# define IF_NOT_FEATURE_SH_STANDALONE(...) __VA_ARGS__
275#endif
276
Denys Vlasenko9acd63c2018-03-28 18:35:07 +0200277#ifndef F_DUPFD_CLOEXEC
278# define F_DUPFD_CLOEXEC F_DUPFD
279#endif
Denys Vlasenko60fb98e2018-03-30 22:15:14 +0200280#ifndef O_CLOEXEC
281# define O_CLOEXEC 0
282#endif
Denys Vlasenko67047462016-12-22 15:21:58 +0100283#ifndef PIPE_BUF
284# define PIPE_BUF 4096 /* amount of buffering in a pipe */
285#endif
286
287#if !BB_MMU
288# error "Do not even bother, ash will not run on NOMMU machine"
289#endif
290
Denys Vlasenko6f9442f2018-01-28 20:41:23 +0100291/* We use a trick to have more optimized code (fewer pointer reloads):
292 * ash.c: extern struct globals *const ash_ptr_to_globals;
293 * ash_ptr_hack.c: struct globals *ash_ptr_to_globals;
294 * This way, compiler in ash.c knows the pointer can not change.
295 *
296 * However, this may break on weird arches or toolchains. In this case,
297 * set "-DBB_GLOBAL_CONST=''" in CONFIG_EXTRA_CFLAGS to disable
298 * this optimization.
299 */
300#ifndef BB_GLOBAL_CONST
301# define BB_GLOBAL_CONST const
302#endif
303
Denis Vlasenkob012b102007-02-19 22:43:01 +0000304
Denis Vlasenko01631112007-12-16 17:20:38 +0000305/* ============ Hash table sizes. Configurable. */
306
307#define VTABSIZE 39
308#define ATABSIZE 39
309#define CMDTABLESIZE 31 /* should be prime */
310
311
Denis Vlasenkob012b102007-02-19 22:43:01 +0000312/* ============ Shell options */
313
314static const char *const optletters_optnames[] = {
315 "e" "errexit",
316 "f" "noglob",
317 "I" "ignoreeof",
318 "i" "interactive",
319 "m" "monitor",
320 "n" "noexec",
321 "s" "stdin",
322 "x" "xtrace",
323 "v" "verbose",
324 "C" "noclobber",
325 "a" "allexport",
326 "b" "notify",
327 "u" "nounset",
Denys Vlasenkoe9ac32a2009-12-05 02:01:25 +0100328 "\0" "vi"
Denys Vlasenko7d4aec02017-01-11 14:00:38 +0100329#if BASH_PIPEFAIL
Denys Vlasenkoe9ac32a2009-12-05 02:01:25 +0100330 ,"\0" "pipefail"
Michael Abbott359da5e2009-12-04 23:03:29 +0100331#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +0000332#if DEBUG
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000333 ,"\0" "nolog"
334 ,"\0" "debug"
Denis Vlasenkob012b102007-02-19 22:43:01 +0000335#endif
336};
337
Denys Vlasenko285ad152009-12-04 23:02:27 +0100338#define optletters(n) optletters_optnames[n][0]
339#define optnames(n) (optletters_optnames[n] + 1)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000340
Denis Vlasenko80b8b392007-06-25 10:55:35 +0000341enum { NOPTS = ARRAY_SIZE(optletters_optnames) };
Denis Vlasenkob012b102007-02-19 22:43:01 +0000342
Eric Andersenc470f442003-07-28 09:56:35 +0000343
Denis Vlasenkob012b102007-02-19 22:43:01 +0000344/* ============ Misc data */
Eric Andersenc470f442003-07-28 09:56:35 +0000345
Denys Vlasenkoea8b2522010-06-02 12:57:26 +0200346#define msg_illnum "Illegal number: %s"
Denis Vlasenkoaa744452007-02-23 01:04:22 +0000347
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +0000348/*
Eric Andersenc470f442003-07-28 09:56:35 +0000349 * We enclose jmp_buf in a structure so that we can declare pointers to
350 * jump locations. The global variable handler contains the location to
Denis Vlasenkof1733952009-03-19 23:21:55 +0000351 * jump to when an exception occurs, and the global variable exception_type
Eric Andersenaff114c2004-04-14 17:51:38 +0000352 * contains a code identifying the exception. To implement nested
Eric Andersenc470f442003-07-28 09:56:35 +0000353 * exception handlers, the user should save the value of handler on entry
354 * to an inner scope, set handler to point to a jmploc structure for the
355 * inner scope, and restore handler on exit from the scope.
356 */
Eric Andersenc470f442003-07-28 09:56:35 +0000357struct jmploc {
358 jmp_buf loc;
359};
Denis Vlasenko01631112007-12-16 17:20:38 +0000360
361struct globals_misc {
Denys Vlasenko4d12e942016-10-01 16:03:11 +0200362 uint8_t exitstatus; /* exit status of last command */
363 uint8_t back_exitstatus;/* exit status of backquoted command */
364 smallint job_warning; /* user was warned about stopped jobs (can be 2, 1 or 0). */
365 int rootpid; /* pid of main shell */
Denis Vlasenko01631112007-12-16 17:20:38 +0000366 /* shell level: 0 for the main shell, 1 for its children, and so on */
367 int shlvl;
368#define rootshell (!shlvl)
Denys Vlasenko675d24a2018-01-27 22:02:05 +0100369 int errlinno;
370
Denis Vlasenko01631112007-12-16 17:20:38 +0000371 char *minusc; /* argument to -c option */
372
373 char *curdir; // = nullstr; /* current working directory */
374 char *physdir; // = nullstr; /* physical working directory */
375
376 char *arg0; /* value of $0 */
377
378 struct jmploc *exception_handler;
Denis Vlasenko991a1da2008-02-10 19:02:53 +0000379
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200380 volatile int suppress_int; /* counter */
381 volatile /*sig_atomic_t*/ smallint pending_int; /* 1 = got SIGINT */
Denys Vlasenko458c1f22016-10-27 23:51:19 +0200382 volatile /*sig_atomic_t*/ smallint got_sigchld; /* 1 = got SIGCHLD */
Denys Vlasenko8f7b0242016-10-28 17:16:11 +0200383 volatile /*sig_atomic_t*/ smallint pending_sig; /* last pending signal */
Denis Vlasenko7f88e342009-03-19 03:36:18 +0000384 smallint exception_type; /* kind of exception (0..5) */
Denis Vlasenko01631112007-12-16 17:20:38 +0000385 /* exceptions */
Eric Andersenc470f442003-07-28 09:56:35 +0000386#define EXINT 0 /* SIGINT received */
387#define EXERROR 1 /* a generic error */
Eric Andersenc470f442003-07-28 09:56:35 +0000388#define EXEXIT 4 /* exit the shell */
Eric Andersen2870d962001-07-02 17:27:21 +0000389
Denis Vlasenkob07a4962008-06-22 13:16:23 +0000390 char nullstr[1]; /* zero length string */
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000391
392 char optlist[NOPTS];
393#define eflag optlist[0]
394#define fflag optlist[1]
395#define Iflag optlist[2]
396#define iflag optlist[3]
397#define mflag optlist[4]
398#define nflag optlist[5]
399#define sflag optlist[6]
400#define xflag optlist[7]
401#define vflag optlist[8]
402#define Cflag optlist[9]
403#define aflag optlist[10]
404#define bflag optlist[11]
405#define uflag optlist[12]
406#define viflag optlist[13]
Denys Vlasenko7d4aec02017-01-11 14:00:38 +0100407#if BASH_PIPEFAIL
Michael Abbott359da5e2009-12-04 23:03:29 +0100408# define pipefail optlist[14]
409#else
410# define pipefail 0
411#endif
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000412#if DEBUG
Denys Vlasenko7d4aec02017-01-11 14:00:38 +0100413# define nolog optlist[14 + BASH_PIPEFAIL]
414# define debug optlist[15 + BASH_PIPEFAIL]
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000415#endif
416
417 /* trap handler commands */
Denis Vlasenko01631112007-12-16 17:20:38 +0000418 /*
419 * Sigmode records the current value of the signal handlers for the various
420 * modes. A value of zero means that the current handler is not known.
Denis Vlasenkof8535cc2008-12-03 10:36:26 +0000421 * S_HARD_IGN indicates that the signal was ignored on entry to the shell.
Denis Vlasenko01631112007-12-16 17:20:38 +0000422 */
423 char sigmode[NSIG - 1];
Denis Vlasenkof8535cc2008-12-03 10:36:26 +0000424#define S_DFL 1 /* default signal handling (SIG_DFL) */
425#define S_CATCH 2 /* signal is caught */
426#define S_IGN 3 /* signal is ignored (SIG_IGN) */
Denys Vlasenko0f14f412017-08-06 20:06:19 +0200427#define S_HARD_IGN 4 /* signal is ignored permanently (it was SIG_IGN on entry to shell) */
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +0000428
Denis Vlasenko01631112007-12-16 17:20:38 +0000429 /* indicates specified signal received */
Denis Vlasenko4b875702009-03-19 13:30:04 +0000430 uint8_t gotsig[NSIG - 1]; /* offset by 1: "signal" 0 is meaningless */
Denys Vlasenko238bf182010-05-18 15:49:07 +0200431 uint8_t may_have_traps; /* 0: definitely no traps are set, 1: some traps may be set */
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000432 char *trap[NSIG];
Denys Vlasenko21d87d42009-09-25 00:06:51 +0200433 char **trap_ptr; /* used only by "trap hack" */
Denis Vlasenko448d30e2008-06-27 00:24:11 +0000434
435 /* Rarely referenced stuff */
436#if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenko3ea2e822009-10-09 20:59:04 +0200437 random_t random_gen;
Denis Vlasenko448d30e2008-06-27 00:24:11 +0000438#endif
439 pid_t backgndpid; /* pid of last background process */
Denis Vlasenko01631112007-12-16 17:20:38 +0000440};
Denys Vlasenko6f9442f2018-01-28 20:41:23 +0100441extern struct globals_misc *BB_GLOBAL_CONST ash_ptr_to_globals_misc;
Denis Vlasenko574f2f42008-02-27 18:41:59 +0000442#define G_misc (*ash_ptr_to_globals_misc)
Denys Vlasenko4d12e942016-10-01 16:03:11 +0200443#define exitstatus (G_misc.exitstatus )
444#define back_exitstatus (G_misc.back_exitstatus )
445#define job_warning (G_misc.job_warning)
Denis Vlasenko26bc57d2008-06-27 00:29:34 +0000446#define rootpid (G_misc.rootpid )
447#define shlvl (G_misc.shlvl )
Denys Vlasenko675d24a2018-01-27 22:02:05 +0100448#define errlinno (G_misc.errlinno )
Denis Vlasenko26bc57d2008-06-27 00:29:34 +0000449#define minusc (G_misc.minusc )
450#define curdir (G_misc.curdir )
451#define physdir (G_misc.physdir )
452#define arg0 (G_misc.arg0 )
Denis Vlasenko01631112007-12-16 17:20:38 +0000453#define exception_handler (G_misc.exception_handler)
Denis Vlasenko7f88e342009-03-19 03:36:18 +0000454#define exception_type (G_misc.exception_type )
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200455#define suppress_int (G_misc.suppress_int )
456#define pending_int (G_misc.pending_int )
Denys Vlasenko458c1f22016-10-27 23:51:19 +0200457#define got_sigchld (G_misc.got_sigchld )
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200458#define pending_sig (G_misc.pending_sig )
Denis Vlasenko26bc57d2008-06-27 00:29:34 +0000459#define nullstr (G_misc.nullstr )
460#define optlist (G_misc.optlist )
461#define sigmode (G_misc.sigmode )
462#define gotsig (G_misc.gotsig )
Denys Vlasenko238bf182010-05-18 15:49:07 +0200463#define may_have_traps (G_misc.may_have_traps )
Denis Vlasenko26bc57d2008-06-27 00:29:34 +0000464#define trap (G_misc.trap )
Denys Vlasenko21d87d42009-09-25 00:06:51 +0200465#define trap_ptr (G_misc.trap_ptr )
Denys Vlasenko3ea2e822009-10-09 20:59:04 +0200466#define random_gen (G_misc.random_gen )
Denis Vlasenko448d30e2008-06-27 00:24:11 +0000467#define backgndpid (G_misc.backgndpid )
Denis Vlasenko01631112007-12-16 17:20:38 +0000468#define INIT_G_misc() do { \
Denis Vlasenko574f2f42008-02-27 18:41:59 +0000469 (*(struct globals_misc**)&ash_ptr_to_globals_misc) = xzalloc(sizeof(G_misc)); \
470 barrier(); \
Denis Vlasenko01631112007-12-16 17:20:38 +0000471 curdir = nullstr; \
472 physdir = nullstr; \
Denys Vlasenko21d87d42009-09-25 00:06:51 +0200473 trap_ptr = trap; \
Denis Vlasenko01631112007-12-16 17:20:38 +0000474} while (0)
475
476
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000477/* ============ DEBUG */
478#if DEBUG
479static void trace_printf(const char *fmt, ...);
480static void trace_vprintf(const char *fmt, va_list va);
481# define TRACE(param) trace_printf param
482# define TRACEV(param) trace_vprintf param
Denis Vlasenko1bb3d7e2009-03-20 07:45:36 +0000483# define close(fd) do { \
484 int dfd = (fd); \
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +0000485 if (close(dfd) < 0) \
Denys Vlasenko883cea42009-07-11 15:31:59 +0200486 bb_error_msg("bug on %d: closing %d(0x%x)", \
Denis Vlasenko1bb3d7e2009-03-20 07:45:36 +0000487 __LINE__, dfd, dfd); \
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +0000488} while (0)
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000489#else
490# define TRACE(param)
491# define TRACEV(param)
492#endif
493
494
Denis Vlasenko559691a2008-10-05 18:39:31 +0000495/* ============ Utility functions */
Denys Vlasenko1961aea2013-02-26 00:36:53 +0100496#define is_name(c) ((c) == '_' || isalpha((unsigned char)(c)))
497#define is_in_name(c) ((c) == '_' || isalnum((unsigned char)(c)))
498
Denys Vlasenko37dc08b2016-10-02 04:38:07 +0200499static int
500isdigit_str9(const char *str)
Denis Vlasenko559691a2008-10-05 18:39:31 +0000501{
502 int maxlen = 9 + 1; /* max 9 digits: 999999999 */
503 while (--maxlen && isdigit(*str))
504 str++;
505 return (*str == '\0');
506}
Denis Vlasenko01631112007-12-16 17:20:38 +0000507
Denys Vlasenko37dc08b2016-10-02 04:38:07 +0200508static const char *
509var_end(const char *var)
Denys Vlasenko8837c5d2010-06-02 12:56:18 +0200510{
511 while (*var)
512 if (*var++ == '=')
513 break;
514 return var;
515}
516
Denis Vlasenko559691a2008-10-05 18:39:31 +0000517
518/* ============ Interrupts / exceptions */
Denys Vlasenko66c5b122011-02-08 05:07:02 +0100519
520static void exitshell(void) NORETURN;
521
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +0000522/*
Eric Andersen2870d962001-07-02 17:27:21 +0000523 * These macros allow the user to suspend the handling of interrupt signals
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +0000524 * over a period of time. This is similar to SIGHOLD or to sigblock, but
Eric Andersen2870d962001-07-02 17:27:21 +0000525 * much more efficient and portable. (But hacking the kernel is so much
526 * more fun than worrying about efficiency and portability. :-))
527 */
Denys Vlasenko06b11492016-11-04 16:43:18 +0100528#if DEBUG_INTONOFF
529# define INT_OFF do { \
530 TRACE(("%s:%d INT_OFF(%d)\n", __func__, __LINE__, suppress_int)); \
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200531 suppress_int++; \
Denys Vlasenkode892052016-10-02 01:49:13 +0200532 barrier(); \
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000533} while (0)
Denys Vlasenko06b11492016-11-04 16:43:18 +0100534#else
535# define INT_OFF do { \
536 suppress_int++; \
537 barrier(); \
538} while (0)
539#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +0000540
541/*
542 * Called to raise an exception. Since C doesn't include exceptions, we
543 * just do a longjmp to the exception handler. The type of exception is
Denis Vlasenko4b875702009-03-19 13:30:04 +0000544 * stored in the global variable "exception_type".
Denis Vlasenkob012b102007-02-19 22:43:01 +0000545 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000546static void raise_exception(int) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +0000547static void
548raise_exception(int e)
549{
550#if DEBUG
Denis Vlasenko2da584f2007-02-19 22:44:05 +0000551 if (exception_handler == NULL)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000552 abort();
553#endif
554 INT_OFF;
Denis Vlasenko7f88e342009-03-19 03:36:18 +0000555 exception_type = e;
Denis Vlasenko2da584f2007-02-19 22:44:05 +0000556 longjmp(exception_handler->loc, 1);
Denis Vlasenkob012b102007-02-19 22:43:01 +0000557}
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000558#if DEBUG
559#define raise_exception(e) do { \
560 TRACE(("raising exception %d on line %d\n", (e), __LINE__)); \
561 raise_exception(e); \
562} while (0)
563#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +0000564
565/*
Denys Vlasenkof37e1152016-10-07 03:17:28 +0200566 * Called when a SIGINT is received. (If the user specifies
Denis Vlasenkob012b102007-02-19 22:43:01 +0000567 * that SIGINT is to be trapped or ignored using the trap builtin, then
568 * this routine is not called.) Suppressint is nonzero when interrupts
569 * are held using the INT_OFF macro. (The test for iflag is just
570 * defensive programming.)
571 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000572static void raise_interrupt(void) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +0000573static void
574raise_interrupt(void)
575{
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200576 pending_int = 0;
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +0000577 /* Signal is not automatically unmasked after it is raised,
578 * do it ourself - unmask all signals */
Denis Vlasenko3f165fa2008-03-17 08:29:08 +0000579 sigprocmask_allsigs(SIG_UNBLOCK);
Denys Vlasenko238bf182010-05-18 15:49:07 +0200580 /* pending_sig = 0; - now done in signal_handler() */
Denis Vlasenko7c139b42007-03-21 20:17:27 +0000581
Denys Vlasenkoc0663c72016-10-27 21:09:01 +0200582 if (!(rootshell && iflag)) {
583 /* Kill ourself with SIGINT */
584 signal(SIGINT, SIG_DFL);
585 raise(SIGINT);
Denis Vlasenkob012b102007-02-19 22:43:01 +0000586 }
Denys Vlasenko4d12e942016-10-01 16:03:11 +0200587 /* bash: ^C even on empty command line sets $? */
588 exitstatus = SIGINT + 128;
Denys Vlasenkoc0663c72016-10-27 21:09:01 +0200589 raise_exception(EXINT);
Denis Vlasenkob012b102007-02-19 22:43:01 +0000590 /* NOTREACHED */
591}
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000592#if DEBUG
593#define raise_interrupt() do { \
594 TRACE(("raising interrupt on line %d\n", __LINE__)); \
595 raise_interrupt(); \
596} while (0)
597#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +0000598
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000599static IF_ASH_OPTIMIZE_FOR_SIZE(inline) void
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000600int_on(void)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000601{
Denys Vlasenkode892052016-10-02 01:49:13 +0200602 barrier();
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200603 if (--suppress_int == 0 && pending_int) {
Denis Vlasenkob012b102007-02-19 22:43:01 +0000604 raise_interrupt();
605 }
606}
Denys Vlasenko06b11492016-11-04 16:43:18 +0100607#if DEBUG_INTONOFF
608# define INT_ON do { \
609 TRACE(("%s:%d INT_ON(%d)\n", __func__, __LINE__, suppress_int-1)); \
610 int_on(); \
611} while (0)
612#else
613# define INT_ON int_on()
614#endif
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000615static IF_ASH_OPTIMIZE_FOR_SIZE(inline) void
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000616force_int_on(void)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000617{
Denys Vlasenkode892052016-10-02 01:49:13 +0200618 barrier();
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200619 suppress_int = 0;
620 if (pending_int)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000621 raise_interrupt();
622}
623#define FORCE_INT_ON force_int_on()
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000624
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200625#define SAVE_INT(v) ((v) = suppress_int)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000626
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000627#define RESTORE_INT(v) do { \
Denys Vlasenkode892052016-10-02 01:49:13 +0200628 barrier(); \
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200629 suppress_int = (v); \
630 if (suppress_int == 0 && pending_int) \
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000631 raise_interrupt(); \
632} while (0)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000633
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000634
Denis Vlasenkobc54cff2007-02-23 01:05:52 +0000635/* ============ Stdout/stderr output */
Eric Andersenc470f442003-07-28 09:56:35 +0000636
Eric Andersenc470f442003-07-28 09:56:35 +0000637static void
Denis Vlasenkob012b102007-02-19 22:43:01 +0000638outstr(const char *p, FILE *file)
Denis Vlasenkoe5570da2007-02-19 22:41:55 +0000639{
Denis Vlasenkob012b102007-02-19 22:43:01 +0000640 INT_OFF;
641 fputs(p, file);
642 INT_ON;
643}
644
645static void
646flush_stdout_stderr(void)
647{
648 INT_OFF;
Denys Vlasenko8131eea2009-11-02 14:19:51 +0100649 fflush_all();
Denis Vlasenkob012b102007-02-19 22:43:01 +0000650 INT_ON;
651}
652
Denys Vlasenko9c541002015-10-07 15:44:36 +0200653/* Was called outcslow(c,FILE*), but c was always '\n' */
Denis Vlasenkob012b102007-02-19 22:43:01 +0000654static void
Denys Vlasenko9c541002015-10-07 15:44:36 +0200655newline_and_flush(FILE *dest)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000656{
657 INT_OFF;
Denys Vlasenko9c541002015-10-07 15:44:36 +0200658 putc('\n', dest);
Denis Vlasenkob012b102007-02-19 22:43:01 +0000659 fflush(dest);
660 INT_ON;
661}
662
663static int out1fmt(const char *, ...) __attribute__((__format__(__printf__,1,2)));
664static int
665out1fmt(const char *fmt, ...)
666{
667 va_list ap;
668 int r;
669
670 INT_OFF;
671 va_start(ap, fmt);
672 r = vprintf(fmt, ap);
673 va_end(ap);
674 INT_ON;
675 return r;
676}
677
678static int fmtstr(char *, size_t, const char *, ...) __attribute__((__format__(__printf__,3,4)));
679static int
680fmtstr(char *outbuf, size_t length, const char *fmt, ...)
681{
682 va_list ap;
683 int ret;
684
Denis Vlasenkob012b102007-02-19 22:43:01 +0000685 INT_OFF;
Denys Vlasenkocf3a7962017-07-26 14:38:19 +0200686 va_start(ap, fmt);
Denis Vlasenkob012b102007-02-19 22:43:01 +0000687 ret = vsnprintf(outbuf, length, fmt, ap);
688 va_end(ap);
689 INT_ON;
690 return ret;
691}
692
693static void
694out1str(const char *p)
695{
696 outstr(p, stdout);
697}
698
699static void
700out2str(const char *p)
701{
702 outstr(p, stderr);
Denys Vlasenko8131eea2009-11-02 14:19:51 +0100703 flush_stdout_stderr();
Denis Vlasenkob012b102007-02-19 22:43:01 +0000704}
705
706
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +0000707/* ============ Parser structures */
Denis Vlasenko4d2183b2007-02-23 01:05:38 +0000708
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000709/* control characters in argument strings */
Denys Vlasenko2ce42e92009-11-29 02:18:13 +0100710#define CTL_FIRST CTLESC
Denys Vlasenkob6c84342009-08-29 20:23:20 +0200711#define CTLESC ((unsigned char)'\201') /* escape next character */
712#define CTLVAR ((unsigned char)'\202') /* variable defn */
713#define CTLENDVAR ((unsigned char)'\203')
714#define CTLBACKQ ((unsigned char)'\204')
Denys Vlasenkob6c84342009-08-29 20:23:20 +0200715#define CTLARI ((unsigned char)'\206') /* arithmetic expression */
716#define CTLENDARI ((unsigned char)'\207')
717#define CTLQUOTEMARK ((unsigned char)'\210')
Denys Vlasenko2ce42e92009-11-29 02:18:13 +0100718#define CTL_LAST CTLQUOTEMARK
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000719
720/* variable substitution byte (follows CTLVAR) */
721#define VSTYPE 0x0f /* type of variable substitution */
722#define VSNUL 0x10 /* colon--treat the empty string as unset */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000723
724/* values of VSTYPE field */
Denis Vlasenko92e13c22008-03-25 01:17:40 +0000725#define VSNORMAL 0x1 /* normal variable: $var or ${var} */
726#define VSMINUS 0x2 /* ${var-text} */
727#define VSPLUS 0x3 /* ${var+text} */
728#define VSQUESTION 0x4 /* ${var?message} */
729#define VSASSIGN 0x5 /* ${var=text} */
730#define VSTRIMRIGHT 0x6 /* ${var%pattern} */
731#define VSTRIMRIGHTMAX 0x7 /* ${var%%pattern} */
732#define VSTRIMLEFT 0x8 /* ${var#pattern} */
733#define VSTRIMLEFTMAX 0x9 /* ${var##pattern} */
734#define VSLENGTH 0xa /* ${#var} */
Denys Vlasenko7d4aec02017-01-11 14:00:38 +0100735#if BASH_SUBSTR
Denis Vlasenko92e13c22008-03-25 01:17:40 +0000736#define VSSUBSTR 0xc /* ${var:position:length} */
Denys Vlasenko7d4aec02017-01-11 14:00:38 +0100737#endif
738#if BASH_PATTERN_SUBST
Denis Vlasenko92e13c22008-03-25 01:17:40 +0000739#define VSREPLACE 0xd /* ${var/pattern/replacement} */
740#define VSREPLACEALL 0xe /* ${var//pattern/replacement} */
741#endif
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000742
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000743static const char dolatstr[] ALIGN1 = {
Ron Yorston549deab2015-05-18 09:57:51 +0200744 CTLQUOTEMARK, CTLVAR, VSNORMAL, '@', '=', CTLQUOTEMARK, '\0'
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000745};
Ron Yorston549deab2015-05-18 09:57:51 +0200746#define DOLATSTRLEN 6
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +0000747
Denis Vlasenko559691a2008-10-05 18:39:31 +0000748#define NCMD 0
749#define NPIPE 1
750#define NREDIR 2
751#define NBACKGND 3
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000752#define NSUBSHELL 4
Denis Vlasenko559691a2008-10-05 18:39:31 +0000753#define NAND 5
754#define NOR 6
755#define NSEMI 7
756#define NIF 8
757#define NWHILE 9
758#define NUNTIL 10
759#define NFOR 11
760#define NCASE 12
761#define NCLIST 13
762#define NDEFUN 14
763#define NARG 15
764#define NTO 16
Denys Vlasenko7d4aec02017-01-11 14:00:38 +0100765#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +0000766#define NTO2 17
767#endif
768#define NCLOBBER 18
769#define NFROM 19
770#define NFROMTO 20
771#define NAPPEND 21
772#define NTOFD 22
773#define NFROMFD 23
774#define NHERE 24
775#define NXHERE 25
776#define NNOT 26
Denis Vlasenko340299a2008-11-21 10:36:36 +0000777#define N_NUMBER 27
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000778
779union node;
780
781struct ncmd {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000782 smallint type; /* Nxxxx */
Denys Vlasenko675d24a2018-01-27 22:02:05 +0100783 int linno;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000784 union node *assign;
785 union node *args;
786 union node *redirect;
787};
788
789struct npipe {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000790 smallint type;
791 smallint pipe_backgnd;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000792 struct nodelist *cmdlist;
793};
794
795struct nredir {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000796 smallint type;
Denys Vlasenko675d24a2018-01-27 22:02:05 +0100797 int linno;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000798 union node *n;
799 union node *redirect;
800};
801
802struct nbinary {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000803 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000804 union node *ch1;
805 union node *ch2;
806};
807
808struct nif {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000809 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000810 union node *test;
811 union node *ifpart;
812 union node *elsepart;
813};
814
815struct nfor {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000816 smallint type;
Denys Vlasenko675d24a2018-01-27 22:02:05 +0100817 int linno;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000818 union node *args;
819 union node *body;
820 char *var;
821};
822
823struct ncase {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000824 smallint type;
Denys Vlasenko675d24a2018-01-27 22:02:05 +0100825 int linno;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000826 union node *expr;
827 union node *cases;
828};
829
830struct nclist {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000831 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000832 union node *next;
833 union node *pattern;
834 union node *body;
835};
836
Denys Vlasenko675d24a2018-01-27 22:02:05 +0100837struct ndefun {
838 smallint type;
839 int linno;
840 char *text;
841 union node *body;
842};
843
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000844struct narg {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000845 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000846 union node *next;
847 char *text;
848 struct nodelist *backquote;
849};
850
Denis Vlasenko559691a2008-10-05 18:39:31 +0000851/* nfile and ndup layout must match!
852 * NTOFD (>&fdnum) uses ndup structure, but we may discover mid-flight
853 * that it is actually NTO2 (>&file), and change its type.
854 */
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000855struct nfile {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000856 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000857 union node *next;
858 int fd;
Denis Vlasenko559691a2008-10-05 18:39:31 +0000859 int _unused_dupfd;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000860 union node *fname;
861 char *expfname;
862};
863
864struct ndup {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000865 smallint type;
Denis Vlasenko559691a2008-10-05 18:39:31 +0000866 union node *next;
867 int fd;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000868 int dupfd;
869 union node *vname;
Denis Vlasenko559691a2008-10-05 18:39:31 +0000870 char *_unused_expfname;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000871};
872
873struct nhere {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000874 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000875 union node *next;
876 int fd;
877 union node *doc;
878};
879
880struct nnot {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000881 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000882 union node *com;
883};
884
885union node {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000886 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000887 struct ncmd ncmd;
888 struct npipe npipe;
889 struct nredir nredir;
890 struct nbinary nbinary;
891 struct nif nif;
892 struct nfor nfor;
893 struct ncase ncase;
894 struct nclist nclist;
Denys Vlasenko675d24a2018-01-27 22:02:05 +0100895 struct ndefun ndefun;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000896 struct narg narg;
897 struct nfile nfile;
898 struct ndup ndup;
899 struct nhere nhere;
900 struct nnot nnot;
901};
902
Denys Vlasenko86e83ec2009-07-23 22:07:07 +0200903/*
904 * NODE_EOF is returned by parsecmd when it encounters an end of file.
905 * It must be distinct from NULL.
906 */
907#define NODE_EOF ((union node *) -1L)
908
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000909struct nodelist {
910 struct nodelist *next;
911 union node *n;
912};
913
914struct funcnode {
915 int count;
916 union node n;
917};
918
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000919/*
920 * Free a parse tree.
921 */
922static void
923freefunc(struct funcnode *f)
924{
925 if (f && --f->count < 0)
926 free(f);
927}
928
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000929
930/* ============ Debugging output */
931
932#if DEBUG
933
934static FILE *tracefile;
935
936static void
937trace_printf(const char *fmt, ...)
938{
939 va_list va;
940
941 if (debug != 1)
942 return;
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000943 if (DEBUG_TIME)
944 fprintf(tracefile, "%u ", (int) time(NULL));
945 if (DEBUG_PID)
946 fprintf(tracefile, "[%u] ", (int) getpid());
947 if (DEBUG_SIG)
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200948 fprintf(tracefile, "pending s:%d i:%d(supp:%d) ", pending_sig, pending_int, suppress_int);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000949 va_start(va, fmt);
950 vfprintf(tracefile, fmt, va);
951 va_end(va);
952}
953
954static void
955trace_vprintf(const char *fmt, va_list va)
956{
957 if (debug != 1)
958 return;
959 vfprintf(tracefile, fmt, va);
Denys Vlasenko474ed062016-10-30 18:30:29 +0100960 fprintf(tracefile, "\n");
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000961}
962
963static void
964trace_puts(const char *s)
965{
966 if (debug != 1)
967 return;
968 fputs(s, tracefile);
969}
970
971static void
972trace_puts_quoted(char *s)
973{
974 char *p;
975 char c;
976
977 if (debug != 1)
978 return;
979 putc('"', tracefile);
980 for (p = s; *p; p++) {
Denys Vlasenkocd716832009-11-28 22:14:02 +0100981 switch ((unsigned char)*p) {
982 case '\n': c = 'n'; goto backslash;
983 case '\t': c = 't'; goto backslash;
984 case '\r': c = 'r'; goto backslash;
985 case '\"': c = '\"'; goto backslash;
986 case '\\': c = '\\'; goto backslash;
987 case CTLESC: c = 'e'; goto backslash;
988 case CTLVAR: c = 'v'; goto backslash;
Denys Vlasenkocd716832009-11-28 22:14:02 +0100989 case CTLBACKQ: c = 'q'; goto backslash;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000990 backslash:
991 putc('\\', tracefile);
992 putc(c, tracefile);
993 break;
994 default:
995 if (*p >= ' ' && *p <= '~')
996 putc(*p, tracefile);
997 else {
998 putc('\\', tracefile);
Denys Vlasenkocd716832009-11-28 22:14:02 +0100999 putc((*p >> 6) & 03, tracefile);
1000 putc((*p >> 3) & 07, tracefile);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001001 putc(*p & 07, tracefile);
1002 }
1003 break;
1004 }
1005 }
1006 putc('"', tracefile);
1007}
1008
1009static void
1010trace_puts_args(char **ap)
1011{
1012 if (debug != 1)
1013 return;
1014 if (!*ap)
1015 return;
1016 while (1) {
1017 trace_puts_quoted(*ap);
1018 if (!*++ap) {
1019 putc('\n', tracefile);
1020 break;
1021 }
1022 putc(' ', tracefile);
1023 }
1024}
1025
1026static void
1027opentrace(void)
1028{
1029 char s[100];
1030#ifdef O_APPEND
1031 int flags;
1032#endif
1033
1034 if (debug != 1) {
1035 if (tracefile)
1036 fflush(tracefile);
1037 /* leave open because libedit might be using it */
1038 return;
1039 }
1040 strcpy(s, "./trace");
1041 if (tracefile) {
1042 if (!freopen(s, "a", tracefile)) {
1043 fprintf(stderr, "Can't re-open %s\n", s);
1044 debug = 0;
1045 return;
1046 }
1047 } else {
1048 tracefile = fopen(s, "a");
1049 if (tracefile == NULL) {
1050 fprintf(stderr, "Can't open %s\n", s);
1051 debug = 0;
1052 return;
1053 }
1054 }
1055#ifdef O_APPEND
Denis Vlasenkod37f2222007-08-19 13:42:08 +00001056 flags = fcntl(fileno(tracefile), F_GETFL);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001057 if (flags >= 0)
1058 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
1059#endif
1060 setlinebuf(tracefile);
1061 fputs("\nTracing started.\n", tracefile);
1062}
1063
1064static void
1065indent(int amount, char *pfx, FILE *fp)
1066{
1067 int i;
1068
1069 for (i = 0; i < amount; i++) {
1070 if (pfx && i == amount - 1)
1071 fputs(pfx, fp);
1072 putc('\t', fp);
1073 }
1074}
1075
1076/* little circular references here... */
1077static void shtree(union node *n, int ind, char *pfx, FILE *fp);
1078
1079static void
1080sharg(union node *arg, FILE *fp)
1081{
1082 char *p;
1083 struct nodelist *bqlist;
Denys Vlasenkocd716832009-11-28 22:14:02 +01001084 unsigned char subtype;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001085
1086 if (arg->type != NARG) {
1087 out1fmt("<node type %d>\n", arg->type);
1088 abort();
1089 }
1090 bqlist = arg->narg.backquote;
1091 for (p = arg->narg.text; *p; p++) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01001092 switch ((unsigned char)*p) {
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001093 case CTLESC:
Dan Fandrich77d48722010-09-07 23:38:28 -07001094 p++;
1095 putc(*p, fp);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001096 break;
1097 case CTLVAR:
1098 putc('$', fp);
1099 putc('{', fp);
1100 subtype = *++p;
1101 if (subtype == VSLENGTH)
1102 putc('#', fp);
1103
Dan Fandrich77d48722010-09-07 23:38:28 -07001104 while (*p != '=') {
1105 putc(*p, fp);
1106 p++;
1107 }
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001108
1109 if (subtype & VSNUL)
1110 putc(':', fp);
1111
1112 switch (subtype & VSTYPE) {
1113 case VSNORMAL:
1114 putc('}', fp);
1115 break;
1116 case VSMINUS:
1117 putc('-', fp);
1118 break;
1119 case VSPLUS:
1120 putc('+', fp);
1121 break;
1122 case VSQUESTION:
1123 putc('?', fp);
1124 break;
1125 case VSASSIGN:
1126 putc('=', fp);
1127 break;
1128 case VSTRIMLEFT:
1129 putc('#', fp);
1130 break;
1131 case VSTRIMLEFTMAX:
1132 putc('#', fp);
1133 putc('#', fp);
1134 break;
1135 case VSTRIMRIGHT:
1136 putc('%', fp);
1137 break;
1138 case VSTRIMRIGHTMAX:
1139 putc('%', fp);
1140 putc('%', fp);
1141 break;
1142 case VSLENGTH:
1143 break;
1144 default:
1145 out1fmt("<subtype %d>", subtype);
1146 }
1147 break;
1148 case CTLENDVAR:
1149 putc('}', fp);
1150 break;
1151 case CTLBACKQ:
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001152 putc('$', fp);
1153 putc('(', fp);
1154 shtree(bqlist->n, -1, NULL, fp);
1155 putc(')', fp);
1156 break;
1157 default:
1158 putc(*p, fp);
1159 break;
1160 }
1161 }
1162}
1163
Denys Vlasenko641dd7b2009-06-11 19:30:19 +02001164static void
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001165shcmd(union node *cmd, FILE *fp)
1166{
1167 union node *np;
1168 int first;
1169 const char *s;
1170 int dftfd;
1171
1172 first = 1;
1173 for (np = cmd->ncmd.args; np; np = np->narg.next) {
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001174 if (!first)
1175 putc(' ', fp);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001176 sharg(np, fp);
1177 first = 0;
1178 }
1179 for (np = cmd->ncmd.redirect; np; np = np->nfile.next) {
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001180 if (!first)
1181 putc(' ', fp);
1182 dftfd = 0;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001183 switch (np->nfile.type) {
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001184 case NTO: s = ">>"+1; dftfd = 1; break;
1185 case NCLOBBER: s = ">|"; dftfd = 1; break;
1186 case NAPPEND: s = ">>"; dftfd = 1; break;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01001187#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00001188 case NTO2:
1189#endif
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001190 case NTOFD: s = ">&"; dftfd = 1; break;
Denis Vlasenko559691a2008-10-05 18:39:31 +00001191 case NFROM: s = "<"; break;
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001192 case NFROMFD: s = "<&"; break;
1193 case NFROMTO: s = "<>"; break;
1194 default: s = "*error*"; break;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001195 }
1196 if (np->nfile.fd != dftfd)
1197 fprintf(fp, "%d", np->nfile.fd);
1198 fputs(s, fp);
1199 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
1200 fprintf(fp, "%d", np->ndup.dupfd);
1201 } else {
1202 sharg(np->nfile.fname, fp);
1203 }
1204 first = 0;
1205 }
1206}
1207
1208static void
1209shtree(union node *n, int ind, char *pfx, FILE *fp)
1210{
1211 struct nodelist *lp;
1212 const char *s;
1213
1214 if (n == NULL)
1215 return;
1216
1217 indent(ind, pfx, fp);
Denys Vlasenko86e83ec2009-07-23 22:07:07 +02001218
1219 if (n == NODE_EOF) {
1220 fputs("<EOF>", fp);
1221 return;
1222 }
1223
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001224 switch (n->type) {
1225 case NSEMI:
1226 s = "; ";
1227 goto binop;
1228 case NAND:
1229 s = " && ";
1230 goto binop;
1231 case NOR:
1232 s = " || ";
1233 binop:
1234 shtree(n->nbinary.ch1, ind, NULL, fp);
1235 /* if (ind < 0) */
1236 fputs(s, fp);
1237 shtree(n->nbinary.ch2, ind, NULL, fp);
1238 break;
1239 case NCMD:
1240 shcmd(n, fp);
1241 if (ind >= 0)
1242 putc('\n', fp);
1243 break;
1244 case NPIPE:
1245 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
Denys Vlasenko7cee00e2009-07-24 01:08:03 +02001246 shtree(lp->n, 0, NULL, fp);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001247 if (lp->next)
1248 fputs(" | ", fp);
1249 }
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00001250 if (n->npipe.pipe_backgnd)
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001251 fputs(" &", fp);
1252 if (ind >= 0)
1253 putc('\n', fp);
1254 break;
1255 default:
1256 fprintf(fp, "<node type %d>", n->type);
1257 if (ind >= 0)
1258 putc('\n', fp);
1259 break;
1260 }
1261}
1262
1263static void
1264showtree(union node *n)
1265{
1266 trace_puts("showtree called\n");
Denys Vlasenko883cea42009-07-11 15:31:59 +02001267 shtree(n, 1, NULL, stderr);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001268}
1269
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001270#endif /* DEBUG */
1271
1272
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00001273/* ============ Parser data */
1274
1275/*
Denis Vlasenkob012b102007-02-19 22:43:01 +00001276 * ash_vmsg() needs parsefile->fd, hence parsefile definition is moved up.
1277 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001278struct strlist {
1279 struct strlist *next;
1280 char *text;
1281};
1282
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001283struct alias;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001284
Denis Vlasenkob012b102007-02-19 22:43:01 +00001285struct strpush {
1286 struct strpush *prev; /* preceding string on stack */
Denis Vlasenko41eb3002008-11-28 03:42:31 +00001287 char *prev_string;
1288 int prev_left_in_line;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001289#if ENABLE_ASH_ALIAS
1290 struct alias *ap; /* if push was associated with an alias */
1291#endif
1292 char *string; /* remember the string since it may change */
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02001293
1294 /* Remember last two characters for pungetc. */
1295 int lastc[2];
1296
1297 /* Number of outstanding calls to pungetc. */
1298 int unget;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001299};
1300
Denys Vlasenko0485b672017-08-14 19:46:56 +02001301/*
1302 * The parsefile structure pointed to by the global variable parsefile
1303 * contains information about the current file being read.
1304 */
Denis Vlasenkob012b102007-02-19 22:43:01 +00001305struct parsefile {
1306 struct parsefile *prev; /* preceding file on stack */
1307 int linno; /* current line */
Denys Vlasenko79b3d422010-06-03 04:29:08 +02001308 int pf_fd; /* file descriptor (or -1 if string) */
Denis Vlasenko41eb3002008-11-28 03:42:31 +00001309 int left_in_line; /* number of chars left in this line */
1310 int left_in_buffer; /* number of chars left in this buffer past the line */
1311 char *next_to_pgetc; /* next char in buffer */
Denis Vlasenkob012b102007-02-19 22:43:01 +00001312 char *buf; /* input buffer */
1313 struct strpush *strpush; /* for pushing strings at this level */
1314 struct strpush basestrpush; /* so pushing one is fast */
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02001315
1316 /* Remember last two characters for pungetc. */
1317 int lastc[2];
1318
1319 /* Number of outstanding calls to pungetc. */
1320 int unget;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001321};
1322
Denis Vlasenko448d30e2008-06-27 00:24:11 +00001323static struct parsefile basepf; /* top level input file */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00001324static struct parsefile *g_parsefile = &basepf; /* current input file */
Denis Vlasenkob012b102007-02-19 22:43:01 +00001325static char *commandname; /* currently executing command */
Denis Vlasenkob012b102007-02-19 22:43:01 +00001326
1327
1328/* ============ Message printing */
1329
1330static void
1331ash_vmsg(const char *msg, va_list ap)
1332{
1333 fprintf(stderr, "%s: ", arg0);
1334 if (commandname) {
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00001335 if (strcmp(arg0, commandname))
1336 fprintf(stderr, "%s: ", commandname);
Denys Vlasenko79b3d422010-06-03 04:29:08 +02001337 if (!iflag || g_parsefile->pf_fd > 0)
Denys Vlasenko675d24a2018-01-27 22:02:05 +01001338 fprintf(stderr, "line %d: ", errlinno);
Eric Andersenc470f442003-07-28 09:56:35 +00001339 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00001340 vfprintf(stderr, msg, ap);
Denys Vlasenko9c541002015-10-07 15:44:36 +02001341 newline_and_flush(stderr);
Eric Andersenc470f442003-07-28 09:56:35 +00001342}
Denis Vlasenkob012b102007-02-19 22:43:01 +00001343
1344/*
1345 * Exverror is called to raise the error exception. If the second argument
1346 * is not NULL then error prints an error message using printf style
1347 * formatting. It then raises the error exception.
1348 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00001349static void ash_vmsg_and_raise(int, const char *, va_list) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001350static void
1351ash_vmsg_and_raise(int cond, const char *msg, va_list ap)
Eric Andersenc470f442003-07-28 09:56:35 +00001352{
Denis Vlasenkob012b102007-02-19 22:43:01 +00001353#if DEBUG
1354 if (msg) {
Denys Vlasenko474ed062016-10-30 18:30:29 +01001355 TRACE(("ash_vmsg_and_raise(%d):", cond));
Denis Vlasenkob012b102007-02-19 22:43:01 +00001356 TRACEV((msg, ap));
Denis Vlasenkob012b102007-02-19 22:43:01 +00001357 } else
Denys Vlasenko474ed062016-10-30 18:30:29 +01001358 TRACE(("ash_vmsg_and_raise(%d):NULL\n", cond));
Denis Vlasenkob012b102007-02-19 22:43:01 +00001359 if (msg)
1360#endif
1361 ash_vmsg(msg, ap);
1362
1363 flush_stdout_stderr();
1364 raise_exception(cond);
1365 /* NOTREACHED */
Eric Andersenc470f442003-07-28 09:56:35 +00001366}
Denis Vlasenkob012b102007-02-19 22:43:01 +00001367
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00001368static void ash_msg_and_raise_error(const char *, ...) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001369static void
1370ash_msg_and_raise_error(const char *msg, ...)
1371{
1372 va_list ap;
1373
Ron Yorstonea7d2f62017-01-03 11:18:23 +01001374 exitstatus = 2;
1375
Denis Vlasenkob012b102007-02-19 22:43:01 +00001376 va_start(ap, msg);
1377 ash_vmsg_and_raise(EXERROR, msg, ap);
1378 /* NOTREACHED */
1379 va_end(ap);
1380}
1381
Ron Yorstonbe366e52017-07-27 13:53:39 +01001382/*
Ron Yorstonbe366e52017-07-27 13:53:39 +01001383 * 'fmt' must be a string literal.
1384 */
Denys Vlasenko6f97b302017-09-29 18:17:25 +02001385#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 +01001386
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00001387static void raise_error_syntax(const char *) NORETURN;
1388static void
1389raise_error_syntax(const char *msg)
1390{
Denys Vlasenko675d24a2018-01-27 22:02:05 +01001391 errlinno = g_parsefile->linno;
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00001392 ash_msg_and_raise_error("syntax error: %s", msg);
1393 /* NOTREACHED */
1394}
1395
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00001396static void ash_msg_and_raise(int, const char *, ...) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001397static void
1398ash_msg_and_raise(int cond, const char *msg, ...)
1399{
1400 va_list ap;
1401
1402 va_start(ap, msg);
1403 ash_vmsg_and_raise(cond, msg, ap);
1404 /* NOTREACHED */
1405 va_end(ap);
1406}
1407
1408/*
1409 * error/warning routines for external builtins
1410 */
1411static void
1412ash_msg(const char *fmt, ...)
1413{
1414 va_list ap;
1415
1416 va_start(ap, fmt);
1417 ash_vmsg(fmt, ap);
1418 va_end(ap);
1419}
1420
1421/*
1422 * Return a string describing an error. The returned string may be a
1423 * pointer to a static buffer that will be overwritten on the next call.
1424 * Action describes the operation that got the error.
1425 */
1426static const char *
1427errmsg(int e, const char *em)
1428{
1429 if (e == ENOENT || e == ENOTDIR) {
1430 return em;
1431 }
1432 return strerror(e);
1433}
1434
1435
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001436/* ============ Memory allocation */
1437
Denys Vlasenkoe7670ff2009-10-11 00:45:25 +02001438#if 0
1439/* I consider these wrappers nearly useless:
1440 * ok, they return you to nearest exception handler, but
1441 * how much memory do you leak in the process, making
1442 * memory starvation worse?
1443 */
1444static void *
1445ckrealloc(void * p, size_t nbytes)
1446{
1447 p = realloc(p, nbytes);
1448 if (!p)
1449 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1450 return p;
1451}
1452
1453static void *
1454ckmalloc(size_t nbytes)
1455{
1456 return ckrealloc(NULL, nbytes);
1457}
1458
1459static void *
1460ckzalloc(size_t nbytes)
1461{
1462 return memset(ckmalloc(nbytes), 0, nbytes);
1463}
1464
1465static char *
1466ckstrdup(const char *s)
1467{
1468 char *p = strdup(s);
1469 if (!p)
1470 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1471 return p;
1472}
1473#else
1474/* Using bbox equivalents. They exit if out of memory */
1475# define ckrealloc xrealloc
1476# define ckmalloc xmalloc
1477# define ckzalloc xzalloc
1478# define ckstrdup xstrdup
1479#endif
1480
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001481/*
1482 * It appears that grabstackstr() will barf with such alignments
1483 * because stalloc() will return a string allocated in a new stackblock.
1484 */
1485#define SHELL_ALIGN(nbytes) (((nbytes) + SHELL_SIZE) & ~SHELL_SIZE)
1486enum {
1487 /* Most machines require the value returned from malloc to be aligned
1488 * in some way. The following macro will get this right
1489 * on many machines. */
Denys Vlasenko0e5e4ea2009-10-11 00:36:20 +02001490 SHELL_SIZE = sizeof(union { int i; char *cp; double d; }) - 1,
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001491 /* Minimum size of a block */
Denis Vlasenko01631112007-12-16 17:20:38 +00001492 MINSIZE = SHELL_ALIGN(504),
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001493};
1494
1495struct stack_block {
1496 struct stack_block *prev;
1497 char space[MINSIZE];
1498};
1499
1500struct stackmark {
1501 struct stack_block *stackp;
1502 char *stacknxt;
1503 size_t stacknleft;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001504};
1505
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001506
Denis Vlasenko01631112007-12-16 17:20:38 +00001507struct globals_memstack {
1508 struct stack_block *g_stackp; // = &stackbase;
Denis Vlasenko01631112007-12-16 17:20:38 +00001509 char *g_stacknxt; // = stackbase.space;
1510 char *sstrend; // = stackbase.space + MINSIZE;
1511 size_t g_stacknleft; // = MINSIZE;
Denis Vlasenko01631112007-12-16 17:20:38 +00001512 struct stack_block stackbase;
1513};
Denys Vlasenko6f9442f2018-01-28 20:41:23 +01001514extern struct globals_memstack *BB_GLOBAL_CONST ash_ptr_to_globals_memstack;
Denis Vlasenko574f2f42008-02-27 18:41:59 +00001515#define G_memstack (*ash_ptr_to_globals_memstack)
Denis Vlasenko01631112007-12-16 17:20:38 +00001516#define g_stackp (G_memstack.g_stackp )
Denis Vlasenko01631112007-12-16 17:20:38 +00001517#define g_stacknxt (G_memstack.g_stacknxt )
1518#define sstrend (G_memstack.sstrend )
1519#define g_stacknleft (G_memstack.g_stacknleft)
Denis Vlasenko01631112007-12-16 17:20:38 +00001520#define stackbase (G_memstack.stackbase )
1521#define INIT_G_memstack() do { \
Denis Vlasenko574f2f42008-02-27 18:41:59 +00001522 (*(struct globals_memstack**)&ash_ptr_to_globals_memstack) = xzalloc(sizeof(G_memstack)); \
1523 barrier(); \
Denis Vlasenko01631112007-12-16 17:20:38 +00001524 g_stackp = &stackbase; \
1525 g_stacknxt = stackbase.space; \
1526 g_stacknleft = MINSIZE; \
1527 sstrend = stackbase.space + MINSIZE; \
Denis Vlasenko01631112007-12-16 17:20:38 +00001528} while (0)
1529
Denys Vlasenkoe7670ff2009-10-11 00:45:25 +02001530
Denis Vlasenko01631112007-12-16 17:20:38 +00001531#define stackblock() ((void *)g_stacknxt)
1532#define stackblocksize() g_stacknleft
1533
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001534/*
1535 * Parse trees for commands are allocated in lifo order, so we use a stack
1536 * to make this more efficient, and also to avoid all sorts of exception
1537 * handling code to handle interrupts in the middle of a parse.
1538 *
1539 * The size 504 was chosen because the Ultrix malloc handles that size
1540 * well.
1541 */
1542static void *
1543stalloc(size_t nbytes)
1544{
1545 char *p;
1546 size_t aligned;
1547
1548 aligned = SHELL_ALIGN(nbytes);
Denis Vlasenko01631112007-12-16 17:20:38 +00001549 if (aligned > g_stacknleft) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001550 size_t len;
1551 size_t blocksize;
1552 struct stack_block *sp;
1553
1554 blocksize = aligned;
1555 if (blocksize < MINSIZE)
1556 blocksize = MINSIZE;
1557 len = sizeof(struct stack_block) - MINSIZE + blocksize;
1558 if (len < blocksize)
1559 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1560 INT_OFF;
1561 sp = ckmalloc(len);
Denis Vlasenko01631112007-12-16 17:20:38 +00001562 sp->prev = g_stackp;
1563 g_stacknxt = sp->space;
1564 g_stacknleft = blocksize;
1565 sstrend = g_stacknxt + blocksize;
1566 g_stackp = sp;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001567 INT_ON;
1568 }
Denis Vlasenko01631112007-12-16 17:20:38 +00001569 p = g_stacknxt;
1570 g_stacknxt += aligned;
1571 g_stacknleft -= aligned;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001572 return p;
1573}
1574
Denis Vlasenko597906c2008-02-20 16:38:54 +00001575static void *
1576stzalloc(size_t nbytes)
1577{
1578 return memset(stalloc(nbytes), 0, nbytes);
1579}
1580
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001581static void
1582stunalloc(void *p)
1583{
1584#if DEBUG
Denis Vlasenko01631112007-12-16 17:20:38 +00001585 if (!p || (g_stacknxt < (char *)p) || ((char *)p < g_stackp->space)) {
Bernhard Reutner-Fischer5e25ddb2008-05-19 09:48:17 +00001586 write(STDERR_FILENO, "stunalloc\n", 10);
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001587 abort();
1588 }
1589#endif
Denis Vlasenko01631112007-12-16 17:20:38 +00001590 g_stacknleft += g_stacknxt - (char *)p;
1591 g_stacknxt = p;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001592}
1593
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001594/*
1595 * Like strdup but works with the ash stack.
1596 */
1597static char *
Denys Vlasenko8e2bc472016-09-28 23:02:57 +02001598sstrdup(const char *p)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001599{
1600 size_t len = strlen(p) + 1;
1601 return memcpy(stalloc(len), p, len);
1602}
1603
Denys Vlasenko03c36e02018-01-10 15:18:35 +01001604static ALWAYS_INLINE void
Denys Vlasenko60ca8342016-09-30 11:21:21 +02001605grabstackblock(size_t len)
1606{
Denys Vlasenkoa318bba2016-10-26 18:26:27 +02001607 stalloc(len);
Denys Vlasenko60ca8342016-09-30 11:21:21 +02001608}
1609
1610static void
1611pushstackmark(struct stackmark *mark, size_t len)
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001612{
Denis Vlasenko01631112007-12-16 17:20:38 +00001613 mark->stackp = g_stackp;
1614 mark->stacknxt = g_stacknxt;
1615 mark->stacknleft = g_stacknleft;
Denys Vlasenko60ca8342016-09-30 11:21:21 +02001616 grabstackblock(len);
1617}
1618
1619static void
1620setstackmark(struct stackmark *mark)
1621{
1622 pushstackmark(mark, g_stacknxt == g_stackp->space && g_stackp != &stackbase);
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001623}
1624
1625static void
1626popstackmark(struct stackmark *mark)
1627{
1628 struct stack_block *sp;
1629
Denis Vlasenko93ebd4f2007-03-13 20:55:36 +00001630 if (!mark->stackp)
1631 return;
1632
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001633 INT_OFF;
Denis Vlasenko01631112007-12-16 17:20:38 +00001634 while (g_stackp != mark->stackp) {
1635 sp = g_stackp;
1636 g_stackp = sp->prev;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001637 free(sp);
1638 }
Denis Vlasenko01631112007-12-16 17:20:38 +00001639 g_stacknxt = mark->stacknxt;
1640 g_stacknleft = mark->stacknleft;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001641 sstrend = mark->stacknxt + mark->stacknleft;
1642 INT_ON;
1643}
1644
1645/*
1646 * When the parser reads in a string, it wants to stick the string on the
1647 * stack and only adjust the stack pointer when it knows how big the
1648 * string is. Stackblock (defined in stack.h) returns a pointer to a block
1649 * of space on top of the stack and stackblocklen returns the length of
1650 * this block. Growstackblock will grow this space by at least one byte,
1651 * possibly moving it (like realloc). Grabstackblock actually allocates the
1652 * part of the block that has been used.
1653 */
1654static void
1655growstackblock(void)
1656{
1657 size_t newlen;
1658
Denis Vlasenko01631112007-12-16 17:20:38 +00001659 newlen = g_stacknleft * 2;
1660 if (newlen < g_stacknleft)
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001661 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1662 if (newlen < 128)
1663 newlen += 128;
1664
Denis Vlasenko01631112007-12-16 17:20:38 +00001665 if (g_stacknxt == g_stackp->space && g_stackp != &stackbase) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001666 struct stack_block *sp;
1667 struct stack_block *prevstackp;
1668 size_t grosslen;
1669
1670 INT_OFF;
Denis Vlasenko01631112007-12-16 17:20:38 +00001671 sp = g_stackp;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001672 prevstackp = sp->prev;
1673 grosslen = newlen + sizeof(struct stack_block) - MINSIZE;
1674 sp = ckrealloc(sp, grosslen);
1675 sp->prev = prevstackp;
Denis Vlasenko01631112007-12-16 17:20:38 +00001676 g_stackp = sp;
1677 g_stacknxt = sp->space;
1678 g_stacknleft = newlen;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001679 sstrend = sp->space + newlen;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001680 INT_ON;
1681 } else {
Denis Vlasenko01631112007-12-16 17:20:38 +00001682 char *oldspace = g_stacknxt;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001683 size_t oldlen = g_stacknleft;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001684 char *p = stalloc(newlen);
1685
1686 /* free the space we just allocated */
Denis Vlasenko01631112007-12-16 17:20:38 +00001687 g_stacknxt = memcpy(p, oldspace, oldlen);
1688 g_stacknleft += newlen;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001689 }
1690}
1691
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001692/*
1693 * The following routines are somewhat easier to use than the above.
1694 * The user declares a variable of type STACKSTR, which may be declared
1695 * to be a register. The macro STARTSTACKSTR initializes things. Then
1696 * the user uses the macro STPUTC to add characters to the string. In
1697 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
1698 * grown as necessary. When the user is done, she can just leave the
1699 * string there and refer to it using stackblock(). Or she can allocate
1700 * the space for it using grabstackstr(). If it is necessary to allow
1701 * someone else to use the stack temporarily and then continue to grow
1702 * the string, the user should use grabstack to allocate the space, and
1703 * then call ungrabstr(p) to return to the previous mode of operation.
1704 *
1705 * USTPUTC is like STPUTC except that it doesn't check for overflow.
1706 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
1707 * is space for at least one character.
1708 */
1709static void *
1710growstackstr(void)
1711{
1712 size_t len = stackblocksize();
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001713 growstackblock();
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001714 return (char *)stackblock() + len;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001715}
1716
1717/*
1718 * Called from CHECKSTRSPACE.
1719 */
1720static char *
1721makestrspace(size_t newlen, char *p)
1722{
Denis Vlasenko01631112007-12-16 17:20:38 +00001723 size_t len = p - g_stacknxt;
Denys Vlasenko53d6e032016-09-30 11:24:12 +02001724 size_t size;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001725
1726 for (;;) {
1727 size_t nleft;
1728
1729 size = stackblocksize();
1730 nleft = size - len;
1731 if (nleft >= newlen)
1732 break;
1733 growstackblock();
1734 }
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001735 return (char *)stackblock() + len;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001736}
1737
1738static char *
1739stack_nputstr(const char *s, size_t n, char *p)
1740{
1741 p = makestrspace(n, p);
Denys Vlasenko5ace96a2017-07-23 21:46:02 +02001742 p = (char *)mempcpy(p, s, n);
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001743 return p;
1744}
1745
1746static char *
1747stack_putstr(const char *s, char *p)
1748{
1749 return stack_nputstr(s, strlen(s), p);
1750}
1751
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001752static char *
1753_STPUTC(int c, char *p)
1754{
1755 if (p == sstrend)
1756 p = growstackstr();
1757 *p++ = c;
1758 return p;
1759}
1760
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00001761#define STARTSTACKSTR(p) ((p) = stackblock())
1762#define STPUTC(c, p) ((p) = _STPUTC((c), (p)))
Denis Vlasenko843cbd52008-06-27 00:23:18 +00001763#define CHECKSTRSPACE(n, p) do { \
1764 char *q = (p); \
1765 size_t l = (n); \
1766 size_t m = sstrend - q; \
1767 if (l > m) \
1768 (p) = makestrspace(l, q); \
1769} while (0)
Denis Vlasenkoef527f52008-06-23 01:52:30 +00001770#define USTPUTC(c, p) (*(p)++ = (c))
Denis Vlasenko843cbd52008-06-27 00:23:18 +00001771#define STACKSTRNUL(p) do { \
1772 if ((p) == sstrend) \
1773 (p) = growstackstr(); \
1774 *(p) = '\0'; \
1775} while (0)
Denis Vlasenkoef527f52008-06-23 01:52:30 +00001776#define STUNPUTC(p) (--(p))
1777#define STTOPC(p) ((p)[-1])
1778#define STADJUST(amount, p) ((p) += (amount))
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001779
1780#define grabstackstr(p) stalloc((char *)(p) - (char *)stackblock())
Denis Vlasenkoef527f52008-06-23 01:52:30 +00001781#define ungrabstackstr(s, p) stunalloc(s)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001782#define stackstrend() ((void *)sstrend)
1783
1784
1785/* ============ String helpers */
1786
1787/*
1788 * prefix -- see if pfx is a prefix of string.
1789 */
1790static char *
1791prefix(const char *string, const char *pfx)
1792{
1793 while (*pfx) {
1794 if (*pfx++ != *string++)
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00001795 return NULL;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001796 }
1797 return (char *) string;
1798}
1799
1800/*
1801 * Check for a valid number. This should be elsewhere.
1802 */
1803static int
1804is_number(const char *p)
1805{
1806 do {
1807 if (!isdigit(*p))
1808 return 0;
1809 } while (*++p != '\0');
1810 return 1;
1811}
1812
1813/*
1814 * Convert a string of digits to an integer, printing an error message on
1815 * failure.
1816 */
1817static int
1818number(const char *s)
1819{
1820 if (!is_number(s))
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02001821 ash_msg_and_raise_error(msg_illnum, s);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001822 return atoi(s);
1823}
1824
1825/*
Denys Vlasenko42ba7572017-07-21 13:20:14 +02001826 * Produce a single quoted string suitable as input to the shell.
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001827 * The return string is allocated on the stack.
1828 */
1829static char *
1830single_quote(const char *s)
1831{
1832 char *p;
1833
1834 STARTSTACKSTR(p);
1835
1836 do {
1837 char *q;
1838 size_t len;
1839
1840 len = strchrnul(s, '\'') - s;
1841
1842 q = p = makestrspace(len + 3, p);
1843
1844 *q++ = '\'';
Denys Vlasenko94af83e2017-07-23 21:55:40 +02001845 q = (char *)mempcpy(q, s, len);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001846 *q++ = '\'';
1847 s += len;
1848
1849 STADJUST(q - p, p);
1850
Denys Vlasenkocd716832009-11-28 22:14:02 +01001851 if (*s != '\'')
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001852 break;
Denys Vlasenkocd716832009-11-28 22:14:02 +01001853 len = 0;
1854 do len++; while (*++s == '\'');
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001855
1856 q = p = makestrspace(len + 3, p);
1857
1858 *q++ = '"';
Denys Vlasenko5ace96a2017-07-23 21:46:02 +02001859 q = (char *)mempcpy(q, s - len, len);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001860 *q++ = '"';
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001861
1862 STADJUST(q - p, p);
1863 } while (*s);
1864
Denys Vlasenkocd716832009-11-28 22:14:02 +01001865 USTPUTC('\0', p);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001866
1867 return stackblock();
1868}
1869
Denys Vlasenko42ba7572017-07-21 13:20:14 +02001870/*
1871 * Produce a possibly single quoted string suitable as input to the shell.
Denys Vlasenko42ba7572017-07-21 13:20:14 +02001872 * If quoting was done, the return string is allocated on the stack,
1873 * otherwise a pointer to the original string is returned.
1874 */
1875static const char *
1876maybe_single_quote(const char *s)
1877{
1878 const char *p = s;
1879
1880 while (*p) {
1881 /* Assuming ACSII */
1882 /* quote ctrl_chars space !"#$%&'()* */
1883 if (*p < '+')
1884 goto need_quoting;
1885 /* quote ;<=>? */
1886 if (*p >= ';' && *p <= '?')
1887 goto need_quoting;
1888 /* quote `[\ */
1889 if (*p == '`')
1890 goto need_quoting;
1891 if (*p == '[')
1892 goto need_quoting;
1893 if (*p == '\\')
1894 goto need_quoting;
1895 /* quote {|}~ DEL and high bytes */
1896 if (*p > 'z')
1897 goto need_quoting;
1898 /* Not quoting these: +,-./ 0-9 :@ A-Z ]^_ a-z */
1899 /* TODO: maybe avoid quoting % */
1900 p++;
1901 }
1902 return s;
1903
1904 need_quoting:
1905 return single_quote(s);
1906}
1907
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001908
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00001909/* ============ nextopt */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001910
1911static char **argptr; /* argument list for builtin commands */
1912static char *optionarg; /* set by nextopt (like getopt) */
1913static char *optptr; /* used by nextopt */
1914
1915/*
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001916 * XXX - should get rid of. Have all builtins use getopt(3).
1917 * The library getopt must have the BSD extension static variable
1918 * "optreset", otherwise it can't be used within the shell safely.
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001919 *
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001920 * Standard option processing (a la getopt) for builtin routines.
1921 * The only argument that is passed to nextopt is the option string;
1922 * the other arguments are unnecessary. It returns the character,
1923 * or '\0' on end of input.
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001924 */
1925static int
1926nextopt(const char *optstring)
1927{
1928 char *p;
1929 const char *q;
1930 char c;
1931
1932 p = optptr;
1933 if (p == NULL || *p == '\0') {
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001934 /* We ate entire "-param", take next one */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001935 p = *argptr;
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001936 if (p == NULL)
1937 return '\0';
1938 if (*p != '-')
1939 return '\0';
1940 if (*++p == '\0') /* just "-" ? */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001941 return '\0';
1942 argptr++;
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001943 if (LONE_DASH(p)) /* "--" ? */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001944 return '\0';
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001945 /* p => next "-param" */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001946 }
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001947 /* p => some option char in the middle of a "-param" */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001948 c = *p++;
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +00001949 for (q = optstring; *q != c;) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001950 if (*q == '\0')
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00001951 ash_msg_and_raise_error("illegal option -%c", c);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001952 if (*++q == ':')
1953 q++;
1954 }
1955 if (*++q == ':') {
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001956 if (*p == '\0') {
1957 p = *argptr++;
1958 if (p == NULL)
1959 ash_msg_and_raise_error("no arg for -%c option", c);
1960 }
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001961 optionarg = p;
1962 p = NULL;
1963 }
1964 optptr = p;
1965 return c;
1966}
1967
1968
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00001969/* ============ Shell variables */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001970
Denis Vlasenko01631112007-12-16 17:20:38 +00001971struct shparam {
1972 int nparam; /* # of positional parameters (without $0) */
1973#if ENABLE_ASH_GETOPTS
1974 int optind; /* next parameter to be processed by getopts */
1975 int optoff; /* used by getopts */
1976#endif
1977 unsigned char malloced; /* if parameter list dynamically allocated */
1978 char **p; /* parameter list */
1979};
1980
1981/*
1982 * Free the list of positional parameters.
1983 */
1984static void
1985freeparam(volatile struct shparam *param)
1986{
Denis Vlasenko01631112007-12-16 17:20:38 +00001987 if (param->malloced) {
Denis Vlasenko3177ba02008-07-13 20:39:23 +00001988 char **ap, **ap1;
1989 ap = ap1 = param->p;
1990 while (*ap)
1991 free(*ap++);
1992 free(ap1);
Denis Vlasenko01631112007-12-16 17:20:38 +00001993 }
1994}
1995
1996#if ENABLE_ASH_GETOPTS
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02001997static void FAST_FUNC getoptsreset(const char *value);
Denis Vlasenko01631112007-12-16 17:20:38 +00001998#endif
1999
2000struct var {
2001 struct var *next; /* next entry in hash list */
2002 int flags; /* flags are defined above */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002003 const char *var_text; /* name=value */
2004 void (*var_func)(const char *) FAST_FUNC; /* function to be called when */
Denis Vlasenko01631112007-12-16 17:20:38 +00002005 /* the variable gets set/unset */
2006};
2007
2008struct localvar {
2009 struct localvar *next; /* next local variable in list */
2010 struct var *vp; /* the variable that was made local */
2011 int flags; /* saved flags */
2012 const char *text; /* saved text */
2013};
2014
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002015/* flags */
2016#define VEXPORT 0x01 /* variable is exported */
2017#define VREADONLY 0x02 /* variable cannot be modified */
2018#define VSTRFIXED 0x04 /* variable struct is statically allocated */
2019#define VTEXTFIXED 0x08 /* text is statically allocated */
2020#define VSTACK 0x10 /* text is allocated on the stack */
2021#define VUNSET 0x20 /* the variable is not set */
2022#define VNOFUNC 0x40 /* don't call the callback function */
2023#define VNOSET 0x80 /* do not set variable - just readonly test */
2024#define VNOSAVE 0x100 /* when text is on the heap before setvareq */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00002025#if ENABLE_ASH_RANDOM_SUPPORT
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00002026# define VDYNAMIC 0x200 /* dynamic variable */
2027#else
2028# define VDYNAMIC 0
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002029#endif
2030
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00002031
Denis Vlasenko01631112007-12-16 17:20:38 +00002032/* Need to be before varinit_data[] */
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00002033#if ENABLE_LOCALE_SUPPORT
Denys Vlasenko2634bf32009-06-09 18:40:07 +02002034static void FAST_FUNC
Denis Vlasenkoa8915072007-02-23 21:10:06 +00002035change_lc_all(const char *value)
2036{
2037 if (value && *value != '\0')
2038 setlocale(LC_ALL, value);
2039}
Denys Vlasenko2634bf32009-06-09 18:40:07 +02002040static void FAST_FUNC
Denis Vlasenkoa8915072007-02-23 21:10:06 +00002041change_lc_ctype(const char *value)
2042{
2043 if (value && *value != '\0')
2044 setlocale(LC_CTYPE, value);
2045}
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00002046#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002047#if ENABLE_ASH_MAIL
2048static void chkmail(void);
Denys Vlasenko8c52f802011-02-04 17:36:21 +01002049static void changemail(const char *var_value) FAST_FUNC;
2050#else
2051# define chkmail() ((void)0)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002052#endif
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02002053static void changepath(const char *) FAST_FUNC;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002054#if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02002055static void change_random(const char *) FAST_FUNC;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002056#endif
Ron Yorston1d371862019-04-15 10:52:05 +01002057#if BASH_EPOCH_VARS
2058static void change_seconds(const char *) FAST_FUNC;
2059static void change_realtime(const char *) FAST_FUNC;
2060#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002061
Denis Vlasenko01631112007-12-16 17:20:38 +00002062static const struct {
2063 int flags;
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002064 const char *var_text;
2065 void (*var_func)(const char *) FAST_FUNC;
Denis Vlasenko01631112007-12-16 17:20:38 +00002066} varinit_data[] = {
Denys Vlasenko566a3132012-07-07 21:40:35 +02002067 /*
2068 * Note: VEXPORT would not work correctly here for NOFORK applets:
2069 * some environment strings may be constant.
2070 */
Denis Vlasenko01631112007-12-16 17:20:38 +00002071 { VSTRFIXED|VTEXTFIXED , defifsvar , NULL },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002072#if ENABLE_ASH_MAIL
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002073 { VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL" , changemail },
2074 { VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH" , changemail },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002075#endif
Denis Vlasenko01631112007-12-16 17:20:38 +00002076 { VSTRFIXED|VTEXTFIXED , bb_PATH_root_path, changepath },
2077 { VSTRFIXED|VTEXTFIXED , "PS1=$ " , NULL },
2078 { VSTRFIXED|VTEXTFIXED , "PS2=> " , NULL },
2079 { VSTRFIXED|VTEXTFIXED , "PS4=+ " , NULL },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002080#if ENABLE_ASH_GETOPTS
Denys Vlasenkoe627ac92016-09-30 14:36:59 +02002081 { VSTRFIXED|VTEXTFIXED , defoptindvar, getoptsreset },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002082#endif
Denys Vlasenko675d24a2018-01-27 22:02:05 +01002083 { VSTRFIXED|VTEXTFIXED , NULL /* inited to linenovar */, NULL },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002084#if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002085 { VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM", change_random },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002086#endif
Ron Yorston1d371862019-04-15 10:52:05 +01002087#if BASH_EPOCH_VARS
2088 { VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "EPOCHSECONDS", change_seconds },
2089 { VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "EPOCHREALTIME", change_realtime },
2090#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002091#if ENABLE_LOCALE_SUPPORT
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002092 { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_ALL" , change_lc_all },
2093 { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_CTYPE" , change_lc_ctype },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002094#endif
2095#if ENABLE_FEATURE_EDITING_SAVEHISTORY
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002096 { VSTRFIXED|VTEXTFIXED|VUNSET, "HISTFILE" , NULL },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002097#endif
2098};
2099
Denis Vlasenko0b769642008-07-24 07:54:57 +00002100struct redirtab;
Denis Vlasenko01631112007-12-16 17:20:38 +00002101
2102struct globals_var {
2103 struct shparam shellparam; /* $@ current positional parameters */
2104 struct redirtab *redirlist;
Denys Vlasenkod07a15b2017-07-30 16:51:05 +02002105 int preverrout_fd; /* stderr fd: usually 2, unless redirect moved it */
Denis Vlasenko01631112007-12-16 17:20:38 +00002106 struct var *vartab[VTABSIZE];
2107 struct var varinit[ARRAY_SIZE(varinit_data)];
Denys Vlasenko675d24a2018-01-27 22:02:05 +01002108 int lineno;
2109 char linenovar[sizeof("LINENO=") + sizeof(int)*3];
Denis Vlasenko01631112007-12-16 17:20:38 +00002110};
Denys Vlasenko6f9442f2018-01-28 20:41:23 +01002111extern struct globals_var *BB_GLOBAL_CONST ash_ptr_to_globals_var;
Denis Vlasenko574f2f42008-02-27 18:41:59 +00002112#define G_var (*ash_ptr_to_globals_var)
Denis Vlasenko01631112007-12-16 17:20:38 +00002113#define shellparam (G_var.shellparam )
Denis Vlasenko0b769642008-07-24 07:54:57 +00002114//#define redirlist (G_var.redirlist )
Denis Vlasenko01631112007-12-16 17:20:38 +00002115#define preverrout_fd (G_var.preverrout_fd)
2116#define vartab (G_var.vartab )
2117#define varinit (G_var.varinit )
Denys Vlasenko675d24a2018-01-27 22:02:05 +01002118#define lineno (G_var.lineno )
2119#define linenovar (G_var.linenovar )
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002120#define vifs varinit[0]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002121#if ENABLE_ASH_MAIL
Ron Yorston1d371862019-04-15 10:52:05 +01002122# define vmail varinit[1]
2123# define vmpath varinit[2]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002124#endif
Ron Yorston1d371862019-04-15 10:52:05 +01002125#define VAR_OFFSET1 (ENABLE_ASH_MAIL*2)
2126#define vpath varinit[VAR_OFFSET1 + 1]
2127#define vps1 varinit[VAR_OFFSET1 + 2]
2128#define vps2 varinit[VAR_OFFSET1 + 3]
2129#define vps4 varinit[VAR_OFFSET1 + 4]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002130#if ENABLE_ASH_GETOPTS
Ron Yorston1d371862019-04-15 10:52:05 +01002131# define voptind varinit[VAR_OFFSET1 + 5]
2132#endif
2133#define VAR_OFFSET2 (VAR_OFFSET1 + ENABLE_ASH_GETOPTS)
2134#define vlineno varinit[VAR_OFFSET2 + 5]
2135#if ENABLE_ASH_RANDOM_SUPPORT
2136# define vrandom varinit[VAR_OFFSET2 + 6]
2137#endif
2138#define VAR_OFFSET3 (VAR_OFFSET2 + ENABLE_ASH_RANDOM_SUPPORT)
2139#if BASH_EPOCH_VARS
2140# define vepochs varinit[VAR_OFFSET3 + 6]
2141# define vepochr varinit[VAR_OFFSET3 + 7]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002142#endif
Denys Vlasenko675d24a2018-01-27 22:02:05 +01002143#define INIT_G_var() do { \
2144 unsigned i; \
2145 (*(struct globals_var**)&ash_ptr_to_globals_var) = xzalloc(sizeof(G_var)); \
2146 barrier(); \
2147 for (i = 0; i < ARRAY_SIZE(varinit_data); i++) { \
2148 varinit[i].flags = varinit_data[i].flags; \
2149 varinit[i].var_text = varinit_data[i].var_text; \
2150 varinit[i].var_func = varinit_data[i].var_func; \
2151 } \
2152 strcpy(linenovar, "LINENO="); \
2153 vlineno.var_text = linenovar; \
2154} while (0)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002155
2156/*
2157 * The following macros access the values of the above variables.
2158 * They have to skip over the name. They return the null string
2159 * for unset variables.
2160 */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002161#define ifsval() (vifs.var_text + 4)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002162#define ifsset() ((vifs.flags & VUNSET) == 0)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002163#if ENABLE_ASH_MAIL
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002164# define mailval() (vmail.var_text + 5)
2165# define mpathval() (vmpath.var_text + 9)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002166# define mpathset() ((vmpath.flags & VUNSET) == 0)
2167#endif
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002168#define pathval() (vpath.var_text + 5)
2169#define ps1val() (vps1.var_text + 4)
2170#define ps2val() (vps2.var_text + 4)
2171#define ps4val() (vps4.var_text + 4)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002172#if ENABLE_ASH_GETOPTS
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002173# define optindval() (voptind.var_text + 7)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002174#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002175
Denis Vlasenko01631112007-12-16 17:20:38 +00002176#if ENABLE_ASH_GETOPTS
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02002177static void FAST_FUNC
Denis Vlasenko01631112007-12-16 17:20:38 +00002178getoptsreset(const char *value)
2179{
Denys Vlasenko46289452017-08-11 00:59:36 +02002180 shellparam.optind = 1;
2181 if (is_number(value))
2182 shellparam.optind = number(value) ?: 1;
Denis Vlasenko01631112007-12-16 17:20:38 +00002183 shellparam.optoff = -1;
2184}
2185#endif
2186
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002187/*
2188 * Compares two strings up to the first = or '\0'. The first
2189 * string must be terminated by '='; the second may be terminated by
2190 * either '=' or '\0'.
2191 */
2192static int
2193varcmp(const char *p, const char *q)
2194{
2195 int c, d;
2196
2197 while ((c = *p) == (d = *q)) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02002198 if (c == '\0' || c == '=')
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002199 goto out;
2200 p++;
2201 q++;
2202 }
2203 if (c == '=')
Denis Vlasenko9650f362007-02-23 01:04:37 +00002204 c = '\0';
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002205 if (d == '=')
Denis Vlasenko9650f362007-02-23 01:04:37 +00002206 d = '\0';
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002207 out:
2208 return c - d;
2209}
2210
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002211/*
2212 * Find the appropriate entry in the hash table from the name.
2213 */
2214static struct var **
2215hashvar(const char *p)
2216{
2217 unsigned hashval;
2218
2219 hashval = ((unsigned char) *p) << 4;
2220 while (*p && *p != '=')
2221 hashval += (unsigned char) *p++;
2222 return &vartab[hashval % VTABSIZE];
2223}
2224
2225static int
2226vpcmp(const void *a, const void *b)
2227{
2228 return varcmp(*(const char **)a, *(const char **)b);
2229}
2230
2231/*
2232 * This routine initializes the builtin variables.
2233 */
2234static void
2235initvar(void)
2236{
2237 struct var *vp;
2238 struct var *end;
2239 struct var **vpp;
2240
2241 /*
2242 * PS1 depends on uid
2243 */
2244#if ENABLE_FEATURE_EDITING && ENABLE_FEATURE_EDITING_FANCY_PROMPT
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002245 vps1.var_text = "PS1=\\w \\$ ";
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002246#else
2247 if (!geteuid())
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002248 vps1.var_text = "PS1=# ";
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002249#endif
2250 vp = varinit;
Denis Vlasenko80b8b392007-06-25 10:55:35 +00002251 end = vp + ARRAY_SIZE(varinit);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002252 do {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002253 vpp = hashvar(vp->var_text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002254 vp->next = *vpp;
2255 *vpp = vp;
2256 } while (++vp < end);
2257}
2258
2259static struct var **
2260findvar(struct var **vpp, const char *name)
2261{
2262 for (; *vpp; vpp = &(*vpp)->next) {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002263 if (varcmp((*vpp)->var_text, name) == 0) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002264 break;
2265 }
2266 }
2267 return vpp;
2268}
2269
2270/*
2271 * Find the value of a variable. Returns NULL if not set.
2272 */
Denys Vlasenko03dad222010-01-12 23:29:57 +01002273static const char* FAST_FUNC
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002274lookupvar(const char *name)
2275{
2276 struct var *v;
2277
2278 v = *findvar(hashvar(name), name);
2279 if (v) {
Ron Yorston1d371862019-04-15 10:52:05 +01002280#if ENABLE_ASH_RANDOM_SUPPORT || BASH_EPOCH_VARS
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002281 /*
2282 * Dynamic variables are implemented roughly the same way they are
2283 * in bash. Namely, they're "special" so long as they aren't unset.
2284 * As soon as they're unset, they're no longer dynamic, and dynamic
2285 * lookup will no longer happen at that point. -- PFM.
2286 */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002287 if (v->flags & VDYNAMIC)
2288 v->var_func(NULL);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002289#endif
Denys Vlasenko675d24a2018-01-27 22:02:05 +01002290 if (!(v->flags & VUNSET)) {
2291 if (v == &vlineno && v->var_text == linenovar) {
2292 fmtstr(linenovar+7, sizeof(linenovar)-7, "%d", lineno);
2293 }
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002294 return var_end(v->var_text);
Denys Vlasenko675d24a2018-01-27 22:02:05 +01002295 }
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002296 }
2297 return NULL;
2298}
2299
Denys Vlasenko0b883582016-12-23 16:49:07 +01002300#if ENABLE_UNICODE_SUPPORT
Denys Vlasenko37dc08b2016-10-02 04:38:07 +02002301static void
2302reinit_unicode_for_ash(void)
Denys Vlasenkoe9ab07c2014-08-13 18:00:08 +02002303{
2304 /* Unicode support should be activated even if LANG is set
2305 * _during_ shell execution, not only if it was set when
2306 * shell was started. Therefore, re-check LANG every time:
2307 */
2308 if (ENABLE_FEATURE_CHECK_UNICODE_IN_ENV
2309 || ENABLE_UNICODE_USING_LOCALE
2310 ) {
2311 const char *s = lookupvar("LC_ALL");
2312 if (!s) s = lookupvar("LC_CTYPE");
2313 if (!s) s = lookupvar("LANG");
2314 reinit_unicode(s);
2315 }
2316}
Denys Vlasenko0b883582016-12-23 16:49:07 +01002317#else
2318# define reinit_unicode_for_ash() ((void)0)
2319#endif
Denys Vlasenkoe9ab07c2014-08-13 18:00:08 +02002320
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002321/*
2322 * Search the environment of a builtin command.
2323 */
Denys Vlasenko488e6092017-07-26 23:08:36 +02002324static ALWAYS_INLINE const char *
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002325bltinlookup(const char *name)
2326{
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002327 return lookupvar(name);
2328}
2329
2330/*
2331 * Same as setvar except that the variable and value are passed in
2332 * the first argument as name=value. Since the first argument will
2333 * be actually stored in the table, it should not be a string that
2334 * will go away.
2335 * Called with interrupts off.
2336 */
Denys Vlasenkod04fc712017-07-26 20:06:48 +02002337static struct var *
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002338setvareq(char *s, int flags)
2339{
2340 struct var *vp, **vpp;
2341
2342 vpp = hashvar(s);
2343 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
Denys Vlasenkod04fc712017-07-26 20:06:48 +02002344 vpp = findvar(vpp, s);
2345 vp = *vpp;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002346 if (vp) {
2347 if ((vp->flags & (VREADONLY|VDYNAMIC)) == VREADONLY) {
2348 const char *n;
2349
2350 if (flags & VNOSAVE)
2351 free(s);
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002352 n = vp->var_text;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +02002353 exitstatus = 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002354 ash_msg_and_raise_error("%.*s: is read only", strchrnul(n, '=') - n, n);
2355 }
2356
2357 if (flags & VNOSET)
Denys Vlasenkod04fc712017-07-26 20:06:48 +02002358 goto out;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002359
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002360 if (vp->var_func && !(flags & VNOFUNC))
2361 vp->var_func(var_end(s));
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002362
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002363 if (!(vp->flags & (VTEXTFIXED|VSTACK)))
2364 free((char*)vp->var_text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002365
Denys Vlasenkob28d4c32017-07-25 16:29:36 +02002366 if (((flags & (VEXPORT|VREADONLY|VSTRFIXED|VUNSET)) | (vp->flags & VSTRFIXED)) == VUNSET) {
2367 *vpp = vp->next;
2368 free(vp);
2369 out_free:
2370 if ((flags & (VTEXTFIXED|VSTACK|VNOSAVE)) == VNOSAVE)
2371 free(s);
Denys Vlasenkod04fc712017-07-26 20:06:48 +02002372 goto out;
Denys Vlasenkob28d4c32017-07-25 16:29:36 +02002373 }
2374
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002375 flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
Ron Yorston1d371862019-04-15 10:52:05 +01002376#if ENABLE_ASH_RANDOM_SUPPORT || BASH_EPOCH_VARS
Ron Yorstond96c69d2019-04-15 10:49:35 +01002377 if (flags & VUNSET)
2378 flags &= ~VDYNAMIC;
2379#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002380 } else {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002381 /* variable s is not found */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002382 if (flags & VNOSET)
Denys Vlasenkod04fc712017-07-26 20:06:48 +02002383 goto out;
Denys Vlasenkob28d4c32017-07-25 16:29:36 +02002384 if ((flags & (VEXPORT|VREADONLY|VSTRFIXED|VUNSET)) == VUNSET)
2385 goto out_free;
Denis Vlasenko597906c2008-02-20 16:38:54 +00002386 vp = ckzalloc(sizeof(*vp));
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002387 vp->next = *vpp;
Denis Vlasenko597906c2008-02-20 16:38:54 +00002388 /*vp->func = NULL; - ckzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002389 *vpp = vp;
2390 }
2391 if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE)))
2392 s = ckstrdup(s);
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002393 vp->var_text = s;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002394 vp->flags = flags;
Denys Vlasenkod04fc712017-07-26 20:06:48 +02002395
2396 out:
2397 return vp;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002398}
2399
2400/*
2401 * Set the value of a variable. The flags argument is ored with the
2402 * flags of the variable. If val is NULL, the variable is unset.
2403 */
Denys Vlasenkod04fc712017-07-26 20:06:48 +02002404static struct var *
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002405setvar(const char *name, const char *val, int flags)
2406{
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002407 const char *q;
2408 char *p;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002409 char *nameeq;
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002410 size_t namelen;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002411 size_t vallen;
Denys Vlasenkod04fc712017-07-26 20:06:48 +02002412 struct var *vp;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002413
2414 q = endofname(name);
2415 p = strchrnul(q, '=');
2416 namelen = p - name;
2417 if (!namelen || p != q)
2418 ash_msg_and_raise_error("%.*s: bad variable name", namelen, name);
2419 vallen = 0;
2420 if (val == NULL) {
2421 flags |= VUNSET;
2422 } else {
2423 vallen = strlen(val);
2424 }
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002425
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002426 INT_OFF;
Ron Yorstone6a63bf2018-11-12 21:10:54 +00002427 nameeq = ckzalloc(namelen + vallen + 2);
Denys Vlasenkoda2244f2017-07-21 18:51:29 +02002428 p = mempcpy(nameeq, name, namelen);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002429 if (val) {
2430 *p++ = '=';
Ron Yorstone6a63bf2018-11-12 21:10:54 +00002431 memcpy(p, val, vallen);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002432 }
Denys Vlasenkod04fc712017-07-26 20:06:48 +02002433 vp = setvareq(nameeq, flags | VNOSAVE);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002434 INT_ON;
Denys Vlasenkod04fc712017-07-26 20:06:48 +02002435
2436 return vp;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002437}
2438
Denys Vlasenko03dad222010-01-12 23:29:57 +01002439static void FAST_FUNC
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02002440setvar0(const char *name, const char *val)
Denys Vlasenko03dad222010-01-12 23:29:57 +01002441{
2442 setvar(name, val, 0);
2443}
2444
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002445/*
2446 * Unset the specified variable.
2447 */
Denys Vlasenkob28d4c32017-07-25 16:29:36 +02002448static void
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002449unsetvar(const char *s)
2450{
Denys Vlasenkocf3a7962017-07-26 14:38:19 +02002451 setvar(s, NULL, 0);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002452}
2453
2454/*
2455 * Process a linked list of variable assignments.
2456 */
2457static void
2458listsetvar(struct strlist *list_set_var, int flags)
2459{
2460 struct strlist *lp = list_set_var;
2461
2462 if (!lp)
2463 return;
2464 INT_OFF;
2465 do {
2466 setvareq(lp->text, flags);
Denis Vlasenko9650f362007-02-23 01:04:37 +00002467 lp = lp->next;
2468 } while (lp);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002469 INT_ON;
2470}
2471
2472/*
2473 * Generate a list of variables satisfying the given conditions.
2474 */
Denys Vlasenkoa5060b82017-11-03 14:16:25 +01002475#if !ENABLE_FEATURE_SH_NOFORK
2476# define listvars(on, off, lp, end) listvars(on, off, end)
2477#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002478static char **
Denys Vlasenkoa5060b82017-11-03 14:16:25 +01002479listvars(int on, int off, struct strlist *lp, char ***end)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002480{
2481 struct var **vpp;
2482 struct var *vp;
2483 char **ep;
2484 int mask;
2485
2486 STARTSTACKSTR(ep);
2487 vpp = vartab;
2488 mask = on | off;
2489 do {
2490 for (vp = *vpp; vp; vp = vp->next) {
2491 if ((vp->flags & mask) == on) {
Denys Vlasenkoa5060b82017-11-03 14:16:25 +01002492#if ENABLE_FEATURE_SH_NOFORK
2493 /* If variable with the same name is both
2494 * exported and temporarily set for a command:
2495 * export ZVAR=5
2496 * ZVAR=6 printenv
2497 * then "ZVAR=6" will be both in vartab and
2498 * lp lists. Do not pass it twice to printenv.
2499 */
2500 struct strlist *lp1 = lp;
2501 while (lp1) {
2502 if (strcmp(lp1->text, vp->var_text) == 0)
2503 goto skip;
2504 lp1 = lp1->next;
2505 }
2506#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002507 if (ep == stackstrend())
2508 ep = growstackstr();
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002509 *ep++ = (char*)vp->var_text;
Denys Vlasenkoa5060b82017-11-03 14:16:25 +01002510#if ENABLE_FEATURE_SH_NOFORK
2511 skip: ;
2512#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002513 }
2514 }
2515 } while (++vpp < vartab + VTABSIZE);
Denys Vlasenkoa5060b82017-11-03 14:16:25 +01002516
2517#if ENABLE_FEATURE_SH_NOFORK
2518 while (lp) {
2519 if (ep == stackstrend())
2520 ep = growstackstr();
2521 *ep++ = lp->text;
2522 lp = lp->next;
2523 }
2524#endif
2525
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002526 if (ep == stackstrend())
2527 ep = growstackstr();
2528 if (end)
2529 *end = ep;
2530 *ep++ = NULL;
2531 return grabstackstr(ep);
2532}
2533
2534
2535/* ============ Path search helper
2536 *
2537 * The variable path (passed by reference) should be set to the start
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002538 * of the path before the first call; path_advance will update
2539 * this value as it proceeds. Successive calls to path_advance will return
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002540 * the possible path expansions in sequence. If an option (indicated by
2541 * a percent sign) appears in the path entry then the global variable
2542 * pathopt will be set to point to it; otherwise pathopt will be set to
2543 * NULL.
2544 */
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002545static const char *pathopt; /* set by path_advance */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002546
2547static char *
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002548path_advance(const char **path, const char *name)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002549{
2550 const char *p;
2551 char *q;
2552 const char *start;
2553 size_t len;
2554
2555 if (*path == NULL)
2556 return NULL;
2557 start = *path;
Denis Vlasenkof7d56652008-03-25 05:51:41 +00002558 for (p = start; *p && *p != ':' && *p != '%'; p++)
2559 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002560 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
2561 while (stackblocksize() < len)
2562 growstackblock();
2563 q = stackblock();
2564 if (p != start) {
Denys Vlasenko5ace96a2017-07-23 21:46:02 +02002565 q = mempcpy(q, start, p - start);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002566 *q++ = '/';
2567 }
2568 strcpy(q, name);
2569 pathopt = NULL;
2570 if (*p == '%') {
2571 pathopt = ++p;
Denis Vlasenkof7d56652008-03-25 05:51:41 +00002572 while (*p && *p != ':')
2573 p++;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002574 }
2575 if (*p == ':')
2576 *path = p + 1;
2577 else
2578 *path = NULL;
2579 return stalloc(len);
2580}
2581
2582
2583/* ============ Prompt */
2584
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +00002585static smallint doprompt; /* if set, prompt the user */
2586static smallint needprompt; /* true if interactive and at start of line */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002587
2588#if ENABLE_FEATURE_EDITING
2589static line_input_t *line_input_state;
2590static const char *cmdedit_prompt;
2591static void
2592putprompt(const char *s)
2593{
2594 if (ENABLE_ASH_EXPAND_PRMT) {
2595 free((char*)cmdedit_prompt);
Denis Vlasenko4222ae42007-02-25 02:37:49 +00002596 cmdedit_prompt = ckstrdup(s);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002597 return;
2598 }
2599 cmdedit_prompt = s;
2600}
2601#else
2602static void
2603putprompt(const char *s)
2604{
2605 out2str(s);
2606}
2607#endif
2608
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002609/* expandstr() needs parsing machinery, so it is far away ahead... */
Denys Vlasenko46999802017-07-29 21:12:29 +02002610static const char *expandstr(const char *ps, int syntax_type);
2611/* Values for syntax param */
2612#define BASESYNTAX 0 /* not in quotes */
2613#define DQSYNTAX 1 /* in double quotes */
2614#define SQSYNTAX 2 /* in single quotes */
2615#define ARISYNTAX 3 /* in arithmetic */
Denys Vlasenko5f0a75f2017-07-29 22:58:44 +02002616#if ENABLE_ASH_EXPAND_PRMT
2617# define PSSYNTAX 4 /* prompt. never passed to SIT() */
2618#endif
Denys Vlasenko46999802017-07-29 21:12:29 +02002619/* PSSYNTAX expansion is identical to DQSYNTAX, except keeping '\$' as '\$' */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002620
Denys Vlasenko46999802017-07-29 21:12:29 +02002621/*
2622 * called by editline -- any expansions to the prompt should be added here.
2623 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002624static void
Denys Vlasenko958581a2010-09-12 15:04:27 +02002625setprompt_if(smallint do_set, int whichprompt)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002626{
2627 const char *prompt;
Denys Vlasenko958581a2010-09-12 15:04:27 +02002628 IF_ASH_EXPAND_PRMT(struct stackmark smark;)
2629
2630 if (!do_set)
2631 return;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002632
2633 needprompt = 0;
2634
2635 switch (whichprompt) {
2636 case 1:
2637 prompt = ps1val();
2638 break;
2639 case 2:
2640 prompt = ps2val();
2641 break;
2642 default: /* 0 */
2643 prompt = nullstr;
2644 }
2645#if ENABLE_ASH_EXPAND_PRMT
Denys Vlasenko60ca8342016-09-30 11:21:21 +02002646 pushstackmark(&smark, stackblocksize());
Denys Vlasenko46999802017-07-29 21:12:29 +02002647 putprompt(expandstr(prompt, PSSYNTAX));
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002648 popstackmark(&smark);
Denys Vlasenko48c803a2017-07-01 23:24:48 +02002649#else
2650 putprompt(prompt);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002651#endif
2652}
2653
2654
2655/* ============ The cd and pwd commands */
2656
2657#define CD_PHYSICAL 1
2658#define CD_PRINT 2
2659
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002660static int
2661cdopt(void)
2662{
2663 int flags = 0;
2664 int i, j;
2665
2666 j = 'L';
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02002667 while ((i = nextopt("LP")) != '\0') {
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002668 if (i != j) {
2669 flags ^= CD_PHYSICAL;
2670 j = i;
2671 }
2672 }
2673
2674 return flags;
2675}
2676
2677/*
2678 * Update curdir (the name of the current directory) in response to a
2679 * cd command.
2680 */
2681static const char *
2682updatepwd(const char *dir)
2683{
2684 char *new;
2685 char *p;
2686 char *cdcomppath;
2687 const char *lim;
2688
Denys Vlasenko8e2bc472016-09-28 23:02:57 +02002689 cdcomppath = sstrdup(dir);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002690 STARTSTACKSTR(new);
2691 if (*dir != '/') {
2692 if (curdir == nullstr)
2693 return 0;
2694 new = stack_putstr(curdir, new);
2695 }
2696 new = makestrspace(strlen(dir) + 2, new);
Denis Vlasenko29eb3592008-05-18 14:06:08 +00002697 lim = (char *)stackblock() + 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002698 if (*dir != '/') {
2699 if (new[-1] != '/')
2700 USTPUTC('/', new);
2701 if (new > lim && *lim == '/')
2702 lim++;
2703 } else {
2704 USTPUTC('/', new);
2705 cdcomppath++;
2706 if (dir[1] == '/' && dir[2] != '/') {
2707 USTPUTC('/', new);
2708 cdcomppath++;
2709 lim++;
2710 }
2711 }
2712 p = strtok(cdcomppath, "/");
2713 while (p) {
2714 switch (*p) {
2715 case '.':
2716 if (p[1] == '.' && p[2] == '\0') {
2717 while (new > lim) {
2718 STUNPUTC(new);
2719 if (new[-1] == '/')
2720 break;
2721 }
2722 break;
Denis Vlasenko16abcd92007-04-13 23:59:52 +00002723 }
2724 if (p[1] == '\0')
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002725 break;
2726 /* fall through */
2727 default:
2728 new = stack_putstr(p, new);
2729 USTPUTC('/', new);
2730 }
Denys Vlasenko00da72b2015-10-23 18:43:16 +02002731 p = strtok(NULL, "/");
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002732 }
2733 if (new > lim)
2734 STUNPUTC(new);
2735 *new = 0;
2736 return stackblock();
2737}
2738
2739/*
2740 * Find out what the current directory is. If we already know the current
2741 * directory, this routine returns immediately.
2742 */
2743static char *
2744getpwd(void)
2745{
Denis Vlasenko01631112007-12-16 17:20:38 +00002746 char *dir = getcwd(NULL, 0); /* huh, using glibc extension? */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002747 return dir ? dir : nullstr;
2748}
2749
2750static void
2751setpwd(const char *val, int setold)
2752{
2753 char *oldcur, *dir;
2754
2755 oldcur = dir = curdir;
2756
2757 if (setold) {
2758 setvar("OLDPWD", oldcur, VEXPORT);
2759 }
2760 INT_OFF;
2761 if (physdir != nullstr) {
2762 if (physdir != oldcur)
2763 free(physdir);
2764 physdir = nullstr;
2765 }
2766 if (oldcur == val || !val) {
2767 char *s = getpwd();
2768 physdir = s;
2769 if (!val)
2770 dir = s;
2771 } else
2772 dir = ckstrdup(val);
2773 if (oldcur != dir && oldcur != nullstr) {
2774 free(oldcur);
2775 }
2776 curdir = dir;
2777 INT_ON;
2778 setvar("PWD", dir, VEXPORT);
2779}
2780
2781static void hashcd(void);
2782
2783/*
Denys Vlasenko70392332016-10-27 02:31:55 +02002784 * Actually do the chdir. We also call hashcd to let other routines
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002785 * know that the current directory has changed.
2786 */
2787static int
2788docd(const char *dest, int flags)
2789{
Denys Vlasenko4b1100e2010-03-05 14:10:54 +01002790 const char *dir = NULL;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002791 int err;
2792
2793 TRACE(("docd(\"%s\", %d) called\n", dest, flags));
2794
2795 INT_OFF;
2796 if (!(flags & CD_PHYSICAL)) {
2797 dir = updatepwd(dest);
2798 if (dir)
2799 dest = dir;
2800 }
2801 err = chdir(dest);
2802 if (err)
2803 goto out;
2804 setpwd(dir, 1);
2805 hashcd();
2806 out:
2807 INT_ON;
2808 return err;
2809}
2810
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02002811static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00002812cdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002813{
2814 const char *dest;
2815 const char *path;
2816 const char *p;
2817 char c;
2818 struct stat statb;
2819 int flags;
2820
2821 flags = cdopt();
2822 dest = *argptr;
2823 if (!dest)
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02002824 dest = bltinlookup("HOME");
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002825 else if (LONE_DASH(dest)) {
2826 dest = bltinlookup("OLDPWD");
2827 flags |= CD_PRINT;
2828 }
2829 if (!dest)
2830 dest = nullstr;
2831 if (*dest == '/')
Denys Vlasenko0e081d02016-10-26 19:56:05 +02002832 goto step6;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002833 if (*dest == '.') {
2834 c = dest[1];
2835 dotdot:
2836 switch (c) {
2837 case '\0':
2838 case '/':
2839 goto step6;
2840 case '.':
2841 c = dest[2];
2842 if (c != '.')
2843 goto dotdot;
2844 }
2845 }
2846 if (!*dest)
2847 dest = ".";
2848 path = bltinlookup("CDPATH");
Denys Vlasenko0e081d02016-10-26 19:56:05 +02002849 while (path) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002850 c = *path;
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002851 p = path_advance(&path, dest);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002852 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
2853 if (c && c != ':')
2854 flags |= CD_PRINT;
2855 docd:
2856 if (!docd(p, flags))
2857 goto out;
Denys Vlasenko0e081d02016-10-26 19:56:05 +02002858 goto err;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002859 }
Denys Vlasenko0e081d02016-10-26 19:56:05 +02002860 }
2861
2862 step6:
2863 p = dest;
2864 goto docd;
2865
2866 err:
Johannes Schindelin687aac02017-08-22 22:03:22 +02002867 ash_msg_and_raise_perror("can't cd to %s", dest);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002868 /* NOTREACHED */
2869 out:
2870 if (flags & CD_PRINT)
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02002871 out1fmt("%s\n", curdir);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002872 return 0;
2873}
2874
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02002875static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00002876pwdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002877{
2878 int flags;
2879 const char *dir = curdir;
2880
2881 flags = cdopt();
2882 if (flags) {
2883 if (physdir == nullstr)
2884 setpwd(dir, 0);
2885 dir = physdir;
2886 }
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02002887 out1fmt("%s\n", dir);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002888 return 0;
2889}
2890
Denis Vlasenko0c032a42007-02-23 01:03:40 +00002891
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00002892/* ============ ... */
Eric Andersenc470f442003-07-28 09:56:35 +00002893
Denis Vlasenko834dee72008-10-07 09:18:30 +00002894
Denys Vlasenko82dd14a2010-05-17 10:10:01 +02002895#define IBUFSIZ (ENABLE_FEATURE_EDITING ? CONFIG_FEATURE_EDITING_MAX_LEN : 1024)
Eric Andersenc470f442003-07-28 09:56:35 +00002896
Eric Andersenc470f442003-07-28 09:56:35 +00002897/* Syntax classes */
Denis Vlasenko834dee72008-10-07 09:18:30 +00002898#define CWORD 0 /* character is nothing special */
2899#define CNL 1 /* newline character */
2900#define CBACK 2 /* a backslash character */
2901#define CSQUOTE 3 /* single quote */
2902#define CDQUOTE 4 /* double quote */
Eric Andersenc470f442003-07-28 09:56:35 +00002903#define CENDQUOTE 5 /* a terminating quote */
Denis Vlasenko834dee72008-10-07 09:18:30 +00002904#define CBQUOTE 6 /* backwards single quote */
2905#define CVAR 7 /* a dollar sign */
2906#define CENDVAR 8 /* a '}' character */
2907#define CLP 9 /* a left paren in arithmetic */
2908#define CRP 10 /* a right paren in arithmetic */
Eric Andersenc470f442003-07-28 09:56:35 +00002909#define CENDFILE 11 /* end of file */
Denis Vlasenko834dee72008-10-07 09:18:30 +00002910#define CCTL 12 /* like CWORD, except it must be escaped */
2911#define CSPCL 13 /* these terminate a word */
2912#define CIGN 14 /* character should be ignored */
Eric Andersenc470f442003-07-28 09:56:35 +00002913
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002914#define PEOF 256
Denis Vlasenko131ae172007-02-18 13:00:19 +00002915#if ENABLE_ASH_ALIAS
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002916# define PEOA 257
Eric Andersenc470f442003-07-28 09:56:35 +00002917#endif
2918
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002919#define USE_SIT_FUNCTION ENABLE_ASH_OPTIMIZE_FOR_SIZE
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002920
Denys Vlasenko0b883582016-12-23 16:49:07 +01002921#if ENABLE_FEATURE_SH_MATH
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002922# define SIT_ITEM(a,b,c,d) (a | (b << 4) | (c << 8) | (d << 12))
Eric Andersenc470f442003-07-28 09:56:35 +00002923#else
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002924# define SIT_ITEM(a,b,c,d) (a | (b << 4) | (c << 8))
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002925#endif
Denys Vlasenko3e134eb2016-04-22 18:09:21 +02002926static const uint16_t S_I_T[] ALIGN2 = {
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002927#if ENABLE_ASH_ALIAS
2928 SIT_ITEM(CSPCL , CIGN , CIGN , CIGN ), /* 0, PEOA */
2929#endif
2930 SIT_ITEM(CSPCL , CWORD , CWORD, CWORD ), /* 1, ' ' */
2931 SIT_ITEM(CNL , CNL , CNL , CNL ), /* 2, \n */
2932 SIT_ITEM(CWORD , CCTL , CCTL , CWORD ), /* 3, !*-/:=?[]~ */
2933 SIT_ITEM(CDQUOTE , CENDQUOTE, CWORD, CWORD ), /* 4, '"' */
2934 SIT_ITEM(CVAR , CVAR , CWORD, CVAR ), /* 5, $ */
2935 SIT_ITEM(CSQUOTE , CWORD , CENDQUOTE, CWORD), /* 6, "'" */
2936 SIT_ITEM(CSPCL , CWORD , CWORD, CLP ), /* 7, ( */
2937 SIT_ITEM(CSPCL , CWORD , CWORD, CRP ), /* 8, ) */
2938 SIT_ITEM(CBACK , CBACK , CCTL , CBACK ), /* 9, \ */
2939 SIT_ITEM(CBQUOTE , CBQUOTE , CWORD, CBQUOTE), /* 10, ` */
2940 SIT_ITEM(CENDVAR , CENDVAR , CWORD, CENDVAR), /* 11, } */
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002941#if !USE_SIT_FUNCTION
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002942 SIT_ITEM(CENDFILE, CENDFILE , CENDFILE, CENDFILE),/* 12, PEOF */
2943 SIT_ITEM(CWORD , CWORD , CWORD, CWORD ), /* 13, 0-9A-Za-z */
2944 SIT_ITEM(CCTL , CCTL , CCTL , CCTL ) /* 14, CTLESC ... */
2945#endif
2946#undef SIT_ITEM
Eric Andersenc470f442003-07-28 09:56:35 +00002947};
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002948/* Constants below must match table above */
2949enum {
2950#if ENABLE_ASH_ALIAS
2951 CSPCL_CIGN_CIGN_CIGN , /* 0 */
2952#endif
2953 CSPCL_CWORD_CWORD_CWORD , /* 1 */
2954 CNL_CNL_CNL_CNL , /* 2 */
2955 CWORD_CCTL_CCTL_CWORD , /* 3 */
2956 CDQUOTE_CENDQUOTE_CWORD_CWORD , /* 4 */
2957 CVAR_CVAR_CWORD_CVAR , /* 5 */
2958 CSQUOTE_CWORD_CENDQUOTE_CWORD , /* 6 */
2959 CSPCL_CWORD_CWORD_CLP , /* 7 */
2960 CSPCL_CWORD_CWORD_CRP , /* 8 */
2961 CBACK_CBACK_CCTL_CBACK , /* 9 */
2962 CBQUOTE_CBQUOTE_CWORD_CBQUOTE , /* 10 */
2963 CENDVAR_CENDVAR_CWORD_CENDVAR , /* 11 */
2964 CENDFILE_CENDFILE_CENDFILE_CENDFILE, /* 12 */
2965 CWORD_CWORD_CWORD_CWORD , /* 13 */
2966 CCTL_CCTL_CCTL_CCTL , /* 14 */
2967};
Eric Andersen2870d962001-07-02 17:27:21 +00002968
Denys Vlasenkocd716832009-11-28 22:14:02 +01002969/* c in SIT(c, syntax) must be an *unsigned char* or PEOA or PEOF,
2970 * caller must ensure proper cast on it if c is *char_ptr!
2971 */
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002972#if USE_SIT_FUNCTION
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002973
Denis Vlasenko0c032a42007-02-23 01:03:40 +00002974static int
2975SIT(int c, int syntax)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002976{
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02002977 /* Used to also have '/' in this string: "\t\n !\"$&'()*-/:;<=>?[\\]`|}~" */
2978 static const char spec_symbls[] ALIGN1 = "\t\n !\"$&'()*-:;<=>?[\\]`|}~";
2979 /*
2980 * This causes '/' to be prepended with CTLESC in dquoted string,
2981 * making "./file"* treated incorrectly because we feed
2982 * ".\/file*" string to glob(), confusing it (see expandmeta func).
2983 * The "homegrown" glob implementation is okay with that,
2984 * but glibc one isn't. With '/' always treated as CWORD,
2985 * both work fine.
2986 */
Denys Vlasenkocd716832009-11-28 22:14:02 +01002987# if ENABLE_ASH_ALIAS
2988 static const uint8_t syntax_index_table[] ALIGN1 = {
Eric Andersenc470f442003-07-28 09:56:35 +00002989 1, 2, 1, 3, 4, 5, 1, 6, /* "\t\n !\"$&'" */
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02002990 7, 8, 3, 3,/*3,*/3, 1, 1, /* "()*-/:;<" */
Eric Andersenc470f442003-07-28 09:56:35 +00002991 3, 1, 3, 3, 9, 3, 10, 1, /* "=>?[\\]`|" */
2992 11, 3 /* "}~" */
2993 };
Denys Vlasenkocd716832009-11-28 22:14:02 +01002994# else
2995 static const uint8_t syntax_index_table[] ALIGN1 = {
Eric Andersenc470f442003-07-28 09:56:35 +00002996 0, 1, 0, 2, 3, 4, 0, 5, /* "\t\n !\"$&'" */
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02002997 6, 7, 2, 2,/*2,*/2, 0, 0, /* "()*-/:;<" */
Eric Andersenc470f442003-07-28 09:56:35 +00002998 2, 0, 2, 2, 8, 2, 9, 0, /* "=>?[\\]`|" */
2999 10, 2 /* "}~" */
3000 };
Denys Vlasenkocd716832009-11-28 22:14:02 +01003001# endif
Manuel Novoa III 16815d42001-08-10 19:36:07 +00003002 const char *s;
3003 int indx;
3004
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01003005 if (c == PEOF)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00003006 return CENDFILE;
Denys Vlasenkocd716832009-11-28 22:14:02 +01003007# if ENABLE_ASH_ALIAS
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01003008 if (c == PEOA)
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00003009 indx = 0;
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01003010 else
Denys Vlasenkocd716832009-11-28 22:14:02 +01003011# endif
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00003012 {
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01003013 /* Cast is purely for paranoia here,
3014 * just in case someone passed signed char to us */
3015 if ((unsigned char)c >= CTL_FIRST
3016 && (unsigned char)c <= CTL_LAST
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00003017 ) {
3018 return CCTL;
3019 }
3020 s = strchrnul(spec_symbls, c);
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01003021 if (*s == '\0')
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00003022 return CWORD;
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00003023 indx = syntax_index_table[s - spec_symbls];
3024 }
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01003025 return (S_I_T[indx] >> (syntax*4)) & 0xf;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00003026}
3027
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00003028#else /* !USE_SIT_FUNCTION */
Manuel Novoa III 16815d42001-08-10 19:36:07 +00003029
Denys Vlasenko3e134eb2016-04-22 18:09:21 +02003030static const uint8_t syntax_index_table[] ALIGN1 = {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003031 /* BASESYNTAX_DQSYNTAX_SQSYNTAX_ARISYNTAX */
Denys Vlasenkocd716832009-11-28 22:14:02 +01003032 /* 0 */ CWORD_CWORD_CWORD_CWORD,
3033 /* 1 */ CWORD_CWORD_CWORD_CWORD,
3034 /* 2 */ CWORD_CWORD_CWORD_CWORD,
3035 /* 3 */ CWORD_CWORD_CWORD_CWORD,
3036 /* 4 */ CWORD_CWORD_CWORD_CWORD,
3037 /* 5 */ CWORD_CWORD_CWORD_CWORD,
3038 /* 6 */ CWORD_CWORD_CWORD_CWORD,
3039 /* 7 */ CWORD_CWORD_CWORD_CWORD,
3040 /* 8 */ CWORD_CWORD_CWORD_CWORD,
3041 /* 9 "\t" */ CSPCL_CWORD_CWORD_CWORD,
3042 /* 10 "\n" */ CNL_CNL_CNL_CNL,
3043 /* 11 */ CWORD_CWORD_CWORD_CWORD,
3044 /* 12 */ CWORD_CWORD_CWORD_CWORD,
3045 /* 13 */ CWORD_CWORD_CWORD_CWORD,
3046 /* 14 */ CWORD_CWORD_CWORD_CWORD,
3047 /* 15 */ CWORD_CWORD_CWORD_CWORD,
3048 /* 16 */ CWORD_CWORD_CWORD_CWORD,
3049 /* 17 */ CWORD_CWORD_CWORD_CWORD,
3050 /* 18 */ CWORD_CWORD_CWORD_CWORD,
3051 /* 19 */ CWORD_CWORD_CWORD_CWORD,
3052 /* 20 */ CWORD_CWORD_CWORD_CWORD,
3053 /* 21 */ CWORD_CWORD_CWORD_CWORD,
3054 /* 22 */ CWORD_CWORD_CWORD_CWORD,
3055 /* 23 */ CWORD_CWORD_CWORD_CWORD,
3056 /* 24 */ CWORD_CWORD_CWORD_CWORD,
3057 /* 25 */ CWORD_CWORD_CWORD_CWORD,
3058 /* 26 */ CWORD_CWORD_CWORD_CWORD,
3059 /* 27 */ CWORD_CWORD_CWORD_CWORD,
3060 /* 28 */ CWORD_CWORD_CWORD_CWORD,
3061 /* 29 */ CWORD_CWORD_CWORD_CWORD,
3062 /* 30 */ CWORD_CWORD_CWORD_CWORD,
3063 /* 31 */ CWORD_CWORD_CWORD_CWORD,
3064 /* 32 " " */ CSPCL_CWORD_CWORD_CWORD,
3065 /* 33 "!" */ CWORD_CCTL_CCTL_CWORD,
3066 /* 34 """ */ CDQUOTE_CENDQUOTE_CWORD_CWORD,
3067 /* 35 "#" */ CWORD_CWORD_CWORD_CWORD,
3068 /* 36 "$" */ CVAR_CVAR_CWORD_CVAR,
3069 /* 37 "%" */ CWORD_CWORD_CWORD_CWORD,
3070 /* 38 "&" */ CSPCL_CWORD_CWORD_CWORD,
3071 /* 39 "'" */ CSQUOTE_CWORD_CENDQUOTE_CWORD,
3072 /* 40 "(" */ CSPCL_CWORD_CWORD_CLP,
3073 /* 41 ")" */ CSPCL_CWORD_CWORD_CRP,
3074 /* 42 "*" */ CWORD_CCTL_CCTL_CWORD,
3075 /* 43 "+" */ CWORD_CWORD_CWORD_CWORD,
3076 /* 44 "," */ CWORD_CWORD_CWORD_CWORD,
3077 /* 45 "-" */ CWORD_CCTL_CCTL_CWORD,
3078 /* 46 "." */ CWORD_CWORD_CWORD_CWORD,
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02003079/* "/" was CWORD_CCTL_CCTL_CWORD, see comment in SIT() function why this is changed: */
3080 /* 47 "/" */ CWORD_CWORD_CWORD_CWORD,
Denys Vlasenkocd716832009-11-28 22:14:02 +01003081 /* 48 "0" */ CWORD_CWORD_CWORD_CWORD,
3082 /* 49 "1" */ CWORD_CWORD_CWORD_CWORD,
3083 /* 50 "2" */ CWORD_CWORD_CWORD_CWORD,
3084 /* 51 "3" */ CWORD_CWORD_CWORD_CWORD,
3085 /* 52 "4" */ CWORD_CWORD_CWORD_CWORD,
3086 /* 53 "5" */ CWORD_CWORD_CWORD_CWORD,
3087 /* 54 "6" */ CWORD_CWORD_CWORD_CWORD,
3088 /* 55 "7" */ CWORD_CWORD_CWORD_CWORD,
3089 /* 56 "8" */ CWORD_CWORD_CWORD_CWORD,
3090 /* 57 "9" */ CWORD_CWORD_CWORD_CWORD,
3091 /* 58 ":" */ CWORD_CCTL_CCTL_CWORD,
3092 /* 59 ";" */ CSPCL_CWORD_CWORD_CWORD,
3093 /* 60 "<" */ CSPCL_CWORD_CWORD_CWORD,
3094 /* 61 "=" */ CWORD_CCTL_CCTL_CWORD,
3095 /* 62 ">" */ CSPCL_CWORD_CWORD_CWORD,
3096 /* 63 "?" */ CWORD_CCTL_CCTL_CWORD,
3097 /* 64 "@" */ CWORD_CWORD_CWORD_CWORD,
3098 /* 65 "A" */ CWORD_CWORD_CWORD_CWORD,
3099 /* 66 "B" */ CWORD_CWORD_CWORD_CWORD,
3100 /* 67 "C" */ CWORD_CWORD_CWORD_CWORD,
3101 /* 68 "D" */ CWORD_CWORD_CWORD_CWORD,
3102 /* 69 "E" */ CWORD_CWORD_CWORD_CWORD,
3103 /* 70 "F" */ CWORD_CWORD_CWORD_CWORD,
3104 /* 71 "G" */ CWORD_CWORD_CWORD_CWORD,
3105 /* 72 "H" */ CWORD_CWORD_CWORD_CWORD,
3106 /* 73 "I" */ CWORD_CWORD_CWORD_CWORD,
3107 /* 74 "J" */ CWORD_CWORD_CWORD_CWORD,
3108 /* 75 "K" */ CWORD_CWORD_CWORD_CWORD,
3109 /* 76 "L" */ CWORD_CWORD_CWORD_CWORD,
3110 /* 77 "M" */ CWORD_CWORD_CWORD_CWORD,
3111 /* 78 "N" */ CWORD_CWORD_CWORD_CWORD,
3112 /* 79 "O" */ CWORD_CWORD_CWORD_CWORD,
3113 /* 80 "P" */ CWORD_CWORD_CWORD_CWORD,
3114 /* 81 "Q" */ CWORD_CWORD_CWORD_CWORD,
3115 /* 82 "R" */ CWORD_CWORD_CWORD_CWORD,
3116 /* 83 "S" */ CWORD_CWORD_CWORD_CWORD,
3117 /* 84 "T" */ CWORD_CWORD_CWORD_CWORD,
3118 /* 85 "U" */ CWORD_CWORD_CWORD_CWORD,
3119 /* 86 "V" */ CWORD_CWORD_CWORD_CWORD,
3120 /* 87 "W" */ CWORD_CWORD_CWORD_CWORD,
3121 /* 88 "X" */ CWORD_CWORD_CWORD_CWORD,
3122 /* 89 "Y" */ CWORD_CWORD_CWORD_CWORD,
3123 /* 90 "Z" */ CWORD_CWORD_CWORD_CWORD,
3124 /* 91 "[" */ CWORD_CCTL_CCTL_CWORD,
3125 /* 92 "\" */ CBACK_CBACK_CCTL_CBACK,
3126 /* 93 "]" */ CWORD_CCTL_CCTL_CWORD,
3127 /* 94 "^" */ CWORD_CWORD_CWORD_CWORD,
3128 /* 95 "_" */ CWORD_CWORD_CWORD_CWORD,
3129 /* 96 "`" */ CBQUOTE_CBQUOTE_CWORD_CBQUOTE,
3130 /* 97 "a" */ CWORD_CWORD_CWORD_CWORD,
3131 /* 98 "b" */ CWORD_CWORD_CWORD_CWORD,
3132 /* 99 "c" */ CWORD_CWORD_CWORD_CWORD,
3133 /* 100 "d" */ CWORD_CWORD_CWORD_CWORD,
3134 /* 101 "e" */ CWORD_CWORD_CWORD_CWORD,
3135 /* 102 "f" */ CWORD_CWORD_CWORD_CWORD,
3136 /* 103 "g" */ CWORD_CWORD_CWORD_CWORD,
3137 /* 104 "h" */ CWORD_CWORD_CWORD_CWORD,
3138 /* 105 "i" */ CWORD_CWORD_CWORD_CWORD,
3139 /* 106 "j" */ CWORD_CWORD_CWORD_CWORD,
3140 /* 107 "k" */ CWORD_CWORD_CWORD_CWORD,
3141 /* 108 "l" */ CWORD_CWORD_CWORD_CWORD,
3142 /* 109 "m" */ CWORD_CWORD_CWORD_CWORD,
3143 /* 110 "n" */ CWORD_CWORD_CWORD_CWORD,
3144 /* 111 "o" */ CWORD_CWORD_CWORD_CWORD,
3145 /* 112 "p" */ CWORD_CWORD_CWORD_CWORD,
3146 /* 113 "q" */ CWORD_CWORD_CWORD_CWORD,
3147 /* 114 "r" */ CWORD_CWORD_CWORD_CWORD,
3148 /* 115 "s" */ CWORD_CWORD_CWORD_CWORD,
3149 /* 116 "t" */ CWORD_CWORD_CWORD_CWORD,
3150 /* 117 "u" */ CWORD_CWORD_CWORD_CWORD,
3151 /* 118 "v" */ CWORD_CWORD_CWORD_CWORD,
3152 /* 119 "w" */ CWORD_CWORD_CWORD_CWORD,
3153 /* 120 "x" */ CWORD_CWORD_CWORD_CWORD,
3154 /* 121 "y" */ CWORD_CWORD_CWORD_CWORD,
3155 /* 122 "z" */ CWORD_CWORD_CWORD_CWORD,
3156 /* 123 "{" */ CWORD_CWORD_CWORD_CWORD,
3157 /* 124 "|" */ CSPCL_CWORD_CWORD_CWORD,
3158 /* 125 "}" */ CENDVAR_CENDVAR_CWORD_CENDVAR,
3159 /* 126 "~" */ CWORD_CCTL_CCTL_CWORD,
3160 /* 127 del */ CWORD_CWORD_CWORD_CWORD,
3161 /* 128 0x80 */ CWORD_CWORD_CWORD_CWORD,
3162 /* 129 CTLESC */ CCTL_CCTL_CCTL_CCTL,
3163 /* 130 CTLVAR */ CCTL_CCTL_CCTL_CCTL,
3164 /* 131 CTLENDVAR */ CCTL_CCTL_CCTL_CCTL,
3165 /* 132 CTLBACKQ */ CCTL_CCTL_CCTL_CCTL,
3166 /* 133 CTLQUOTE */ CCTL_CCTL_CCTL_CCTL,
3167 /* 134 CTLARI */ CCTL_CCTL_CCTL_CCTL,
3168 /* 135 CTLENDARI */ CCTL_CCTL_CCTL_CCTL,
3169 /* 136 CTLQUOTEMARK */ CCTL_CCTL_CCTL_CCTL,
3170 /* 137 */ CWORD_CWORD_CWORD_CWORD,
3171 /* 138 */ CWORD_CWORD_CWORD_CWORD,
3172 /* 139 */ CWORD_CWORD_CWORD_CWORD,
3173 /* 140 */ CWORD_CWORD_CWORD_CWORD,
3174 /* 141 */ CWORD_CWORD_CWORD_CWORD,
3175 /* 142 */ CWORD_CWORD_CWORD_CWORD,
3176 /* 143 */ CWORD_CWORD_CWORD_CWORD,
3177 /* 144 */ CWORD_CWORD_CWORD_CWORD,
3178 /* 145 */ CWORD_CWORD_CWORD_CWORD,
3179 /* 146 */ CWORD_CWORD_CWORD_CWORD,
3180 /* 147 */ CWORD_CWORD_CWORD_CWORD,
3181 /* 148 */ CWORD_CWORD_CWORD_CWORD,
3182 /* 149 */ CWORD_CWORD_CWORD_CWORD,
3183 /* 150 */ CWORD_CWORD_CWORD_CWORD,
3184 /* 151 */ CWORD_CWORD_CWORD_CWORD,
3185 /* 152 */ CWORD_CWORD_CWORD_CWORD,
3186 /* 153 */ CWORD_CWORD_CWORD_CWORD,
3187 /* 154 */ CWORD_CWORD_CWORD_CWORD,
3188 /* 155 */ CWORD_CWORD_CWORD_CWORD,
3189 /* 156 */ CWORD_CWORD_CWORD_CWORD,
3190 /* 157 */ CWORD_CWORD_CWORD_CWORD,
3191 /* 158 */ CWORD_CWORD_CWORD_CWORD,
3192 /* 159 */ CWORD_CWORD_CWORD_CWORD,
3193 /* 160 */ CWORD_CWORD_CWORD_CWORD,
3194 /* 161 */ CWORD_CWORD_CWORD_CWORD,
3195 /* 162 */ CWORD_CWORD_CWORD_CWORD,
3196 /* 163 */ CWORD_CWORD_CWORD_CWORD,
3197 /* 164 */ CWORD_CWORD_CWORD_CWORD,
3198 /* 165 */ CWORD_CWORD_CWORD_CWORD,
3199 /* 166 */ CWORD_CWORD_CWORD_CWORD,
3200 /* 167 */ CWORD_CWORD_CWORD_CWORD,
3201 /* 168 */ CWORD_CWORD_CWORD_CWORD,
3202 /* 169 */ CWORD_CWORD_CWORD_CWORD,
3203 /* 170 */ CWORD_CWORD_CWORD_CWORD,
3204 /* 171 */ CWORD_CWORD_CWORD_CWORD,
3205 /* 172 */ CWORD_CWORD_CWORD_CWORD,
3206 /* 173 */ CWORD_CWORD_CWORD_CWORD,
3207 /* 174 */ CWORD_CWORD_CWORD_CWORD,
3208 /* 175 */ CWORD_CWORD_CWORD_CWORD,
3209 /* 176 */ CWORD_CWORD_CWORD_CWORD,
3210 /* 177 */ CWORD_CWORD_CWORD_CWORD,
3211 /* 178 */ CWORD_CWORD_CWORD_CWORD,
3212 /* 179 */ CWORD_CWORD_CWORD_CWORD,
3213 /* 180 */ CWORD_CWORD_CWORD_CWORD,
3214 /* 181 */ CWORD_CWORD_CWORD_CWORD,
3215 /* 182 */ CWORD_CWORD_CWORD_CWORD,
3216 /* 183 */ CWORD_CWORD_CWORD_CWORD,
3217 /* 184 */ CWORD_CWORD_CWORD_CWORD,
3218 /* 185 */ CWORD_CWORD_CWORD_CWORD,
3219 /* 186 */ CWORD_CWORD_CWORD_CWORD,
3220 /* 187 */ CWORD_CWORD_CWORD_CWORD,
3221 /* 188 */ CWORD_CWORD_CWORD_CWORD,
3222 /* 189 */ CWORD_CWORD_CWORD_CWORD,
3223 /* 190 */ CWORD_CWORD_CWORD_CWORD,
3224 /* 191 */ CWORD_CWORD_CWORD_CWORD,
3225 /* 192 */ CWORD_CWORD_CWORD_CWORD,
3226 /* 193 */ CWORD_CWORD_CWORD_CWORD,
3227 /* 194 */ CWORD_CWORD_CWORD_CWORD,
3228 /* 195 */ CWORD_CWORD_CWORD_CWORD,
3229 /* 196 */ CWORD_CWORD_CWORD_CWORD,
3230 /* 197 */ CWORD_CWORD_CWORD_CWORD,
3231 /* 198 */ CWORD_CWORD_CWORD_CWORD,
3232 /* 199 */ CWORD_CWORD_CWORD_CWORD,
3233 /* 200 */ CWORD_CWORD_CWORD_CWORD,
3234 /* 201 */ CWORD_CWORD_CWORD_CWORD,
3235 /* 202 */ CWORD_CWORD_CWORD_CWORD,
3236 /* 203 */ CWORD_CWORD_CWORD_CWORD,
3237 /* 204 */ CWORD_CWORD_CWORD_CWORD,
3238 /* 205 */ CWORD_CWORD_CWORD_CWORD,
3239 /* 206 */ CWORD_CWORD_CWORD_CWORD,
3240 /* 207 */ CWORD_CWORD_CWORD_CWORD,
3241 /* 208 */ CWORD_CWORD_CWORD_CWORD,
3242 /* 209 */ CWORD_CWORD_CWORD_CWORD,
3243 /* 210 */ CWORD_CWORD_CWORD_CWORD,
3244 /* 211 */ CWORD_CWORD_CWORD_CWORD,
3245 /* 212 */ CWORD_CWORD_CWORD_CWORD,
3246 /* 213 */ CWORD_CWORD_CWORD_CWORD,
3247 /* 214 */ CWORD_CWORD_CWORD_CWORD,
3248 /* 215 */ CWORD_CWORD_CWORD_CWORD,
3249 /* 216 */ CWORD_CWORD_CWORD_CWORD,
3250 /* 217 */ CWORD_CWORD_CWORD_CWORD,
3251 /* 218 */ CWORD_CWORD_CWORD_CWORD,
3252 /* 219 */ CWORD_CWORD_CWORD_CWORD,
3253 /* 220 */ CWORD_CWORD_CWORD_CWORD,
3254 /* 221 */ CWORD_CWORD_CWORD_CWORD,
3255 /* 222 */ CWORD_CWORD_CWORD_CWORD,
3256 /* 223 */ CWORD_CWORD_CWORD_CWORD,
3257 /* 224 */ CWORD_CWORD_CWORD_CWORD,
3258 /* 225 */ CWORD_CWORD_CWORD_CWORD,
3259 /* 226 */ CWORD_CWORD_CWORD_CWORD,
3260 /* 227 */ CWORD_CWORD_CWORD_CWORD,
3261 /* 228 */ CWORD_CWORD_CWORD_CWORD,
3262 /* 229 */ CWORD_CWORD_CWORD_CWORD,
3263 /* 230 */ CWORD_CWORD_CWORD_CWORD,
3264 /* 231 */ CWORD_CWORD_CWORD_CWORD,
3265 /* 232 */ CWORD_CWORD_CWORD_CWORD,
3266 /* 233 */ CWORD_CWORD_CWORD_CWORD,
3267 /* 234 */ CWORD_CWORD_CWORD_CWORD,
3268 /* 235 */ CWORD_CWORD_CWORD_CWORD,
3269 /* 236 */ CWORD_CWORD_CWORD_CWORD,
3270 /* 237 */ CWORD_CWORD_CWORD_CWORD,
3271 /* 238 */ CWORD_CWORD_CWORD_CWORD,
3272 /* 239 */ CWORD_CWORD_CWORD_CWORD,
3273 /* 230 */ CWORD_CWORD_CWORD_CWORD,
3274 /* 241 */ CWORD_CWORD_CWORD_CWORD,
3275 /* 242 */ CWORD_CWORD_CWORD_CWORD,
3276 /* 243 */ CWORD_CWORD_CWORD_CWORD,
3277 /* 244 */ CWORD_CWORD_CWORD_CWORD,
3278 /* 245 */ CWORD_CWORD_CWORD_CWORD,
3279 /* 246 */ CWORD_CWORD_CWORD_CWORD,
3280 /* 247 */ CWORD_CWORD_CWORD_CWORD,
3281 /* 248 */ CWORD_CWORD_CWORD_CWORD,
3282 /* 249 */ CWORD_CWORD_CWORD_CWORD,
3283 /* 250 */ CWORD_CWORD_CWORD_CWORD,
3284 /* 251 */ CWORD_CWORD_CWORD_CWORD,
3285 /* 252 */ CWORD_CWORD_CWORD_CWORD,
3286 /* 253 */ CWORD_CWORD_CWORD_CWORD,
3287 /* 254 */ CWORD_CWORD_CWORD_CWORD,
3288 /* 255 */ CWORD_CWORD_CWORD_CWORD,
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01003289 /* PEOF */ CENDFILE_CENDFILE_CENDFILE_CENDFILE,
Denys Vlasenkocd716832009-11-28 22:14:02 +01003290# if ENABLE_ASH_ALIAS
3291 /* PEOA */ CSPCL_CIGN_CIGN_CIGN,
3292# endif
Eric Andersen2870d962001-07-02 17:27:21 +00003293};
3294
Denys Vlasenko2fe66b12016-12-12 17:39:12 +01003295#if 1
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01003296# define SIT(c, syntax) ((S_I_T[syntax_index_table[c]] >> ((syntax)*4)) & 0xf)
Denys Vlasenko2fe66b12016-12-12 17:39:12 +01003297#else /* debug version, caught one signed char bug */
3298# define SIT(c, syntax) \
3299 ({ \
3300 if ((c) < 0 || (c) > (PEOF + ENABLE_ASH_ALIAS)) \
3301 bb_error_msg_and_die("line:%d c:%d", __LINE__, (c)); \
Denys Vlasenko0b883582016-12-23 16:49:07 +01003302 if ((syntax) < 0 || (syntax) > (2 + ENABLE_FEATURE_SH_MATH)) \
Denys Vlasenko2fe66b12016-12-12 17:39:12 +01003303 bb_error_msg_and_die("line:%d c:%d", __LINE__, (c)); \
3304 ((S_I_T[syntax_index_table[c]] >> ((syntax)*4)) & 0xf); \
3305 })
3306#endif
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00003307
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01003308#endif /* !USE_SIT_FUNCTION */
Eric Andersenc470f442003-07-28 09:56:35 +00003309
Eric Andersen2870d962001-07-02 17:27:21 +00003310
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00003311/* ============ Alias handling */
Denis Vlasenkofc06f292007-02-23 21:09:35 +00003312
Denis Vlasenko131ae172007-02-18 13:00:19 +00003313#if ENABLE_ASH_ALIAS
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00003314
3315#define ALIASINUSE 1
3316#define ALIASDEAD 2
3317
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00003318struct alias {
3319 struct alias *next;
3320 char *name;
3321 char *val;
3322 int flag;
3323};
3324
Denis Vlasenko01631112007-12-16 17:20:38 +00003325
3326static struct alias **atab; // [ATABSIZE];
3327#define INIT_G_alias() do { \
3328 atab = xzalloc(ATABSIZE * sizeof(atab[0])); \
3329} while (0)
3330
Eric Andersen2870d962001-07-02 17:27:21 +00003331
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00003332static struct alias **
Denys Vlasenko37dc08b2016-10-02 04:38:07 +02003333__lookupalias(const char *name)
3334{
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00003335 unsigned int hashval;
3336 struct alias **app;
3337 const char *p;
3338 unsigned int ch;
3339
3340 p = name;
3341
3342 ch = (unsigned char)*p;
3343 hashval = ch << 4;
3344 while (ch) {
3345 hashval += ch;
3346 ch = (unsigned char)*++p;
3347 }
3348 app = &atab[hashval % ATABSIZE];
3349
3350 for (; *app; app = &(*app)->next) {
3351 if (strcmp(name, (*app)->name) == 0) {
3352 break;
3353 }
3354 }
3355
3356 return app;
3357}
3358
3359static struct alias *
3360lookupalias(const char *name, int check)
3361{
3362 struct alias *ap = *__lookupalias(name);
3363
3364 if (check && ap && (ap->flag & ALIASINUSE))
3365 return NULL;
3366 return ap;
3367}
3368
3369static struct alias *
3370freealias(struct alias *ap)
3371{
3372 struct alias *next;
3373
3374 if (ap->flag & ALIASINUSE) {
3375 ap->flag |= ALIASDEAD;
3376 return ap;
3377 }
3378
3379 next = ap->next;
3380 free(ap->name);
3381 free(ap->val);
3382 free(ap);
3383 return next;
3384}
Eric Andersencb57d552001-06-28 07:25:16 +00003385
Eric Andersenc470f442003-07-28 09:56:35 +00003386static void
3387setalias(const char *name, const char *val)
Eric Andersencb57d552001-06-28 07:25:16 +00003388{
3389 struct alias *ap, **app;
3390
3391 app = __lookupalias(name);
3392 ap = *app;
Denis Vlasenkob012b102007-02-19 22:43:01 +00003393 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +00003394 if (ap) {
3395 if (!(ap->flag & ALIASINUSE)) {
Denis Vlasenkob012b102007-02-19 22:43:01 +00003396 free(ap->val);
Eric Andersencb57d552001-06-28 07:25:16 +00003397 }
Denis Vlasenko0c032a42007-02-23 01:03:40 +00003398 ap->val = ckstrdup(val);
Eric Andersencb57d552001-06-28 07:25:16 +00003399 ap->flag &= ~ALIASDEAD;
3400 } else {
3401 /* not found */
Denis Vlasenko597906c2008-02-20 16:38:54 +00003402 ap = ckzalloc(sizeof(struct alias));
Denis Vlasenko0c032a42007-02-23 01:03:40 +00003403 ap->name = ckstrdup(name);
3404 ap->val = ckstrdup(val);
Denis Vlasenko597906c2008-02-20 16:38:54 +00003405 /*ap->flag = 0; - ckzalloc did it */
3406 /*ap->next = NULL;*/
Eric Andersencb57d552001-06-28 07:25:16 +00003407 *app = ap;
3408 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00003409 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +00003410}
3411
Eric Andersenc470f442003-07-28 09:56:35 +00003412static int
3413unalias(const char *name)
Eric Andersen2870d962001-07-02 17:27:21 +00003414{
Eric Andersencb57d552001-06-28 07:25:16 +00003415 struct alias **app;
3416
3417 app = __lookupalias(name);
3418
3419 if (*app) {
Denis Vlasenkob012b102007-02-19 22:43:01 +00003420 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +00003421 *app = freealias(*app);
Denis Vlasenkob012b102007-02-19 22:43:01 +00003422 INT_ON;
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003423 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003424 }
3425
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003426 return 1;
Eric Andersencb57d552001-06-28 07:25:16 +00003427}
3428
Eric Andersenc470f442003-07-28 09:56:35 +00003429static void
3430rmaliases(void)
Eric Andersen2870d962001-07-02 17:27:21 +00003431{
Eric Andersencb57d552001-06-28 07:25:16 +00003432 struct alias *ap, **app;
3433 int i;
3434
Denis Vlasenkob012b102007-02-19 22:43:01 +00003435 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +00003436 for (i = 0; i < ATABSIZE; i++) {
3437 app = &atab[i];
3438 for (ap = *app; ap; ap = *app) {
3439 *app = freealias(*app);
3440 if (ap == *app) {
3441 app = &ap->next;
3442 }
3443 }
3444 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00003445 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +00003446}
3447
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00003448static void
3449printalias(const struct alias *ap)
3450{
3451 out1fmt("%s=%s\n", ap->name, single_quote(ap->val));
3452}
3453
Eric Andersencb57d552001-06-28 07:25:16 +00003454/*
3455 * TODO - sort output
3456 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02003457static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003458aliascmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003459{
3460 char *n, *v;
3461 int ret = 0;
3462 struct alias *ap;
3463
Denis Vlasenko68404f12008-03-17 09:00:54 +00003464 if (!argv[1]) {
Eric Andersencb57d552001-06-28 07:25:16 +00003465 int i;
3466
Denis Vlasenko68404f12008-03-17 09:00:54 +00003467 for (i = 0; i < ATABSIZE; i++) {
Eric Andersencb57d552001-06-28 07:25:16 +00003468 for (ap = atab[i]; ap; ap = ap->next) {
3469 printalias(ap);
3470 }
Denis Vlasenko68404f12008-03-17 09:00:54 +00003471 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003472 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003473 }
3474 while ((n = *++argv) != NULL) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +00003475 v = strchr(n+1, '=');
3476 if (v == NULL) { /* n+1: funny ksh stuff */
3477 ap = *__lookupalias(n);
3478 if (ap == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00003479 fprintf(stderr, "%s: %s not found\n", "alias", n);
Eric Andersencb57d552001-06-28 07:25:16 +00003480 ret = 1;
3481 } else
3482 printalias(ap);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003483 } else {
Eric Andersencb57d552001-06-28 07:25:16 +00003484 *v++ = '\0';
3485 setalias(n, v);
3486 }
3487 }
3488
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003489 return ret;
Eric Andersencb57d552001-06-28 07:25:16 +00003490}
3491
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02003492static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003493unaliascmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +00003494{
3495 int i;
3496
Denys Vlasenko6c149f42017-04-12 21:31:32 +02003497 while (nextopt("a") != '\0') {
3498 rmaliases();
3499 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003500 }
3501 for (i = 0; *argptr; argptr++) {
3502 if (unalias(*argptr)) {
Eric Andersenc470f442003-07-28 09:56:35 +00003503 fprintf(stderr, "%s: %s not found\n", "unalias", *argptr);
Eric Andersencb57d552001-06-28 07:25:16 +00003504 i = 1;
3505 }
3506 }
3507
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003508 return i;
Eric Andersencb57d552001-06-28 07:25:16 +00003509}
Denis Vlasenkofc06f292007-02-23 21:09:35 +00003510
Denis Vlasenko131ae172007-02-18 13:00:19 +00003511#endif /* ASH_ALIAS */
Eric Andersencb57d552001-06-28 07:25:16 +00003512
Eric Andersenc470f442003-07-28 09:56:35 +00003513
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003514/* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */
Denys Vlasenko285ad152009-12-04 23:02:27 +01003515#define FORK_FG 0
3516#define FORK_BG 1
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003517#define FORK_NOJOB 2
3518
3519/* mode flags for showjob(s) */
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02003520#define SHOW_ONLY_PGID 0x01 /* show only pgid (jobs -p) */
3521#define SHOW_PIDS 0x02 /* show individual pids, not just one line per job */
3522#define SHOW_CHANGED 0x04 /* only jobs whose state has changed */
Denys Vlasenko9c541002015-10-07 15:44:36 +02003523#define SHOW_STDERR 0x08 /* print to stderr (else stdout) */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003524
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003525/*
3526 * A job structure contains information about a job. A job is either a
3527 * single process or a set of processes contained in a pipeline. In the
3528 * latter case, pidlist will be non-NULL, and will point to a -1 terminated
3529 * array of pids.
3530 */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003531struct procstat {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003532 pid_t ps_pid; /* process id */
3533 int ps_status; /* last process status from wait() */
3534 char *ps_cmd; /* text of command being run */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003535};
3536
3537struct job {
3538 struct procstat ps0; /* status of process */
Denys Vlasenko966f0872019-03-27 15:51:42 +01003539 struct procstat *ps; /* status of processes when more than one */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003540#if JOBS
3541 int stopstatus; /* status of a stopped job */
3542#endif
Denys Vlasenko4c179372017-01-11 18:44:15 +01003543 unsigned nprocs; /* number of processes */
3544
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003545#define JOBRUNNING 0 /* at least one proc running */
3546#define JOBSTOPPED 1 /* all procs are stopped */
3547#define JOBDONE 2 /* all procs are completed */
Denys Vlasenko4c179372017-01-11 18:44:15 +01003548 unsigned
3549 state: 8,
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003550#if JOBS
3551 sigint: 1, /* job was killed by SIGINT */
3552 jobctl: 1, /* job running under job control */
3553#endif
3554 waited: 1, /* true if this entry has been waited for */
3555 used: 1, /* true if this entry is in used */
3556 changed: 1; /* true if status has changed */
3557 struct job *prev_job; /* previous job */
3558};
3559
Denis Vlasenko68404f12008-03-17 09:00:54 +00003560static struct job *makejob(/*union node *,*/ int);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003561static int forkshell(struct job *, union node *, int);
3562static int waitforjob(struct job *);
3563
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00003564#if !JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +00003565enum { doing_jobctl = 0 };
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00003566#define setjobctl(on) do {} while (0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003567#else
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003568static smallint doing_jobctl; //references:8
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003569static void setjobctl(int);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003570#endif
3571
3572/*
Denis Vlasenko4b875702009-03-19 13:30:04 +00003573 * Ignore a signal.
3574 */
3575static void
3576ignoresig(int signo)
3577{
3578 /* Avoid unnecessary system calls. Is it already SIG_IGNed? */
3579 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
3580 /* No, need to do it */
3581 signal(signo, SIG_IGN);
3582 }
3583 sigmode[signo - 1] = S_HARD_IGN;
3584}
3585
3586/*
Denys Vlasenko238bf182010-05-18 15:49:07 +02003587 * Only one usage site - in setsignal()
Denis Vlasenko4b875702009-03-19 13:30:04 +00003588 */
3589static void
Denys Vlasenko238bf182010-05-18 15:49:07 +02003590signal_handler(int signo)
Denis Vlasenko4b875702009-03-19 13:30:04 +00003591{
Denys Vlasenko458c1f22016-10-27 23:51:19 +02003592 if (signo == SIGCHLD) {
3593 got_sigchld = 1;
3594 if (!trap[SIGCHLD])
3595 return;
3596 }
3597
Denis Vlasenko4b875702009-03-19 13:30:04 +00003598 gotsig[signo - 1] = 1;
Denys Vlasenko458c1f22016-10-27 23:51:19 +02003599 pending_sig = signo;
Denis Vlasenko4b875702009-03-19 13:30:04 +00003600
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02003601 if (signo == SIGINT && !trap[SIGINT]) {
3602 if (!suppress_int) {
3603 pending_sig = 0;
Denis Vlasenko4b875702009-03-19 13:30:04 +00003604 raise_interrupt(); /* does not return */
3605 }
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02003606 pending_int = 1;
Denis Vlasenko4b875702009-03-19 13:30:04 +00003607 }
3608}
3609
3610/*
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003611 * Set the signal handler for the specified signal. The routine figures
3612 * out what it should be set to.
3613 */
3614static void
3615setsignal(int signo)
3616{
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003617 char *t;
3618 char cur_act, new_act;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003619 struct sigaction act;
3620
3621 t = trap[signo];
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003622 new_act = S_DFL;
3623 if (t != NULL) { /* trap for this sig is set */
3624 new_act = S_CATCH;
3625 if (t[0] == '\0') /* trap is "": ignore this sig */
3626 new_act = S_IGN;
3627 }
3628
3629 if (rootshell && new_act == S_DFL) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003630 switch (signo) {
3631 case SIGINT:
3632 if (iflag || minusc || sflag == 0)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003633 new_act = S_CATCH;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003634 break;
3635 case SIGQUIT:
3636#if DEBUG
3637 if (debug)
3638 break;
3639#endif
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003640 /* man bash:
3641 * "In all cases, bash ignores SIGQUIT. Non-builtin
3642 * commands run by bash have signal handlers
3643 * set to the values inherited by the shell
3644 * from its parent". */
3645 new_act = S_IGN;
3646 break;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003647 case SIGTERM:
3648 if (iflag)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003649 new_act = S_IGN;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003650 break;
3651#if JOBS
3652 case SIGTSTP:
3653 case SIGTTOU:
3654 if (mflag)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003655 new_act = S_IGN;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003656 break;
3657#endif
3658 }
3659 }
Denys Vlasenko49e6bf22017-08-04 14:28:16 +02003660 /* if !rootshell, we reset SIGQUIT to DFL,
3661 * whereas we have to restore it to what shell got on entry.
3662 * This is handled by the fact that if signal was IGNored on entry,
3663 * then cur_act is S_HARD_IGN and we never change its sigaction
3664 * (see code below).
3665 */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003666
Denys Vlasenko458c1f22016-10-27 23:51:19 +02003667 if (signo == SIGCHLD)
3668 new_act = S_CATCH;
3669
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003670 t = &sigmode[signo - 1];
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003671 cur_act = *t;
3672 if (cur_act == 0) {
3673 /* current setting is not yet known */
3674 if (sigaction(signo, NULL, &act)) {
3675 /* pretend it worked; maybe we should give a warning,
3676 * but other shells don't. We don't alter sigmode,
3677 * so we retry every time.
3678 * btw, in Linux it never fails. --vda */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003679 return;
3680 }
3681 if (act.sa_handler == SIG_IGN) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003682 cur_act = S_HARD_IGN;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003683 if (mflag
3684 && (signo == SIGTSTP || signo == SIGTTIN || signo == SIGTTOU)
3685 ) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003686 cur_act = S_IGN; /* don't hard ignore these */
Denis Vlasenko991a1da2008-02-10 19:02:53 +00003687 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003688 }
Denys Vlasenko0f14f412017-08-06 20:06:19 +02003689 if (act.sa_handler == SIG_DFL && new_act == S_DFL) {
3690 /* installing SIG_DFL over SIG_DFL is a no-op */
3691 /* saves one sigaction call in each "sh -c SCRIPT" invocation */
3692 *t = S_DFL;
3693 return;
3694 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003695 }
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003696 if (cur_act == S_HARD_IGN || cur_act == new_act)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003697 return;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003698
Denys Vlasenko49e6bf22017-08-04 14:28:16 +02003699 *t = new_act;
3700
Denis Vlasenko991a1da2008-02-10 19:02:53 +00003701 act.sa_handler = SIG_DFL;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003702 switch (new_act) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003703 case S_CATCH:
Denys Vlasenko238bf182010-05-18 15:49:07 +02003704 act.sa_handler = signal_handler;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003705 break;
3706 case S_IGN:
3707 act.sa_handler = SIG_IGN;
3708 break;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003709 }
Ian Wienand89b3cba2011-04-16 20:05:14 +02003710 /* flags and mask matter only if !DFL and !IGN, but we do it
3711 * for all cases for more deterministic behavior:
3712 */
Denys Vlasenko49e6bf22017-08-04 14:28:16 +02003713 act.sa_flags = 0; //TODO: why not SA_RESTART?
Ian Wienand89b3cba2011-04-16 20:05:14 +02003714 sigfillset(&act.sa_mask);
3715
Denis Vlasenko8e2cfec2008-03-12 23:19:35 +00003716 sigaction_set(signo, &act);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003717}
3718
3719/* mode flags for set_curjob */
3720#define CUR_DELETE 2
3721#define CUR_RUNNING 1
3722#define CUR_STOPPED 0
3723
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003724#if JOBS
3725/* pgrp of shell on invocation */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003726static int initialpgrp; //references:2
3727static int ttyfd = -1; //5
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003728#endif
3729/* array of jobs */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003730static struct job *jobtab; //5
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003731/* size of array */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003732static unsigned njobs; //4
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003733/* current job */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003734static struct job *curjob; //lots
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003735/* number of presumed living untracked jobs */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003736static int jobless; //4
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003737
Denys Vlasenko098b7132017-01-11 19:59:03 +01003738#if 0
3739/* Bash has a feature: it restores termios after a successful wait for
3740 * a foreground job which had at least one stopped or sigkilled member.
3741 * The probable rationale is that SIGSTOP and SIGKILL can preclude task from
3742 * properly restoring tty state. Should we do this too?
3743 * A reproducer: ^Z an interactive python:
3744 *
3745 * # python
3746 * Python 2.7.12 (...)
3747 * >>> ^Z
3748 * { python leaves tty in -icanon -echo state. We do survive that... }
3749 * [1]+ Stopped python
3750 * { ...however, next program (python #2) does not survive it well: }
3751 * # python
3752 * Python 2.7.12 (...)
3753 * >>> Traceback (most recent call last):
3754 * { above, I typed "qwerty<CR>", but -echo state is still in effect }
3755 * File "<stdin>", line 1, in <module>
3756 * NameError: name 'qwerty' is not defined
3757 *
3758 * The implementation below is modeled on bash code and seems to work.
3759 * However, I'm not sure we should do this. For one: what if I'd fg
3760 * the stopped python instead? It'll be confused by "restored" tty state.
3761 */
3762static struct termios shell_tty_info;
3763static void
3764get_tty_state(void)
3765{
3766 if (rootshell && ttyfd >= 0)
3767 tcgetattr(ttyfd, &shell_tty_info);
3768}
3769static void
3770set_tty_state(void)
3771{
3772 /* if (rootshell) - caller ensures this */
3773 if (ttyfd >= 0)
3774 tcsetattr(ttyfd, TCSADRAIN, &shell_tty_info);
3775}
3776static int
3777job_signal_status(struct job *jp)
3778{
3779 int status;
3780 unsigned i;
3781 struct procstat *ps = jp->ps;
3782 for (i = 0; i < jp->nprocs; i++) {
3783 status = ps[i].ps_status;
3784 if (WIFSIGNALED(status) || WIFSTOPPED(status))
3785 return status;
3786 }
3787 return 0;
3788}
3789static void
3790restore_tty_if_stopped_or_signaled(struct job *jp)
3791{
3792//TODO: check what happens if we come from waitforjob() in expbackq()
3793 if (rootshell) {
3794 int s = job_signal_status(jp);
3795 if (s) /* WIFSIGNALED(s) || WIFSTOPPED(s) */
3796 set_tty_state();
3797 }
3798}
3799#else
3800# define get_tty_state() ((void)0)
3801# define restore_tty_if_stopped_or_signaled(jp) ((void)0)
3802#endif
3803
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003804static void
3805set_curjob(struct job *jp, unsigned mode)
3806{
3807 struct job *jp1;
3808 struct job **jpp, **curp;
3809
3810 /* first remove from list */
3811 jpp = curp = &curjob;
Denys Vlasenko940c7202011-03-02 04:07:14 +01003812 while (1) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003813 jp1 = *jpp;
3814 if (jp1 == jp)
3815 break;
3816 jpp = &jp1->prev_job;
Denys Vlasenko940c7202011-03-02 04:07:14 +01003817 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003818 *jpp = jp1->prev_job;
3819
3820 /* Then re-insert in correct position */
3821 jpp = curp;
3822 switch (mode) {
3823 default:
3824#if DEBUG
3825 abort();
3826#endif
3827 case CUR_DELETE:
3828 /* job being deleted */
3829 break;
3830 case CUR_RUNNING:
3831 /* newly created job or backgrounded job,
Denys Vlasenko60cb48c2013-01-14 15:57:44 +01003832 * put after all stopped jobs.
3833 */
Denys Vlasenko940c7202011-03-02 04:07:14 +01003834 while (1) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003835 jp1 = *jpp;
3836#if JOBS
3837 if (!jp1 || jp1->state != JOBSTOPPED)
3838#endif
3839 break;
3840 jpp = &jp1->prev_job;
Denys Vlasenko940c7202011-03-02 04:07:14 +01003841 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003842 /* FALLTHROUGH */
3843#if JOBS
3844 case CUR_STOPPED:
3845#endif
3846 /* newly stopped job - becomes curjob */
3847 jp->prev_job = *jpp;
3848 *jpp = jp;
3849 break;
3850 }
3851}
3852
3853#if JOBS || DEBUG
3854static int
3855jobno(const struct job *jp)
3856{
3857 return jp - jobtab + 1;
3858}
3859#endif
3860
3861/*
3862 * Convert a job name to a job structure.
3863 */
Denis Vlasenko85c24712008-03-17 09:04:04 +00003864#if !JOBS
3865#define getjob(name, getctl) getjob(name)
3866#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003867static struct job *
3868getjob(const char *name, int getctl)
3869{
3870 struct job *jp;
3871 struct job *found;
Denys Vlasenkoffc39202009-08-17 02:12:20 +02003872 const char *err_msg = "%s: no such job";
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003873 unsigned num;
3874 int c;
3875 const char *p;
3876 char *(*match)(const char *, const char *);
3877
3878 jp = curjob;
3879 p = name;
3880 if (!p)
3881 goto currentjob;
3882
3883 if (*p != '%')
3884 goto err;
3885
3886 c = *++p;
3887 if (!c)
3888 goto currentjob;
3889
3890 if (!p[1]) {
3891 if (c == '+' || c == '%') {
3892 currentjob:
3893 err_msg = "No current job";
3894 goto check;
3895 }
3896 if (c == '-') {
3897 if (jp)
3898 jp = jp->prev_job;
3899 err_msg = "No previous job";
3900 check:
3901 if (!jp)
3902 goto err;
3903 goto gotit;
3904 }
3905 }
3906
3907 if (is_number(p)) {
3908 num = atoi(p);
Denys Vlasenko46a45ce2016-09-29 01:10:08 +02003909 if (num > 0 && num <= njobs) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003910 jp = jobtab + num - 1;
3911 if (jp->used)
3912 goto gotit;
3913 goto err;
3914 }
3915 }
3916
3917 match = prefix;
3918 if (*p == '?') {
3919 match = strstr;
3920 p++;
3921 }
3922
Denys Vlasenkoffc39202009-08-17 02:12:20 +02003923 found = NULL;
3924 while (jp) {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003925 if (match(jp->ps[0].ps_cmd, p)) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003926 if (found)
3927 goto err;
3928 found = jp;
3929 err_msg = "%s: ambiguous";
3930 }
3931 jp = jp->prev_job;
3932 }
Denys Vlasenkoffc39202009-08-17 02:12:20 +02003933 if (!found)
3934 goto err;
3935 jp = found;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003936
3937 gotit:
3938#if JOBS
3939 err_msg = "job %s not created under job control";
3940 if (getctl && jp->jobctl == 0)
3941 goto err;
3942#endif
3943 return jp;
3944 err:
3945 ash_msg_and_raise_error(err_msg, name);
3946}
3947
3948/*
3949 * Mark a job structure as unused.
3950 */
3951static void
3952freejob(struct job *jp)
3953{
3954 struct procstat *ps;
3955 int i;
3956
3957 INT_OFF;
3958 for (i = jp->nprocs, ps = jp->ps; --i >= 0; ps++) {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003959 if (ps->ps_cmd != nullstr)
3960 free(ps->ps_cmd);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003961 }
3962 if (jp->ps != &jp->ps0)
3963 free(jp->ps);
3964 jp->used = 0;
3965 set_curjob(jp, CUR_DELETE);
3966 INT_ON;
3967}
3968
3969#if JOBS
3970static void
3971xtcsetpgrp(int fd, pid_t pgrp)
3972{
3973 if (tcsetpgrp(fd, pgrp))
Ron Yorstonbe366e52017-07-27 13:53:39 +01003974 ash_msg_and_raise_perror("can't set tty process group");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003975}
3976
3977/*
3978 * Turn job control on and off.
3979 *
3980 * Note: This code assumes that the third arg to ioctl is a character
3981 * pointer, which is true on Berkeley systems but not System V. Since
3982 * System V doesn't have job control yet, this isn't a problem now.
3983 *
3984 * Called with interrupts off.
3985 */
3986static void
3987setjobctl(int on)
3988{
3989 int fd;
3990 int pgrp;
3991
Denis Vlasenkob07a4962008-06-22 13:16:23 +00003992 if (on == doing_jobctl || rootshell == 0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003993 return;
3994 if (on) {
3995 int ofd;
3996 ofd = fd = open(_PATH_TTY, O_RDWR);
3997 if (fd < 0) {
3998 /* BTW, bash will try to open(ttyname(0)) if open("/dev/tty") fails.
3999 * That sometimes helps to acquire controlling tty.
4000 * Obviously, a workaround for bugs when someone
4001 * failed to provide a controlling tty to bash! :) */
Denis Vlasenkoed270a52007-11-26 05:37:07 +00004002 fd = 2;
4003 while (!isatty(fd))
4004 if (--fd < 0)
4005 goto out;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004006 }
Denys Vlasenko64774602016-10-26 15:24:30 +02004007 /* fd is a tty at this point */
Denys Vlasenko60fb98e2018-03-30 22:15:14 +02004008 fd = fcntl(fd, F_DUPFD_CLOEXEC, 10);
Denys Vlasenko10ad6222017-04-17 16:13:32 +02004009 if (ofd >= 0) /* if it is "/dev/tty", close. If 0/1/2, don't */
Denis Vlasenkoed270a52007-11-26 05:37:07 +00004010 close(ofd);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004011 if (fd < 0)
Denys Vlasenko64774602016-10-26 15:24:30 +02004012 goto out; /* F_DUPFD failed */
Denys Vlasenko60fb98e2018-03-30 22:15:14 +02004013 if (F_DUPFD_CLOEXEC == F_DUPFD) /* if old libc (w/o F_DUPFD_CLOEXEC) */
4014 close_on_exec_on(fd);
Denys Vlasenko940c7202011-03-02 04:07:14 +01004015 while (1) { /* while we are in the background */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004016 pgrp = tcgetpgrp(fd);
4017 if (pgrp < 0) {
4018 out:
4019 ash_msg("can't access tty; job control turned off");
4020 mflag = on = 0;
4021 goto close;
4022 }
4023 if (pgrp == getpgrp())
4024 break;
4025 killpg(0, SIGTTIN);
Denys Vlasenko940c7202011-03-02 04:07:14 +01004026 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004027 initialpgrp = pgrp;
4028
4029 setsignal(SIGTSTP);
4030 setsignal(SIGTTOU);
4031 setsignal(SIGTTIN);
4032 pgrp = rootpid;
4033 setpgid(0, pgrp);
4034 xtcsetpgrp(fd, pgrp);
4035 } else {
4036 /* turning job control off */
4037 fd = ttyfd;
4038 pgrp = initialpgrp;
Denis Vlasenko08c8c1d2007-04-28 22:39:02 +00004039 /* was xtcsetpgrp, but this can make exiting ash
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004040 * loop forever if pty is already deleted */
Denis Vlasenko08c8c1d2007-04-28 22:39:02 +00004041 tcsetpgrp(fd, pgrp);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004042 setpgid(0, pgrp);
4043 setsignal(SIGTSTP);
4044 setsignal(SIGTTOU);
4045 setsignal(SIGTTIN);
4046 close:
Denis Vlasenkoed270a52007-11-26 05:37:07 +00004047 if (fd >= 0)
4048 close(fd);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004049 fd = -1;
4050 }
4051 ttyfd = fd;
Denis Vlasenkob07a4962008-06-22 13:16:23 +00004052 doing_jobctl = on;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004053}
4054
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02004055static int FAST_FUNC
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004056killcmd(int argc, char **argv)
4057{
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00004058 if (argv[1] && strcmp(argv[1], "-l") != 0) {
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004059 int i = 1;
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00004060 do {
4061 if (argv[i][0] == '%') {
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004062 /*
4063 * "kill %N" - job kill
4064 * Converting to pgrp / pid kill
4065 */
4066 struct job *jp;
4067 char *dst;
4068 int j, n;
4069
4070 jp = getjob(argv[i], 0);
4071 /*
4072 * In jobs started under job control, we signal
4073 * entire process group by kill -PGRP_ID.
4074 * This happens, f.e., in interactive shell.
4075 *
4076 * Otherwise, we signal each child via
4077 * kill PID1 PID2 PID3.
4078 * Testcases:
4079 * sh -c 'sleep 1|sleep 1 & kill %1'
4080 * sh -c 'true|sleep 2 & sleep 1; kill %1'
4081 * sh -c 'true|sleep 1 & sleep 2; kill %1'
4082 */
4083 n = jp->nprocs; /* can't be 0 (I hope) */
4084 if (jp->jobctl)
4085 n = 1;
4086 dst = alloca(n * sizeof(int)*4);
4087 argv[i] = dst;
4088 for (j = 0; j < n; j++) {
4089 struct procstat *ps = &jp->ps[j];
4090 /* Skip non-running and not-stopped members
4091 * (i.e. dead members) of the job
4092 */
4093 if (ps->ps_status != -1 && !WIFSTOPPED(ps->ps_status))
4094 continue;
4095 /*
4096 * kill_main has matching code to expect
4097 * leading space. Needed to not confuse
4098 * negative pids with "kill -SIGNAL_NO" syntax
4099 */
4100 dst += sprintf(dst, jp->jobctl ? " -%u" : " %u", (int)ps->ps_pid);
4101 }
4102 *dst = '\0';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004103 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00004104 } while (argv[++i]);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004105 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00004106 return kill_main(argc, argv);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004107}
4108
4109static void
Denys Vlasenko285ad152009-12-04 23:02:27 +01004110showpipe(struct job *jp /*, FILE *out*/)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004111{
Denys Vlasenko285ad152009-12-04 23:02:27 +01004112 struct procstat *ps;
4113 struct procstat *psend;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004114
Denys Vlasenko285ad152009-12-04 23:02:27 +01004115 psend = jp->ps + jp->nprocs;
4116 for (ps = jp->ps + 1; ps < psend; ps++)
4117 printf(" | %s", ps->ps_cmd);
Denys Vlasenko9c541002015-10-07 15:44:36 +02004118 newline_and_flush(stdout);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004119 flush_stdout_stderr();
4120}
4121
4122
4123static int
4124restartjob(struct job *jp, int mode)
4125{
4126 struct procstat *ps;
4127 int i;
4128 int status;
4129 pid_t pgid;
4130
4131 INT_OFF;
4132 if (jp->state == JOBDONE)
4133 goto out;
4134 jp->state = JOBRUNNING;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004135 pgid = jp->ps[0].ps_pid;
Denys Vlasenko098b7132017-01-11 19:59:03 +01004136 if (mode == FORK_FG) {
4137 get_tty_state();
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004138 xtcsetpgrp(ttyfd, pgid);
Denys Vlasenko098b7132017-01-11 19:59:03 +01004139 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004140 killpg(pgid, SIGCONT);
4141 ps = jp->ps;
4142 i = jp->nprocs;
4143 do {
Denys Vlasenko285ad152009-12-04 23:02:27 +01004144 if (WIFSTOPPED(ps->ps_status)) {
4145 ps->ps_status = -1;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004146 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00004147 ps++;
4148 } while (--i);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004149 out:
4150 status = (mode == FORK_FG) ? waitforjob(jp) : 0;
4151 INT_ON;
4152 return status;
4153}
4154
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02004155static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00004156fg_bgcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004157{
4158 struct job *jp;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004159 int mode;
4160 int retval;
4161
4162 mode = (**argv == 'f') ? FORK_FG : FORK_BG;
4163 nextopt(nullstr);
4164 argv = argptr;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004165 do {
4166 jp = getjob(*argv, 1);
4167 if (mode == FORK_BG) {
4168 set_curjob(jp, CUR_RUNNING);
Denys Vlasenko285ad152009-12-04 23:02:27 +01004169 printf("[%d] ", jobno(jp));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004170 }
Denys Vlasenko285ad152009-12-04 23:02:27 +01004171 out1str(jp->ps[0].ps_cmd);
4172 showpipe(jp /*, stdout*/);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004173 retval = restartjob(jp, mode);
4174 } while (*argv && *++argv);
4175 return retval;
4176}
4177#endif
4178
4179static int
Denys Vlasenko9c541002015-10-07 15:44:36 +02004180sprint_status48(char *s, int status, int sigonly)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004181{
4182 int col;
4183 int st;
4184
4185 col = 0;
4186 if (!WIFEXITED(status)) {
Johannes Schindelin9d4dc842017-07-14 22:25:58 +02004187#if JOBS
4188 if (WIFSTOPPED(status))
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004189 st = WSTOPSIG(status);
4190 else
Johannes Schindelin9d4dc842017-07-14 22:25:58 +02004191#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004192 st = WTERMSIG(status);
4193 if (sigonly) {
4194 if (st == SIGINT || st == SIGPIPE)
4195 goto out;
Johannes Schindelin9d4dc842017-07-14 22:25:58 +02004196#if JOBS
4197 if (WIFSTOPPED(status))
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004198 goto out;
Johannes Schindelin9d4dc842017-07-14 22:25:58 +02004199#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004200 }
4201 st &= 0x7f;
Denys Vlasenko7c6f2462011-02-14 17:17:10 +01004202//TODO: use bbox's get_signame? strsignal adds ~600 bytes to text+rodata
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004203 col = fmtstr(s, 32, strsignal(st));
4204 if (WCOREDUMP(status)) {
Denys Vlasenko9c541002015-10-07 15:44:36 +02004205 strcpy(s + col, " (core dumped)");
4206 col += sizeof(" (core dumped)")-1;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004207 }
4208 } else if (!sigonly) {
4209 st = WEXITSTATUS(status);
Denys Vlasenko9c541002015-10-07 15:44:36 +02004210 col = fmtstr(s, 16, (st ? "Done(%d)" : "Done"), st);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004211 }
4212 out:
4213 return col;
4214}
4215
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004216static int
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004217wait_block_or_sig(int *status)
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004218{
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004219 int pid;
4220
4221 do {
Denys Vlasenko1ab7c2f2016-11-03 20:17:23 +01004222 sigset_t mask;
4223
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004224 /* Poll all children for changes in their state */
4225 got_sigchld = 0;
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004226 /* if job control is active, accept stopped processes too */
4227 pid = waitpid(-1, status, doing_jobctl ? (WNOHANG|WUNTRACED) : WNOHANG);
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004228 if (pid != 0)
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004229 break; /* Error (e.g. EINTR, ECHILD) or pid */
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004230
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004231 /* Children exist, but none are ready. Sleep until interesting signal */
Denys Vlasenko1ab7c2f2016-11-03 20:17:23 +01004232#if 1
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004233 sigfillset(&mask);
Denys Vlasenkob437df12018-12-08 15:35:24 +01004234 sigprocmask2(SIG_SETMASK, &mask); /* mask is updated */
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004235 while (!got_sigchld && !pending_sig)
4236 sigsuspend(&mask);
4237 sigprocmask(SIG_SETMASK, &mask, NULL);
Denys Vlasenko1ab7c2f2016-11-03 20:17:23 +01004238#else /* unsafe: a signal can set pending_sig after check, but before pause() */
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004239 while (!got_sigchld && !pending_sig)
4240 pause();
4241#endif
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004242
4243 /* If it was SIGCHLD, poll children again */
4244 } while (got_sigchld);
4245
4246 return pid;
4247}
4248
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004249#define DOWAIT_NONBLOCK 0
4250#define DOWAIT_BLOCK 1
4251#define DOWAIT_BLOCK_OR_SIG 2
Ron Yorstone48559e2019-03-31 09:27:09 +01004252#if BASH_WAIT_N
Denys Vlasenko966f0872019-03-27 15:51:42 +01004253# define DOWAIT_JOBSTATUS 0x10 /* OR this to get job's exitstatus instead of pid */
4254#endif
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004255
4256static int
Denys Vlasenkob543bda2016-10-27 20:08:28 +02004257dowait(int block, struct job *job)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004258{
4259 int pid;
4260 int status;
4261 struct job *jp;
Denys Vlasenko966f0872019-03-27 15:51:42 +01004262 struct job *thisjob;
Ron Yorstone48559e2019-03-31 09:27:09 +01004263#if BASH_WAIT_N
Denys Vlasenko966f0872019-03-27 15:51:42 +01004264 bool want_jobexitstatus = (block & DOWAIT_JOBSTATUS);
4265 block = (block & ~DOWAIT_JOBSTATUS);
4266#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004267
Denys Vlasenkob543bda2016-10-27 20:08:28 +02004268 TRACE(("dowait(0x%x) called\n", block));
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +00004269
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004270 /* It's wrong to call waitpid() outside of INT_OFF region:
4271 * signal can arrive just after syscall return and handler can
4272 * longjmp away, losing stop/exit notification processing.
4273 * Thus, for "jobs" builtin, and for waiting for a fg job,
4274 * we call waitpid() (blocking or non-blocking) inside INT_OFF.
4275 *
4276 * However, for "wait" builtin it is wrong to simply call waitpid()
4277 * in INT_OFF region: "wait" needs to wait for any running job
4278 * to change state, but should exit on any trap too.
4279 * In INT_OFF region, a signal just before syscall entry can set
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004280 * pending_sig variables, but we can't check them, and we would
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004281 * either enter a sleeping waitpid() (BUG), or need to busy-loop.
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004282 *
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004283 * Because of this, we run inside INT_OFF, but use a special routine
Denys Vlasenko1ab7c2f2016-11-03 20:17:23 +01004284 * which combines waitpid() and sigsuspend().
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004285 * This is the reason why we need to have a handler for SIGCHLD:
Denys Vlasenko1ab7c2f2016-11-03 20:17:23 +01004286 * SIG_DFL handler does not wake sigsuspend().
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004287 */
4288 INT_OFF;
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004289 if (block == DOWAIT_BLOCK_OR_SIG) {
4290 pid = wait_block_or_sig(&status);
4291 } else {
4292 int wait_flags = 0;
4293 if (block == DOWAIT_NONBLOCK)
4294 wait_flags = WNOHANG;
4295 /* if job control is active, accept stopped processes too */
4296 if (doing_jobctl)
4297 wait_flags |= WUNTRACED;
4298 /* NB: _not_ safe_waitpid, we need to detect EINTR */
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004299 pid = waitpid(-1, &status, wait_flags);
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004300 }
Denis Vlasenkob21f3792009-03-19 23:09:58 +00004301 TRACE(("wait returns pid=%d, status=0x%x, errno=%d(%s)\n",
4302 pid, status, errno, strerror(errno)));
Denys Vlasenko966f0872019-03-27 15:51:42 +01004303 thisjob = NULL;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004304 if (pid <= 0)
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004305 goto out;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004306
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004307 for (jp = curjob; jp; jp = jp->prev_job) {
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004308 int jobstate;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004309 struct procstat *ps;
4310 struct procstat *psend;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004311 if (jp->state == JOBDONE)
4312 continue;
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004313 jobstate = JOBDONE;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004314 ps = jp->ps;
4315 psend = ps + jp->nprocs;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004316 do {
Denys Vlasenko285ad152009-12-04 23:02:27 +01004317 if (ps->ps_pid == pid) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004318 TRACE(("Job %d: changing status of proc %d "
4319 "from 0x%x to 0x%x\n",
Denys Vlasenko285ad152009-12-04 23:02:27 +01004320 jobno(jp), pid, ps->ps_status, status));
4321 ps->ps_status = status;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004322 thisjob = jp;
4323 }
Denys Vlasenko285ad152009-12-04 23:02:27 +01004324 if (ps->ps_status == -1)
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004325 jobstate = JOBRUNNING;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004326#if JOBS
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004327 if (jobstate == JOBRUNNING)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004328 continue;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004329 if (WIFSTOPPED(ps->ps_status)) {
4330 jp->stopstatus = ps->ps_status;
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004331 jobstate = JOBSTOPPED;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004332 }
4333#endif
Denys Vlasenko285ad152009-12-04 23:02:27 +01004334 } while (++ps < psend);
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004335 if (!thisjob)
4336 continue;
4337
4338 /* Found the job where one of its processes changed its state.
4339 * Is there at least one live and running process in this job? */
4340 if (jobstate != JOBRUNNING) {
4341 /* No. All live processes in the job are stopped
4342 * (JOBSTOPPED) or there are no live processes (JOBDONE)
4343 */
4344 thisjob->changed = 1;
4345 if (thisjob->state != jobstate) {
4346 TRACE(("Job %d: changing state from %d to %d\n",
4347 jobno(thisjob), thisjob->state, jobstate));
4348 thisjob->state = jobstate;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004349#if JOBS
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004350 if (jobstate == JOBSTOPPED)
4351 set_curjob(thisjob, CUR_STOPPED);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004352#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004353 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004354 }
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004355 goto out;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004356 }
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004357 /* The process wasn't found in job list */
Johannes Schindelin9d4dc842017-07-14 22:25:58 +02004358#if JOBS
4359 if (!WIFSTOPPED(status))
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004360 jobless--;
Johannes Schindelin9d4dc842017-07-14 22:25:58 +02004361#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004362 out:
4363 INT_ON;
4364
Ron Yorstone48559e2019-03-31 09:27:09 +01004365#if BASH_WAIT_N
Denys Vlasenko966f0872019-03-27 15:51:42 +01004366 if (want_jobexitstatus) {
4367 pid = -1;
4368 if (thisjob && thisjob->state == JOBDONE)
4369 pid = thisjob->ps[thisjob->nprocs - 1].ps_status;
4370 }
4371#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004372 if (thisjob && thisjob == job) {
4373 char s[48 + 1];
4374 int len;
4375
Denys Vlasenko9c541002015-10-07 15:44:36 +02004376 len = sprint_status48(s, status, 1);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004377 if (len) {
4378 s[len] = '\n';
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004379 s[len + 1] = '\0';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004380 out2str(s);
4381 }
4382 }
4383 return pid;
4384}
4385
4386#if JOBS
4387static void
Denys Vlasenko9c541002015-10-07 15:44:36 +02004388showjob(struct job *jp, int mode)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004389{
4390 struct procstat *ps;
4391 struct procstat *psend;
4392 int col;
Denis Vlasenko40ba9982007-07-14 00:48:29 +00004393 int indent_col;
Denys Vlasenko9c541002015-10-07 15:44:36 +02004394 char s[16 + 16 + 48];
4395 FILE *out = (mode & SHOW_STDERR ? stderr : stdout);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004396
4397 ps = jp->ps;
4398
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004399 if (mode & SHOW_ONLY_PGID) { /* jobs -p */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004400 /* just output process (group) id of pipeline */
Denys Vlasenko285ad152009-12-04 23:02:27 +01004401 fprintf(out, "%d\n", ps->ps_pid);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004402 return;
4403 }
4404
4405 col = fmtstr(s, 16, "[%d] ", jobno(jp));
Denis Vlasenko40ba9982007-07-14 00:48:29 +00004406 indent_col = col;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004407
4408 if (jp == curjob)
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004409 s[col - 3] = '+';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004410 else if (curjob && jp == curjob->prev_job)
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004411 s[col - 3] = '-';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004412
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004413 if (mode & SHOW_PIDS)
Denys Vlasenko285ad152009-12-04 23:02:27 +01004414 col += fmtstr(s + col, 16, "%d ", ps->ps_pid);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004415
4416 psend = ps + jp->nprocs;
4417
4418 if (jp->state == JOBRUNNING) {
4419 strcpy(s + col, "Running");
4420 col += sizeof("Running") - 1;
4421 } else {
Denys Vlasenko285ad152009-12-04 23:02:27 +01004422 int status = psend[-1].ps_status;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004423 if (jp->state == JOBSTOPPED)
4424 status = jp->stopstatus;
Denys Vlasenko9c541002015-10-07 15:44:36 +02004425 col += sprint_status48(s + col, status, 0);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004426 }
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004427 /* By now, "[JOBID]* [maybe PID] STATUS" is printed */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004428
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004429 /* This loop either prints "<cmd1> | <cmd2> | <cmd3>" line
4430 * or prints several "PID | <cmdN>" lines,
4431 * depending on SHOW_PIDS bit.
4432 * We do not print status of individual processes
4433 * between PID and <cmdN>. bash does it, but not very well:
4434 * first line shows overall job status, not process status,
4435 * making it impossible to know 1st process status.
4436 */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004437 goto start;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004438 do {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004439 /* for each process */
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004440 s[0] = '\0';
4441 col = 33;
4442 if (mode & SHOW_PIDS)
Denys Vlasenko285ad152009-12-04 23:02:27 +01004443 col = fmtstr(s, 48, "\n%*c%d ", indent_col, ' ', ps->ps_pid) - 1;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004444 start:
Denys Vlasenko285ad152009-12-04 23:02:27 +01004445 fprintf(out, "%s%*c%s%s",
4446 s,
4447 33 - col >= 0 ? 33 - col : 0, ' ',
4448 ps == jp->ps ? "" : "| ",
4449 ps->ps_cmd
4450 );
4451 } while (++ps != psend);
Denys Vlasenko9c541002015-10-07 15:44:36 +02004452 newline_and_flush(out);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004453
4454 jp->changed = 0;
4455
4456 if (jp->state == JOBDONE) {
4457 TRACE(("showjob: freeing job %d\n", jobno(jp)));
4458 freejob(jp);
4459 }
4460}
4461
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004462/*
4463 * Print a list of jobs. If "change" is nonzero, only print jobs whose
4464 * statuses have changed since the last call to showjobs.
4465 */
4466static void
Denys Vlasenko9c541002015-10-07 15:44:36 +02004467showjobs(int mode)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004468{
4469 struct job *jp;
4470
Denys Vlasenko883cea42009-07-11 15:31:59 +02004471 TRACE(("showjobs(0x%x) called\n", mode));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004472
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004473 /* Handle all finished jobs */
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004474 while (dowait(DOWAIT_NONBLOCK, NULL) > 0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004475 continue;
4476
4477 for (jp = curjob; jp; jp = jp->prev_job) {
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004478 if (!(mode & SHOW_CHANGED) || jp->changed) {
Denys Vlasenko9c541002015-10-07 15:44:36 +02004479 showjob(jp, mode);
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004480 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004481 }
4482}
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004483
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02004484static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00004485jobscmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004486{
4487 int mode, m;
4488
4489 mode = 0;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02004490 while ((m = nextopt("lp")) != '\0') {
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004491 if (m == 'l')
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004492 mode |= SHOW_PIDS;
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004493 else
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004494 mode |= SHOW_ONLY_PGID;
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004495 }
4496
4497 argv = argptr;
4498 if (*argv) {
4499 do
Denys Vlasenko9c541002015-10-07 15:44:36 +02004500 showjob(getjob(*argv, 0), mode);
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004501 while (*++argv);
Denys Vlasenko285ad152009-12-04 23:02:27 +01004502 } else {
Denys Vlasenko9c541002015-10-07 15:44:36 +02004503 showjobs(mode);
Denys Vlasenko285ad152009-12-04 23:02:27 +01004504 }
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004505
4506 return 0;
4507}
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004508#endif /* JOBS */
4509
Michael Abbott359da5e2009-12-04 23:03:29 +01004510/* Called only on finished or stopped jobs (no members are running) */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004511static int
4512getstatus(struct job *job)
4513{
4514 int status;
4515 int retval;
Michael Abbott359da5e2009-12-04 23:03:29 +01004516 struct procstat *ps;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004517
Michael Abbott359da5e2009-12-04 23:03:29 +01004518 /* Fetch last member's status */
4519 ps = job->ps + job->nprocs - 1;
4520 status = ps->ps_status;
4521 if (pipefail) {
4522 /* "set -o pipefail" mode: use last _nonzero_ status */
4523 while (status == 0 && --ps >= job->ps)
4524 status = ps->ps_status;
4525 }
4526
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004527 retval = WEXITSTATUS(status);
4528 if (!WIFEXITED(status)) {
4529#if JOBS
4530 retval = WSTOPSIG(status);
4531 if (!WIFSTOPPED(status))
4532#endif
4533 {
4534 /* XXX: limits number of signals */
4535 retval = WTERMSIG(status);
4536#if JOBS
4537 if (retval == SIGINT)
4538 job->sigint = 1;
4539#endif
4540 }
4541 retval += 128;
4542 }
Denys Vlasenko883cea42009-07-11 15:31:59 +02004543 TRACE(("getstatus: job %d, nproc %d, status 0x%x, retval 0x%x\n",
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004544 jobno(job), job->nprocs, status, retval));
4545 return retval;
4546}
4547
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02004548static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00004549waitcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004550{
4551 struct job *job;
4552 int retval;
4553 struct job *jp;
Ron Yorstone48559e2019-03-31 09:27:09 +01004554#if BASH_WAIT_N
Denys Vlasenko966f0872019-03-27 15:51:42 +01004555 int status;
4556 char one = nextopt("n");
4557#else
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004558 nextopt(nullstr);
Denys Vlasenko966f0872019-03-27 15:51:42 +01004559#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004560 retval = 0;
4561
4562 argv = argptr;
Denys Vlasenko966f0872019-03-27 15:51:42 +01004563 if (!argv[0]) {
4564 /* wait for all jobs / one job if -n */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004565 for (;;) {
4566 jp = curjob;
Ron Yorstone48559e2019-03-31 09:27:09 +01004567#if BASH_WAIT_N
Denys Vlasenko966f0872019-03-27 15:51:42 +01004568 if (one && !jp)
4569 /* exitcode of "wait -n" with nothing to wait for is 127, not 0 */
4570 retval = 127;
4571#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004572 while (1) {
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004573 if (!jp) /* no running procs */
4574 goto ret;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004575 if (jp->state == JOBRUNNING)
4576 break;
4577 jp->waited = 1;
4578 jp = jp->prev_job;
4579 }
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004580 /* man bash:
4581 * "When bash is waiting for an asynchronous command via
4582 * the wait builtin, the reception of a signal for which a trap
4583 * has been set will cause the wait builtin to return immediately
4584 * with an exit status greater than 128, immediately after which
4585 * the trap is executed."
Denys Vlasenko69188112016-10-27 20:18:18 +02004586 */
Ron Yorstone48559e2019-03-31 09:27:09 +01004587#if BASH_WAIT_N
Denys Vlasenko966f0872019-03-27 15:51:42 +01004588 status = dowait(DOWAIT_BLOCK_OR_SIG | DOWAIT_JOBSTATUS, NULL);
4589#else
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004590 dowait(DOWAIT_BLOCK_OR_SIG, NULL);
Denys Vlasenko966f0872019-03-27 15:51:42 +01004591#endif
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02004592 /* if child sends us a signal *and immediately exits*,
4593 * dowait() returns pid > 0. Check this case,
4594 * not "if (dowait() < 0)"!
4595 */
Denys Vlasenko7c1ed9f2010-05-17 04:42:40 +02004596 if (pending_sig)
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02004597 goto sigout;
Ron Yorstone48559e2019-03-31 09:27:09 +01004598#if BASH_WAIT_N
Denys Vlasenko966f0872019-03-27 15:51:42 +01004599 if (one) {
4600 /* wait -n waits for one _job_, not one _process_.
4601 * date; sleep 3 & sleep 2 | sleep 1 & wait -n; date
4602 * should wait for 2 seconds. Not 1 or 3.
4603 */
4604 if (status != -1 && !WIFSTOPPED(status)) {
4605 retval = WEXITSTATUS(status);
4606 if (WIFSIGNALED(status))
4607 retval = WTERMSIG(status) + 128;
4608 goto ret;
4609 }
4610 }
4611#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004612 }
4613 }
4614
4615 retval = 127;
4616 do {
4617 if (**argv != '%') {
4618 pid_t pid = number(*argv);
4619 job = curjob;
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004620 while (1) {
4621 if (!job)
4622 goto repeat;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004623 if (job->ps[job->nprocs - 1].ps_pid == pid)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004624 break;
4625 job = job->prev_job;
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004626 }
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004627 } else {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004628 job = getjob(*argv, 0);
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004629 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004630 /* loop until process terminated or stopped */
Denys Vlasenko69188112016-10-27 20:18:18 +02004631 while (job->state == JOBRUNNING) {
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004632 dowait(DOWAIT_BLOCK_OR_SIG, NULL);
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02004633 if (pending_sig)
4634 goto sigout;
Denys Vlasenko69188112016-10-27 20:18:18 +02004635 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004636 job->waited = 1;
4637 retval = getstatus(job);
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004638 repeat: ;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004639 } while (*++argv);
4640
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004641 ret:
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004642 return retval;
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02004643 sigout:
4644 retval = 128 + pending_sig;
4645 return retval;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004646}
4647
4648static struct job *
4649growjobtab(void)
4650{
4651 size_t len;
4652 ptrdiff_t offset;
4653 struct job *jp, *jq;
4654
4655 len = njobs * sizeof(*jp);
4656 jq = jobtab;
4657 jp = ckrealloc(jq, len + 4 * sizeof(*jp));
4658
4659 offset = (char *)jp - (char *)jq;
4660 if (offset) {
4661 /* Relocate pointers */
4662 size_t l = len;
4663
4664 jq = (struct job *)((char *)jq + l);
4665 while (l) {
4666 l -= sizeof(*jp);
4667 jq--;
4668#define joff(p) ((struct job *)((char *)(p) + l))
4669#define jmove(p) (p) = (void *)((char *)(p) + offset)
4670 if (joff(jp)->ps == &jq->ps0)
4671 jmove(joff(jp)->ps);
4672 if (joff(jp)->prev_job)
4673 jmove(joff(jp)->prev_job);
4674 }
4675 if (curjob)
4676 jmove(curjob);
4677#undef joff
4678#undef jmove
4679 }
4680
4681 njobs += 4;
4682 jobtab = jp;
4683 jp = (struct job *)((char *)jp + len);
4684 jq = jp + 3;
4685 do {
4686 jq->used = 0;
4687 } while (--jq >= jp);
4688 return jp;
4689}
4690
4691/*
4692 * Return a new job structure.
4693 * Called with interrupts off.
4694 */
4695static struct job *
Denis Vlasenko68404f12008-03-17 09:00:54 +00004696makejob(/*union node *node,*/ int nprocs)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004697{
4698 int i;
4699 struct job *jp;
4700
4701 for (i = njobs, jp = jobtab; ; jp++) {
4702 if (--i < 0) {
4703 jp = growjobtab();
4704 break;
4705 }
4706 if (jp->used == 0)
4707 break;
4708 if (jp->state != JOBDONE || !jp->waited)
4709 continue;
4710#if JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +00004711 if (doing_jobctl)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004712 continue;
4713#endif
4714 freejob(jp);
4715 break;
4716 }
4717 memset(jp, 0, sizeof(*jp));
4718#if JOBS
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004719 /* jp->jobctl is a bitfield.
Denys Vlasenko098b7132017-01-11 19:59:03 +01004720 * "jp->jobctl |= doing_jobctl" likely to give awful code */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00004721 if (doing_jobctl)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004722 jp->jobctl = 1;
4723#endif
4724 jp->prev_job = curjob;
4725 curjob = jp;
4726 jp->used = 1;
4727 jp->ps = &jp->ps0;
4728 if (nprocs > 1) {
4729 jp->ps = ckmalloc(nprocs * sizeof(struct procstat));
4730 }
Denis Vlasenko68404f12008-03-17 09:00:54 +00004731 TRACE(("makejob(%d) returns %%%d\n", nprocs,
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004732 jobno(jp)));
4733 return jp;
4734}
4735
4736#if JOBS
4737/*
4738 * Return a string identifying a command (to be printed by the
4739 * jobs command).
4740 */
4741static char *cmdnextc;
4742
4743static void
4744cmdputs(const char *s)
4745{
Denis Vlasenko92e13c22008-03-25 01:17:40 +00004746 static const char vstype[VSTYPE + 1][3] = {
4747 "", "}", "-", "+", "?", "=",
4748 "%", "%%", "#", "##"
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01004749 IF_BASH_SUBSTR(, ":")
4750 IF_BASH_PATTERN_SUBST(, "/", "//")
Denis Vlasenko92e13c22008-03-25 01:17:40 +00004751 };
4752
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004753 const char *p, *str;
Denys Vlasenko46a14772009-12-10 21:27:13 +01004754 char cc[2];
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004755 char *nextc;
Denys Vlasenkocd716832009-11-28 22:14:02 +01004756 unsigned char c;
4757 unsigned char subtype = 0;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004758 int quoted = 0;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004759
Denys Vlasenko46a14772009-12-10 21:27:13 +01004760 cc[1] = '\0';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004761 nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
4762 p = s;
Denys Vlasenko46a14772009-12-10 21:27:13 +01004763 while ((c = *p++) != '\0') {
Denis Vlasenkoef527f52008-06-23 01:52:30 +00004764 str = NULL;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004765 switch (c) {
4766 case CTLESC:
4767 c = *p++;
4768 break;
4769 case CTLVAR:
4770 subtype = *p++;
4771 if ((subtype & VSTYPE) == VSLENGTH)
4772 str = "${#";
4773 else
4774 str = "${";
Ron Yorston549deab2015-05-18 09:57:51 +02004775 goto dostr;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004776 case CTLENDVAR:
4777 str = "\"}" + !(quoted & 1);
4778 quoted >>= 1;
4779 subtype = 0;
4780 goto dostr;
4781 case CTLBACKQ:
4782 str = "$(...)";
4783 goto dostr;
Denys Vlasenko0b883582016-12-23 16:49:07 +01004784#if ENABLE_FEATURE_SH_MATH
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004785 case CTLARI:
4786 str = "$((";
4787 goto dostr;
4788 case CTLENDARI:
4789 str = "))";
4790 goto dostr;
4791#endif
4792 case CTLQUOTEMARK:
4793 quoted ^= 1;
4794 c = '"';
4795 break;
4796 case '=':
4797 if (subtype == 0)
4798 break;
4799 if ((subtype & VSTYPE) != VSNORMAL)
4800 quoted <<= 1;
4801 str = vstype[subtype & VSTYPE];
4802 if (subtype & VSNUL)
4803 c = ':';
4804 else
4805 goto checkstr;
4806 break;
4807 case '\'':
4808 case '\\':
4809 case '"':
4810 case '$':
4811 /* These can only happen inside quotes */
4812 cc[0] = c;
4813 str = cc;
Denys Vlasenkod0fff912017-07-31 14:32:18 +02004814//FIXME:
4815// $ true $$ &
4816// $ <cr>
4817// [1]+ Done true ${\$} <<=== BUG: ${\$} is not a valid way to write $$ (${$} would be ok)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004818 c = '\\';
4819 break;
4820 default:
4821 break;
4822 }
4823 USTPUTC(c, nextc);
4824 checkstr:
4825 if (!str)
4826 continue;
4827 dostr:
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02004828 while ((c = *str++) != '\0') {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004829 USTPUTC(c, nextc);
4830 }
Denys Vlasenko46a14772009-12-10 21:27:13 +01004831 } /* while *p++ not NUL */
4832
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004833 if (quoted & 1) {
4834 USTPUTC('"', nextc);
4835 }
4836 *nextc = 0;
4837 cmdnextc = nextc;
4838}
4839
4840/* cmdtxt() and cmdlist() call each other */
4841static void cmdtxt(union node *n);
4842
4843static void
4844cmdlist(union node *np, int sep)
4845{
4846 for (; np; np = np->narg.next) {
4847 if (!sep)
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00004848 cmdputs(" ");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004849 cmdtxt(np);
4850 if (sep && np->narg.next)
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00004851 cmdputs(" ");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004852 }
4853}
4854
4855static void
4856cmdtxt(union node *n)
4857{
4858 union node *np;
4859 struct nodelist *lp;
4860 const char *p;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004861
4862 if (!n)
4863 return;
4864 switch (n->type) {
4865 default:
4866#if DEBUG
4867 abort();
4868#endif
4869 case NPIPE:
4870 lp = n->npipe.cmdlist;
4871 for (;;) {
4872 cmdtxt(lp->n);
4873 lp = lp->next;
4874 if (!lp)
4875 break;
4876 cmdputs(" | ");
4877 }
4878 break;
4879 case NSEMI:
4880 p = "; ";
4881 goto binop;
4882 case NAND:
4883 p = " && ";
4884 goto binop;
4885 case NOR:
4886 p = " || ";
4887 binop:
4888 cmdtxt(n->nbinary.ch1);
4889 cmdputs(p);
4890 n = n->nbinary.ch2;
4891 goto donode;
4892 case NREDIR:
4893 case NBACKGND:
4894 n = n->nredir.n;
4895 goto donode;
4896 case NNOT:
4897 cmdputs("!");
4898 n = n->nnot.com;
4899 donode:
4900 cmdtxt(n);
4901 break;
4902 case NIF:
4903 cmdputs("if ");
4904 cmdtxt(n->nif.test);
4905 cmdputs("; then ");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004906 if (n->nif.elsepart) {
Denys Vlasenko7cee00e2009-07-24 01:08:03 +02004907 cmdtxt(n->nif.ifpart);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004908 cmdputs("; else ");
4909 n = n->nif.elsepart;
Denys Vlasenko7cee00e2009-07-24 01:08:03 +02004910 } else {
4911 n = n->nif.ifpart;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004912 }
4913 p = "; fi";
4914 goto dotail;
4915 case NSUBSHELL:
4916 cmdputs("(");
4917 n = n->nredir.n;
4918 p = ")";
4919 goto dotail;
4920 case NWHILE:
4921 p = "while ";
4922 goto until;
4923 case NUNTIL:
4924 p = "until ";
4925 until:
4926 cmdputs(p);
4927 cmdtxt(n->nbinary.ch1);
4928 n = n->nbinary.ch2;
4929 p = "; done";
4930 dodo:
4931 cmdputs("; do ");
4932 dotail:
4933 cmdtxt(n);
4934 goto dotail2;
4935 case NFOR:
4936 cmdputs("for ");
4937 cmdputs(n->nfor.var);
4938 cmdputs(" in ");
4939 cmdlist(n->nfor.args, 1);
4940 n = n->nfor.body;
4941 p = "; done";
4942 goto dodo;
4943 case NDEFUN:
Denys Vlasenko675d24a2018-01-27 22:02:05 +01004944 cmdputs(n->ndefun.text);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004945 p = "() { ... }";
4946 goto dotail2;
4947 case NCMD:
4948 cmdlist(n->ncmd.args, 1);
4949 cmdlist(n->ncmd.redirect, 0);
4950 break;
4951 case NARG:
4952 p = n->narg.text;
4953 dotail2:
4954 cmdputs(p);
4955 break;
4956 case NHERE:
4957 case NXHERE:
4958 p = "<<...";
4959 goto dotail2;
4960 case NCASE:
4961 cmdputs("case ");
4962 cmdputs(n->ncase.expr->narg.text);
4963 cmdputs(" in ");
4964 for (np = n->ncase.cases; np; np = np->nclist.next) {
4965 cmdtxt(np->nclist.pattern);
4966 cmdputs(") ");
4967 cmdtxt(np->nclist.body);
4968 cmdputs(";; ");
4969 }
4970 p = "esac";
4971 goto dotail2;
4972 case NTO:
4973 p = ">";
4974 goto redir;
4975 case NCLOBBER:
4976 p = ">|";
4977 goto redir;
4978 case NAPPEND:
4979 p = ">>";
4980 goto redir;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01004981#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00004982 case NTO2:
4983#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004984 case NTOFD:
4985 p = ">&";
4986 goto redir;
4987 case NFROM:
4988 p = "<";
4989 goto redir;
4990 case NFROMFD:
4991 p = "<&";
4992 goto redir;
4993 case NFROMTO:
4994 p = "<>";
4995 redir:
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00004996 cmdputs(utoa(n->nfile.fd));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004997 cmdputs(p);
4998 if (n->type == NTOFD || n->type == NFROMFD) {
Denys Vlasenkod0fff912017-07-31 14:32:18 +02004999 if (n->ndup.dupfd >= 0)
5000 cmdputs(utoa(n->ndup.dupfd));
5001 else
5002 cmdputs("-");
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005003 break;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005004 }
5005 n = n->nfile.fname;
5006 goto donode;
5007 }
5008}
5009
5010static char *
5011commandtext(union node *n)
5012{
5013 char *name;
5014
5015 STARTSTACKSTR(cmdnextc);
5016 cmdtxt(n);
5017 name = stackblock();
Denys Vlasenko6a94cee2016-10-25 17:40:25 +02005018 TRACE(("commandtext: name %p, end %p\n", name, cmdnextc));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005019 return ckstrdup(name);
5020}
5021#endif /* JOBS */
5022
5023/*
5024 * Fork off a subshell. If we are doing job control, give the subshell its
5025 * own process group. Jp is a job structure that the job is to be added to.
5026 * N is the command that will be evaluated by the child. Both jp and n may
5027 * be NULL. The mode parameter can be one of the following:
5028 * FORK_FG - Fork off a foreground process.
5029 * FORK_BG - Fork off a background process.
5030 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
5031 * process group even if job control is on.
5032 *
5033 * When job control is turned off, background processes have their standard
5034 * input redirected to /dev/null (except for the second and later processes
5035 * in a pipeline).
5036 *
5037 * Called with interrupts off.
5038 */
5039/*
5040 * Clear traps on a fork.
5041 */
5042static void
5043clear_traps(void)
5044{
5045 char **tp;
5046
Denys Vlasenkob4f51d32016-10-27 12:55:09 +02005047 INT_OFF;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005048 for (tp = trap; tp < &trap[NSIG]; tp++) {
Denis Vlasenko991a1da2008-02-10 19:02:53 +00005049 if (*tp && **tp) { /* trap not NULL or "" (SIG_IGN) */
Denys Vlasenkoe305c282009-09-25 02:12:27 +02005050 if (trap_ptr == trap)
5051 free(*tp);
5052 /* else: it "belongs" to trap_ptr vector, don't free */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005053 *tp = NULL;
Denys Vlasenko0800e3a2009-09-24 03:09:26 +02005054 if ((tp - trap) != 0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005055 setsignal(tp - trap);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005056 }
5057 }
Alexander Shishkinccb97712010-07-25 13:07:39 +02005058 may_have_traps = 0;
Denys Vlasenkob4f51d32016-10-27 12:55:09 +02005059 INT_ON;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005060}
Denis Vlasenkobdc406d2007-07-15 01:13:25 +00005061
5062/* Lives far away from here, needed for forkchild */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005063static void closescript(void);
Denis Vlasenko41770222007-10-07 18:02:52 +00005064
Denis Vlasenkobdc406d2007-07-15 01:13:25 +00005065/* Called after fork(), in child */
Denys Vlasenko70392332016-10-27 02:31:55 +02005066/* jp and n are NULL when called by openhere() for heredoc support */
Denys Vlasenko21d87d42009-09-25 00:06:51 +02005067static NOINLINE void
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02005068forkchild(struct job *jp, union node *n, int mode)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005069{
5070 int oldlvl;
5071
5072 TRACE(("Child shell %d\n", getpid()));
5073 oldlvl = shlvl;
5074 shlvl++;
5075
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005076 /* man bash: "Non-builtin commands run by bash have signal handlers
5077 * set to the values inherited by the shell from its parent".
5078 * Do we do it correctly? */
5079
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005080 closescript();
Denys Vlasenko844f9902009-09-23 03:25:52 +02005081
5082 if (mode == FORK_NOJOB /* is it `xxx` ? */
5083 && n && n->type == NCMD /* is it single cmd? */
5084 /* && n->ncmd.args->type == NARG - always true? */
Denys Vlasenko74269202010-02-21 01:26:42 +01005085 && n->ncmd.args && strcmp(n->ncmd.args->narg.text, "trap") == 0
Denys Vlasenko844f9902009-09-23 03:25:52 +02005086 && n->ncmd.args->narg.next == NULL /* "trap" with no arguments */
5087 /* && n->ncmd.args->narg.backquote == NULL - do we need to check this? */
5088 ) {
5089 TRACE(("Trap hack\n"));
5090 /* Awful hack for `trap` or $(trap).
5091 *
5092 * http://www.opengroup.org/onlinepubs/009695399/utilities/trap.html
5093 * contains an example where "trap" is executed in a subshell:
5094 *
5095 * save_traps=$(trap)
5096 * ...
5097 * eval "$save_traps"
5098 *
5099 * Standard does not say that "trap" in subshell shall print
5100 * parent shell's traps. It only says that its output
5101 * must have suitable form, but then, in the above example
5102 * (which is not supposed to be normative), it implies that.
5103 *
5104 * bash (and probably other shell) does implement it
5105 * (traps are reset to defaults, but "trap" still shows them),
5106 * but as a result, "trap" logic is hopelessly messed up:
5107 *
5108 * # trap
5109 * trap -- 'echo Ho' SIGWINCH <--- we have a handler
5110 * # (trap) <--- trap is in subshell - no output (correct, traps are reset)
5111 * # true | trap <--- trap is in subshell - no output (ditto)
5112 * # echo `true | trap` <--- in subshell - output (but traps are reset!)
5113 * trap -- 'echo Ho' SIGWINCH
5114 * # echo `(trap)` <--- in subshell in subshell - output
5115 * trap -- 'echo Ho' SIGWINCH
5116 * # echo `true | (trap)` <--- in subshell in subshell in subshell - output!
5117 * trap -- 'echo Ho' SIGWINCH
5118 *
5119 * The rules when to forget and when to not forget traps
5120 * get really complex and nonsensical.
5121 *
5122 * Our solution: ONLY bare $(trap) or `trap` is special.
5123 */
Denys Vlasenko8f88d852009-09-25 12:12:53 +02005124 /* Save trap handler strings for trap builtin to print */
Ron Yorstond840c5d2015-07-19 23:05:20 +02005125 trap_ptr = xmemdup(trap, sizeof(trap));
Denys Vlasenko8f88d852009-09-25 12:12:53 +02005126 /* Fall through into clearing traps */
Denys Vlasenko844f9902009-09-23 03:25:52 +02005127 }
Denys Vlasenkoe305c282009-09-25 02:12:27 +02005128 clear_traps();
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005129#if JOBS
5130 /* do job control only in root shell */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00005131 doing_jobctl = 0;
Denys Vlasenkob12553f2011-02-21 03:22:20 +01005132 if (mode != FORK_NOJOB && jp->jobctl && oldlvl == 0) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005133 pid_t pgrp;
5134
5135 if (jp->nprocs == 0)
5136 pgrp = getpid();
5137 else
Denys Vlasenko285ad152009-12-04 23:02:27 +01005138 pgrp = jp->ps[0].ps_pid;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005139 /* this can fail because we are doing it in the parent also */
5140 setpgid(0, pgrp);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005141 if (mode == FORK_FG)
5142 xtcsetpgrp(ttyfd, pgrp);
5143 setsignal(SIGTSTP);
5144 setsignal(SIGTTOU);
5145 } else
5146#endif
5147 if (mode == FORK_BG) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005148 /* man bash: "When job control is not in effect,
5149 * asynchronous commands ignore SIGINT and SIGQUIT" */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005150 ignoresig(SIGINT);
5151 ignoresig(SIGQUIT);
5152 if (jp->nprocs == 0) {
5153 close(0);
5154 if (open(bb_dev_null, O_RDONLY) != 0)
Denys Vlasenko12ffefb2017-08-23 14:52:56 +02005155 ash_msg_and_raise_perror("can't open '%s'", bb_dev_null);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005156 }
5157 }
Denys Vlasenkob12553f2011-02-21 03:22:20 +01005158 if (oldlvl == 0) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005159 if (iflag) { /* why if iflag only? */
5160 setsignal(SIGINT);
5161 setsignal(SIGTERM);
5162 }
5163 /* man bash:
5164 * "In all cases, bash ignores SIGQUIT. Non-builtin
5165 * commands run by bash have signal handlers
5166 * set to the values inherited by the shell
5167 * from its parent".
5168 * Take care of the second rule: */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005169 setsignal(SIGQUIT);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005170 }
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02005171#if JOBS
Denys Vlasenko844f9902009-09-23 03:25:52 +02005172 if (n && n->type == NCMD
Denys Vlasenko74269202010-02-21 01:26:42 +01005173 && n->ncmd.args && strcmp(n->ncmd.args->narg.text, "jobs") == 0
Denys Vlasenko844f9902009-09-23 03:25:52 +02005174 ) {
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02005175 TRACE(("Job hack\n"));
Denys Vlasenko844f9902009-09-23 03:25:52 +02005176 /* "jobs": we do not want to clear job list for it,
5177 * instead we remove only _its_ own_ job from job list.
5178 * This makes "jobs .... | cat" more useful.
5179 */
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02005180 freejob(curjob);
5181 return;
5182 }
5183#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005184 for (jp = curjob; jp; jp = jp->prev_job)
5185 freejob(jp);
5186 jobless = 0;
5187}
5188
Denis Vlasenkobdc406d2007-07-15 01:13:25 +00005189/* Called after fork(), in parent */
Denis Vlasenko85c24712008-03-17 09:04:04 +00005190#if !JOBS
5191#define forkparent(jp, n, mode, pid) forkparent(jp, mode, pid)
5192#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005193static void
5194forkparent(struct job *jp, union node *n, int mode, pid_t pid)
5195{
5196 TRACE(("In parent shell: child = %d\n", pid));
5197 if (!jp) {
Denys Vlasenko70392332016-10-27 02:31:55 +02005198 /* jp is NULL when called by openhere() for heredoc support */
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00005199 while (jobless && dowait(DOWAIT_NONBLOCK, NULL) > 0)
5200 continue;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005201 jobless++;
5202 return;
5203 }
5204#if JOBS
5205 if (mode != FORK_NOJOB && jp->jobctl) {
5206 int pgrp;
5207
5208 if (jp->nprocs == 0)
5209 pgrp = pid;
5210 else
Denys Vlasenko285ad152009-12-04 23:02:27 +01005211 pgrp = jp->ps[0].ps_pid;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005212 /* This can fail because we are doing it in the child also */
5213 setpgid(pid, pgrp);
5214 }
5215#endif
5216 if (mode == FORK_BG) {
5217 backgndpid = pid; /* set $! */
5218 set_curjob(jp, CUR_RUNNING);
5219 }
5220 if (jp) {
5221 struct procstat *ps = &jp->ps[jp->nprocs++];
Denys Vlasenko285ad152009-12-04 23:02:27 +01005222 ps->ps_pid = pid;
5223 ps->ps_status = -1;
5224 ps->ps_cmd = nullstr;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005225#if JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +00005226 if (doing_jobctl && n)
Denys Vlasenko285ad152009-12-04 23:02:27 +01005227 ps->ps_cmd = commandtext(n);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005228#endif
5229 }
5230}
5231
Denys Vlasenko70392332016-10-27 02:31:55 +02005232/* jp and n are NULL when called by openhere() for heredoc support */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005233static int
5234forkshell(struct job *jp, union node *n, int mode)
5235{
5236 int pid;
5237
5238 TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
5239 pid = fork();
5240 if (pid < 0) {
5241 TRACE(("Fork failed, errno=%d", errno));
5242 if (jp)
5243 freejob(jp);
Denys Vlasenko12ffefb2017-08-23 14:52:56 +02005244 ash_msg_and_raise_perror("can't fork");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005245 }
Denys Vlasenko76ace252009-10-12 15:25:01 +02005246 if (pid == 0) {
5247 CLEAR_RANDOM_T(&random_gen); /* or else $RANDOM repeats in child */
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02005248 forkchild(jp, n, mode);
Denys Vlasenko76ace252009-10-12 15:25:01 +02005249 } else {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005250 forkparent(jp, n, mode, pid);
Denys Vlasenko76ace252009-10-12 15:25:01 +02005251 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005252 return pid;
5253}
5254
5255/*
5256 * Wait for job to finish.
5257 *
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005258 * Under job control we have the problem that while a child process
5259 * is running interrupts generated by the user are sent to the child
5260 * but not to the shell. This means that an infinite loop started by
5261 * an interactive user may be hard to kill. With job control turned off,
5262 * an interactive user may place an interactive program inside a loop.
5263 * If the interactive program catches interrupts, the user doesn't want
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005264 * these interrupts to also abort the loop. The approach we take here
5265 * is to have the shell ignore interrupt signals while waiting for a
5266 * foreground process to terminate, and then send itself an interrupt
5267 * signal if the child process was terminated by an interrupt signal.
5268 * Unfortunately, some programs want to do a bit of cleanup and then
5269 * exit on interrupt; unless these processes terminate themselves by
5270 * sending a signal to themselves (instead of calling exit) they will
5271 * confuse this approach.
5272 *
5273 * Called with interrupts off.
5274 */
5275static int
5276waitforjob(struct job *jp)
5277{
5278 int st;
5279
5280 TRACE(("waitforjob(%%%d) called\n", jobno(jp)));
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005281
5282 INT_OFF;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005283 while (jp->state == JOBRUNNING) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005284 /* In non-interactive shells, we _can_ get
5285 * a keyboard signal here and be EINTRed,
5286 * but we just loop back, waiting for command to complete.
5287 *
5288 * man bash:
5289 * "If bash is waiting for a command to complete and receives
5290 * a signal for which a trap has been set, the trap
5291 * will not be executed until the command completes."
5292 *
5293 * Reality is that even if trap is not set, bash
5294 * will not act on the signal until command completes.
5295 * Try this. sleep5intoff.c:
5296 * #include <signal.h>
5297 * #include <unistd.h>
5298 * int main() {
5299 * sigset_t set;
5300 * sigemptyset(&set);
5301 * sigaddset(&set, SIGINT);
5302 * sigaddset(&set, SIGQUIT);
5303 * sigprocmask(SIG_BLOCK, &set, NULL);
5304 * sleep(5);
5305 * return 0;
5306 * }
5307 * $ bash -c './sleep5intoff; echo hi'
5308 * ^C^C^C^C <--- pressing ^C once a second
5309 * $ _
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005310 * $ bash -c './sleep5intoff; echo hi'
5311 * ^\^\^\^\hi <--- pressing ^\ (SIGQUIT)
5312 * $ _
5313 */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005314 dowait(DOWAIT_BLOCK, jp);
5315 }
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005316 INT_ON;
5317
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005318 st = getstatus(jp);
5319#if JOBS
5320 if (jp->jobctl) {
5321 xtcsetpgrp(ttyfd, rootpid);
Denys Vlasenko098b7132017-01-11 19:59:03 +01005322 restore_tty_if_stopped_or_signaled(jp);
5323
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005324 /*
5325 * This is truly gross.
5326 * If we're doing job control, then we did a TIOCSPGRP which
5327 * caused us (the shell) to no longer be in the controlling
5328 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
5329 * intuit from the subprocess exit status whether a SIGINT
5330 * occurred, and if so interrupt ourselves. Yuck. - mycroft
5331 */
Denis Vlasenko991a1da2008-02-10 19:02:53 +00005332 if (jp->sigint) /* TODO: do the same with all signals */
5333 raise(SIGINT); /* ... by raise(jp->sig) instead? */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005334 }
5335 if (jp->state == JOBDONE)
5336#endif
5337 freejob(jp);
5338 return st;
5339}
5340
5341/*
5342 * return 1 if there are stopped jobs, otherwise 0
5343 */
5344static int
5345stoppedjobs(void)
5346{
5347 struct job *jp;
5348 int retval;
5349
5350 retval = 0;
5351 if (job_warning)
5352 goto out;
5353 jp = curjob;
5354 if (jp && jp->state == JOBSTOPPED) {
5355 out2str("You have stopped jobs.\n");
5356 job_warning = 2;
5357 retval++;
5358 }
5359 out:
5360 return retval;
5361}
5362
5363
Denys Vlasenko70392332016-10-27 02:31:55 +02005364/*
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005365 * Code for dealing with input/output redirection.
5366 */
5367
Denys Vlasenko8d0e0cd2011-01-25 23:21:46 +01005368#undef EMPTY
5369#undef CLOSED
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005370#define EMPTY -2 /* marks an unused slot in redirtab */
Denys Vlasenko035486c2017-07-31 04:09:19 +02005371#define CLOSED -1 /* marks a slot of previously-closed fd */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005372
5373/*
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005374 * Handle here documents. Normally we fork off a process to write the
5375 * data to a pipe. If the document is short, we can stuff the data in
5376 * the pipe without forking.
5377 */
5378/* openhere needs this forward reference */
5379static void expandhere(union node *arg, int fd);
5380static int
5381openhere(union node *redir)
5382{
5383 int pip[2];
5384 size_t len = 0;
5385
5386 if (pipe(pip) < 0)
Denys Vlasenko12ffefb2017-08-23 14:52:56 +02005387 ash_msg_and_raise_perror("can't create pipe");
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005388 if (redir->type == NHERE) {
5389 len = strlen(redir->nhere.doc->narg.text);
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005390 if (len <= PIPE_BUF) {
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005391 full_write(pip[1], redir->nhere.doc->narg.text, len);
5392 goto out;
5393 }
5394 }
5395 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
Denis Vlasenko0b769642008-07-24 07:54:57 +00005396 /* child */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005397 close(pip[0]);
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005398 ignoresig(SIGINT); //signal(SIGINT, SIG_IGN);
5399 ignoresig(SIGQUIT); //signal(SIGQUIT, SIG_IGN);
5400 ignoresig(SIGHUP); //signal(SIGHUP, SIG_IGN);
5401 ignoresig(SIGTSTP); //signal(SIGTSTP, SIG_IGN);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005402 signal(SIGPIPE, SIG_DFL);
5403 if (redir->type == NHERE)
5404 full_write(pip[1], redir->nhere.doc->narg.text, len);
Denis Vlasenko0b769642008-07-24 07:54:57 +00005405 else /* NXHERE */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005406 expandhere(redir->nhere.doc, pip[1]);
Bernhard Reutner-Fischer636a1f82008-05-19 09:29:47 +00005407 _exit(EXIT_SUCCESS);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005408 }
5409 out:
5410 close(pip[1]);
5411 return pip[0];
5412}
5413
5414static int
5415openredirect(union node *redir)
5416{
Denys Vlasenkof1a5cb02017-07-25 17:47:48 +02005417 struct stat sb;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005418 char *fname;
5419 int f;
5420
5421 switch (redir->nfile.type) {
Denys Vlasenko557482c2016-09-25 21:24:04 +02005422/* Can't happen, our single caller does this itself */
5423// case NTOFD:
5424// case NFROMFD:
5425// return -1;
5426 case NHERE:
5427 case NXHERE:
5428 return openhere(redir);
5429 }
5430
5431 /* For N[X]HERE, reading redir->nfile.expfname would touch beyond
5432 * allocated space. Do it only when we know it is safe.
5433 */
5434 fname = redir->nfile.expfname;
5435
5436 switch (redir->nfile.type) {
5437 default:
5438#if DEBUG
5439 abort();
5440#endif
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005441 case NFROM:
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005442 f = open(fname, O_RDONLY);
5443 if (f < 0)
5444 goto eopen;
5445 break;
5446 case NFROMTO:
Andreas Bühmannda75f442010-06-24 04:32:37 +02005447 f = open(fname, O_RDWR|O_CREAT, 0666);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005448 if (f < 0)
5449 goto ecreate;
5450 break;
5451 case NTO:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01005452#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00005453 case NTO2:
5454#endif
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005455 /* Take care of noclobber mode. */
5456 if (Cflag) {
Denys Vlasenkof1a5cb02017-07-25 17:47:48 +02005457 if (stat(fname, &sb) < 0) {
5458 f = open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
5459 if (f < 0)
5460 goto ecreate;
5461 } else if (!S_ISREG(sb.st_mode)) {
5462 f = open(fname, O_WRONLY, 0666);
5463 if (f < 0)
5464 goto ecreate;
Denys Vlasenko355ec352018-04-02 13:34:57 +02005465 if (!fstat(f, &sb) && S_ISREG(sb.st_mode)) {
Denys Vlasenkof1a5cb02017-07-25 17:47:48 +02005466 close(f);
5467 errno = EEXIST;
5468 goto ecreate;
5469 }
5470 } else {
5471 errno = EEXIST;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005472 goto ecreate;
Denys Vlasenkof1a5cb02017-07-25 17:47:48 +02005473 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005474 break;
5475 }
5476 /* FALLTHROUGH */
5477 case NCLOBBER:
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005478 f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666);
5479 if (f < 0)
5480 goto ecreate;
5481 break;
5482 case NAPPEND:
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005483 f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666);
5484 if (f < 0)
5485 goto ecreate;
5486 break;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005487 }
5488
5489 return f;
5490 ecreate:
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +00005491 ash_msg_and_raise_error("can't create %s: %s", fname, errmsg(errno, "nonexistent directory"));
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005492 eopen:
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +00005493 ash_msg_and_raise_error("can't open %s: %s", fname, errmsg(errno, "no such file"));
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005494}
5495
5496/*
Denys Vlasenko64774602016-10-26 15:24:30 +02005497 * Copy a file descriptor to be >= 10. Throws exception on error.
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005498 */
5499static int
Denys Vlasenko64774602016-10-26 15:24:30 +02005500savefd(int from)
5501{
5502 int newfd;
5503 int err;
5504
Denys Vlasenko60fb98e2018-03-30 22:15:14 +02005505 newfd = fcntl(from, F_DUPFD_CLOEXEC, 10);
Denys Vlasenko64774602016-10-26 15:24:30 +02005506 err = newfd < 0 ? errno : 0;
5507 if (err != EBADF) {
5508 if (err)
Ron Yorstonbe366e52017-07-27 13:53:39 +01005509 ash_msg_and_raise_perror("%d", from);
Denys Vlasenko64774602016-10-26 15:24:30 +02005510 close(from);
Denys Vlasenko60fb98e2018-03-30 22:15:14 +02005511 if (F_DUPFD_CLOEXEC == F_DUPFD)
5512 close_on_exec_on(newfd);
Denys Vlasenko64774602016-10-26 15:24:30 +02005513 }
5514
5515 return newfd;
5516}
5517static int
5518dup2_or_raise(int from, int to)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005519{
5520 int newfd;
5521
Denys Vlasenko64774602016-10-26 15:24:30 +02005522 newfd = (from != to) ? dup2(from, to) : to;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005523 if (newfd < 0) {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005524 /* Happens when source fd is not open: try "echo >&99" */
Ron Yorstonbe366e52017-07-27 13:53:39 +01005525 ash_msg_and_raise_perror("%d", from);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005526 }
5527 return newfd;
5528}
Denys Vlasenko035486c2017-07-31 04:09:19 +02005529static int
Denys Vlasenko9acd63c2018-03-28 18:35:07 +02005530dup_CLOEXEC(int fd, int avoid_fd)
Denys Vlasenko035486c2017-07-31 04:09:19 +02005531{
5532 int newfd;
5533 repeat:
Denys Vlasenko9acd63c2018-03-28 18:35:07 +02005534 newfd = fcntl(fd, F_DUPFD_CLOEXEC, avoid_fd + 1);
5535 if (newfd >= 0) {
5536 if (F_DUPFD_CLOEXEC == F_DUPFD) /* if old libc (w/o F_DUPFD_CLOEXEC) */
Denys Vlasenko60fb98e2018-03-30 22:15:14 +02005537 close_on_exec_on(newfd);
Denys Vlasenko9acd63c2018-03-28 18:35:07 +02005538 } else { /* newfd < 0 */
Denys Vlasenko035486c2017-07-31 04:09:19 +02005539 if (errno == EBUSY)
5540 goto repeat;
5541 if (errno == EINTR)
5542 goto repeat;
5543 }
5544 return newfd;
5545}
5546static int
5547xdup_CLOEXEC_and_close(int fd, int avoid_fd)
5548{
5549 int newfd;
5550 repeat:
Denys Vlasenko60fb98e2018-03-30 22:15:14 +02005551 newfd = fcntl(fd, F_DUPFD_CLOEXEC, avoid_fd + 1);
Denys Vlasenko035486c2017-07-31 04:09:19 +02005552 if (newfd < 0) {
5553 if (errno == EBUSY)
5554 goto repeat;
5555 if (errno == EINTR)
5556 goto repeat;
5557 /* fd was not open? */
5558 if (errno == EBADF)
5559 return fd;
5560 ash_msg_and_raise_perror("%d", newfd);
5561 }
Denys Vlasenko60fb98e2018-03-30 22:15:14 +02005562 if (F_DUPFD_CLOEXEC == F_DUPFD)
5563 close_on_exec_on(newfd);
Denys Vlasenko035486c2017-07-31 04:09:19 +02005564 close(fd);
5565 return newfd;
5566}
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005567
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005568/* Struct def and variable are moved down to the first usage site */
Denys Vlasenko035486c2017-07-31 04:09:19 +02005569struct squirrel {
5570 int orig_fd;
5571 int moved_to;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005572};
Denis Vlasenko0b769642008-07-24 07:54:57 +00005573struct redirtab {
5574 struct redirtab *next;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005575 int pair_count;
Denys Vlasenko035486c2017-07-31 04:09:19 +02005576 struct squirrel two_fd[];
Denis Vlasenko0b769642008-07-24 07:54:57 +00005577};
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005578#define redirlist (G_var.redirlist)
Denis Vlasenko0b769642008-07-24 07:54:57 +00005579
Denys Vlasenko035486c2017-07-31 04:09:19 +02005580static void
5581add_squirrel_closed(struct redirtab *sq, int fd)
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005582{
5583 int i;
5584
Denys Vlasenko035486c2017-07-31 04:09:19 +02005585 if (!sq)
5586 return;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005587
Denys Vlasenko035486c2017-07-31 04:09:19 +02005588 for (i = 0; sq->two_fd[i].orig_fd != EMPTY; i++) {
5589 /* If we collide with an already moved fd... */
5590 if (fd == sq->two_fd[i].orig_fd) {
5591 /* Examples:
5592 * "echo 3>FILE 3>&- 3>FILE"
5593 * "echo 3>&- 3>FILE"
5594 * No need for last redirect to insert
5595 * another "need to close 3" indicator.
5596 */
5597 TRACE(("redirect_fd %d: already moved or closed\n", fd));
5598 return;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005599 }
5600 }
Denys Vlasenko035486c2017-07-31 04:09:19 +02005601 TRACE(("redirect_fd %d: previous fd was closed\n", fd));
5602 sq->two_fd[i].orig_fd = fd;
5603 sq->two_fd[i].moved_to = CLOSED;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005604}
5605
Denys Vlasenko37dc08b2016-10-02 04:38:07 +02005606static int
Denys Vlasenko035486c2017-07-31 04:09:19 +02005607save_fd_on_redirect(int fd, int avoid_fd, struct redirtab *sq)
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005608{
Denys Vlasenko035486c2017-07-31 04:09:19 +02005609 int i, new_fd;
Denis Vlasenko34c73c42008-08-16 11:48:02 +00005610
Denys Vlasenko035486c2017-07-31 04:09:19 +02005611 if (avoid_fd < 9) /* the important case here is that it can be -1 */
5612 avoid_fd = 9;
5613
5614#if JOBS
5615 if (fd == ttyfd) {
5616 /* Testcase: "ls -l /proc/$$/fd 10>&-" should work */
5617 ttyfd = xdup_CLOEXEC_and_close(ttyfd, avoid_fd);
5618 TRACE(("redirect_fd %d: matches ttyfd, moving it to %d\n", fd, ttyfd));
5619 return 1; /* "we closed fd" */
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005620 }
Denys Vlasenko035486c2017-07-31 04:09:19 +02005621#endif
5622 /* Are we called from redirect(0)? E.g. redirect
5623 * in a forked child. No need to save fds,
5624 * we aren't going to use them anymore, ok to trash.
5625 */
5626 if (!sq)
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005627 return 0;
Denys Vlasenko035486c2017-07-31 04:09:19 +02005628
5629 /* If this one of script's fds? */
5630 if (fd != 0) {
5631 struct parsefile *pf = g_parsefile;
5632 while (pf) {
5633 /* We skip fd == 0 case because of the following:
5634 * $ ash # running ash interactively
5635 * $ . ./script.sh
5636 * and in script.sh: "exec 9>&0".
5637 * Even though top-level pf_fd _is_ 0,
5638 * it's still ok to use it: "read" builtin uses it,
5639 * why should we cripple "exec" builtin?
5640 */
5641 if (fd == pf->pf_fd) {
5642 pf->pf_fd = xdup_CLOEXEC_and_close(fd, avoid_fd);
5643 return 1; /* "we closed fd" */
5644 }
5645 pf = pf->prev;
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005646 }
5647 }
Denys Vlasenko035486c2017-07-31 04:09:19 +02005648
5649 /* Check whether it collides with any open fds (e.g. stdio), save fds as needed */
5650
5651 /* First: do we collide with some already moved fds? */
5652 for (i = 0; sq->two_fd[i].orig_fd != EMPTY; i++) {
5653 /* If we collide with an already moved fd... */
5654 if (fd == sq->two_fd[i].moved_to) {
Denys Vlasenko9acd63c2018-03-28 18:35:07 +02005655 new_fd = dup_CLOEXEC(fd, avoid_fd);
Denys Vlasenko035486c2017-07-31 04:09:19 +02005656 sq->two_fd[i].moved_to = new_fd;
5657 TRACE(("redirect_fd %d: already busy, moving to %d\n", fd, new_fd));
5658 if (new_fd < 0) /* what? */
5659 xfunc_die();
5660 return 0; /* "we did not close fd" */
5661 }
5662 if (fd == sq->two_fd[i].orig_fd) {
5663 /* Example: echo Hello >/dev/null 1>&2 */
5664 TRACE(("redirect_fd %d: already moved\n", fd));
5665 return 0; /* "we did not close fd" */
5666 }
5667 }
5668
5669 /* 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 +02005670 new_fd = dup_CLOEXEC(fd, avoid_fd);
Denys Vlasenko035486c2017-07-31 04:09:19 +02005671 TRACE(("redirect_fd %d: previous fd is moved to %d (-1 if it was closed)\n", fd, new_fd));
5672 if (new_fd < 0) {
5673 if (errno != EBADF)
5674 xfunc_die();
5675 /* new_fd = CLOSED; - already is -1 */
5676 }
5677 sq->two_fd[i].moved_to = new_fd;
5678 sq->two_fd[i].orig_fd = fd;
5679
5680 /* if we move stderr, let "set -x" code know */
5681 if (fd == preverrout_fd)
5682 preverrout_fd = new_fd;
5683
5684 return 0; /* "we did not close fd" */
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005685}
5686
Denys Vlasenko32fdf2f2017-07-31 04:32:06 +02005687static int
5688internally_opened_fd(int fd, struct redirtab *sq)
5689{
5690 int i;
5691#if JOBS
5692 if (fd == ttyfd)
5693 return 1;
5694#endif
5695 /* If this one of script's fds? */
5696 if (fd != 0) {
5697 struct parsefile *pf = g_parsefile;
5698 while (pf) {
5699 if (fd == pf->pf_fd)
5700 return 1;
5701 pf = pf->prev;
5702 }
5703 }
5704
5705 if (sq) for (i = 0; i < sq->pair_count && sq->two_fd[i].orig_fd != EMPTY; i++) {
5706 if (fd == sq->two_fd[i].moved_to)
5707 return 1;
5708 }
5709 return 0;
5710}
5711
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005712/*
5713 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
5714 * old file descriptors are stashed away so that the redirection can be
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005715 * undone by calling popredir.
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005716 */
5717/* flags passed to redirect */
5718#define REDIR_PUSH 01 /* save previous values of file descriptors */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005719static void
5720redirect(union node *redir, int flags)
5721{
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005722 struct redirtab *sv;
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005723
Denys Vlasenko1c79aeb2017-07-29 22:51:52 +02005724 if (!redir)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005725 return;
Denys Vlasenko035486c2017-07-31 04:09:19 +02005726
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005727 sv = NULL;
5728 INT_OFF;
Denys Vlasenko1c79aeb2017-07-29 22:51:52 +02005729 if (flags & REDIR_PUSH)
5730 sv = redirlist;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005731 do {
Denys Vlasenko035486c2017-07-31 04:09:19 +02005732 int fd;
5733 int newfd;
5734 int close_fd;
5735 int closed;
5736
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00005737 fd = redir->nfile.fd;
Denis Vlasenko0b769642008-07-24 07:54:57 +00005738 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
Denys Vlasenko035486c2017-07-31 04:09:19 +02005739 //bb_error_msg("doing %d > %d", fd, newfd);
5740 newfd = redir->ndup.dupfd;
5741 close_fd = -1;
Denis Vlasenko0b769642008-07-24 07:54:57 +00005742 } else {
5743 newfd = openredirect(redir); /* always >= 0 */
5744 if (fd == newfd) {
Denys Vlasenko035486c2017-07-31 04:09:19 +02005745 /* open() gave us precisely the fd we wanted.
5746 * This means that this fd was not busy
5747 * (not opened to anywhere).
5748 * Remember to close it on restore:
5749 */
5750 add_squirrel_closed(sv, fd);
Denis Vlasenko0b769642008-07-24 07:54:57 +00005751 continue;
5752 }
Denys Vlasenko035486c2017-07-31 04:09:19 +02005753 close_fd = newfd;
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005754 }
Denys Vlasenko035486c2017-07-31 04:09:19 +02005755
5756 if (fd == newfd)
5757 continue;
5758
5759 /* if "N>FILE": move newfd to fd */
5760 /* if "N>&M": dup newfd to fd */
5761 /* if "N>&-": close fd (newfd is -1) */
5762
5763 IF_BASH_REDIR_OUTPUT(redirect_more:)
5764
5765 closed = save_fd_on_redirect(fd, /*avoid:*/ newfd, sv);
5766 if (newfd == -1) {
5767 /* "N>&-" means "close me" */
5768 if (!closed) {
5769 /* ^^^ optimization: saving may already
5770 * have closed it. If not... */
5771 close(fd);
Denis Vlasenko22f74142008-07-24 22:34:43 +00005772 }
Denys Vlasenko035486c2017-07-31 04:09:19 +02005773 } else {
Denys Vlasenko32fdf2f2017-07-31 04:32:06 +02005774 /* if newfd is a script fd or saved fd, simulate EBADF */
5775 if (internally_opened_fd(newfd, sv)) {
5776 errno = EBADF;
5777 ash_msg_and_raise_perror("%d", newfd);
5778 }
Denys Vlasenko64774602016-10-26 15:24:30 +02005779 dup2_or_raise(newfd, fd);
Denys Vlasenko035486c2017-07-31 04:09:19 +02005780 if (close_fd >= 0) /* "N>FILE" or ">&FILE" or heredoc? */
5781 close(close_fd);
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01005782#if BASH_REDIR_OUTPUT
Denys Vlasenko035486c2017-07-31 04:09:19 +02005783 if (redir->nfile.type == NTO2 && fd == 1) {
5784 /* ">&FILE". we already redirected to 1, now copy 1 to 2 */
5785 fd = 2;
5786 newfd = 1;
5787 close_fd = -1;
5788 goto redirect_more;
5789 }
Denis Vlasenko559691a2008-10-05 18:39:31 +00005790#endif
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005791 }
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00005792 } while ((redir = redir->nfile.next) != NULL);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005793 INT_ON;
Denys Vlasenkod07a15b2017-07-30 16:51:05 +02005794
5795//dash:#define REDIR_SAVEFD2 03 /* set preverrout */
5796#define REDIR_SAVEFD2 0
5797 // dash has a bug: since REDIR_SAVEFD2=3 and REDIR_PUSH=1, this test
5798 // triggers for pure REDIR_PUSH too. Thus, this is done almost always,
5799 // not only for calls with flags containing REDIR_SAVEFD2.
Denys Vlasenko035486c2017-07-31 04:09:19 +02005800 // We do this unconditionally (see save_fd_on_redirect()).
Denys Vlasenkod07a15b2017-07-30 16:51:05 +02005801 //if ((flags & REDIR_SAVEFD2) && copied_fd2 >= 0)
5802 // preverrout_fd = copied_fd2;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005803}
5804
Denys Vlasenko170f93e2017-07-29 18:54:53 +02005805static int
5806redirectsafe(union node *redir, int flags)
5807{
5808 int err;
5809 volatile int saveint;
5810 struct jmploc *volatile savehandler = exception_handler;
5811 struct jmploc jmploc;
5812
5813 SAVE_INT(saveint);
5814 /* "echo 9>/dev/null; echo >&9; echo result: $?" - result should be 1, not 2! */
Denys Vlasenko035486c2017-07-31 04:09:19 +02005815 err = setjmp(jmploc.loc); /* was = setjmp(jmploc.loc) * 2; */
Denys Vlasenko170f93e2017-07-29 18:54:53 +02005816 if (!err) {
5817 exception_handler = &jmploc;
5818 redirect(redir, flags);
5819 }
5820 exception_handler = savehandler;
5821 if (err && exception_type != EXERROR)
5822 longjmp(exception_handler->loc, 1);
5823 RESTORE_INT(saveint);
5824 return err;
5825}
5826
Denys Vlasenko1c79aeb2017-07-29 22:51:52 +02005827static struct redirtab*
5828pushredir(union node *redir)
5829{
5830 struct redirtab *sv;
5831 int i;
5832
5833 if (!redir)
5834 return redirlist;
5835
5836 i = 0;
5837 do {
5838 i++;
5839#if BASH_REDIR_OUTPUT
5840 if (redir->nfile.type == NTO2)
5841 i++;
5842#endif
5843 redir = redir->nfile.next;
5844 } while (redir);
5845
5846 sv = ckzalloc(sizeof(*sv) + i * sizeof(sv->two_fd[0]));
5847 sv->pair_count = i;
5848 while (--i >= 0)
Denys Vlasenko035486c2017-07-31 04:09:19 +02005849 sv->two_fd[i].orig_fd = sv->two_fd[i].moved_to = EMPTY;
Denys Vlasenko1c79aeb2017-07-29 22:51:52 +02005850 sv->next = redirlist;
5851 redirlist = sv;
5852 return sv->next;
5853}
5854
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005855/*
5856 * Undo the effects of the last redirection.
5857 */
5858static void
Denys Vlasenko035486c2017-07-31 04:09:19 +02005859popredir(int drop)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005860{
5861 struct redirtab *rp;
5862 int i;
5863
Denys Vlasenkoeaf94362016-10-25 21:46:03 +02005864 if (redirlist == NULL)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005865 return;
5866 INT_OFF;
5867 rp = redirlist;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005868 for (i = 0; i < rp->pair_count; i++) {
Denys Vlasenko035486c2017-07-31 04:09:19 +02005869 int fd = rp->two_fd[i].orig_fd;
5870 int copy = rp->two_fd[i].moved_to;
Denis Vlasenko22f74142008-07-24 22:34:43 +00005871 if (copy == CLOSED) {
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005872 if (!drop)
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005873 close(fd);
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005874 continue;
5875 }
Denis Vlasenko22f74142008-07-24 22:34:43 +00005876 if (copy != EMPTY) {
Denys Vlasenko035486c2017-07-31 04:09:19 +02005877 if (!drop) {
Denis Vlasenko5a867312008-07-24 19:46:38 +00005878 /*close(fd);*/
Denys Vlasenko64774602016-10-26 15:24:30 +02005879 dup2_or_raise(copy, fd);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005880 }
Denys Vlasenko035486c2017-07-31 04:09:19 +02005881 close(copy);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005882 }
5883 }
5884 redirlist = rp->next;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005885 free(rp);
5886 INT_ON;
5887}
5888
Denys Vlasenko1c79aeb2017-07-29 22:51:52 +02005889static void
5890unwindredir(struct redirtab *stop)
5891{
5892 while (redirlist != stop)
Denys Vlasenko035486c2017-07-31 04:09:19 +02005893 popredir(/*drop:*/ 0);
Denys Vlasenko1c79aeb2017-07-29 22:51:52 +02005894}
5895
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005896
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005897/* ============ Routines to expand arguments to commands
5898 *
5899 * We have to deal with backquotes, shell variables, and file metacharacters.
5900 */
5901
Denys Vlasenko0b883582016-12-23 16:49:07 +01005902#if ENABLE_FEATURE_SH_MATH
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005903static arith_t
5904ash_arith(const char *s)
5905{
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005906 arith_state_t math_state;
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005907 arith_t result;
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005908
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005909 math_state.lookupvar = lookupvar;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02005910 math_state.setvar = setvar0;
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005911 //math_state.endofname = endofname;
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005912
5913 INT_OFF;
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005914 result = arith(&math_state, s);
Denys Vlasenko063847d2010-09-15 13:33:02 +02005915 if (math_state.errmsg)
5916 ash_msg_and_raise_error(math_state.errmsg);
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005917 INT_ON;
5918
5919 return result;
5920}
Denis Vlasenko448d30e2008-06-27 00:24:11 +00005921#endif
Denys Vlasenkobaa41c72018-01-10 13:22:25 +01005922#if BASH_SUBSTR
5923# if ENABLE_FEATURE_SH_MATH
5924static int substr_atoi(const char *s)
5925{
5926 arith_t t = ash_arith(s);
5927 if (sizeof(t) > sizeof(int)) {
5928 /* clamp very large or very large negative nums for ${v:N:M}:
5929 * else "${v:0:0x100000001}" would work as "${v:0:1}"
5930 */
5931 if (t > INT_MAX)
5932 t = INT_MAX;
5933 if (t < INT_MIN)
5934 t = INT_MIN;
5935 }
5936 return t;
5937}
5938# else
5939# define substr_atoi(s) number(s)
5940# endif
5941#endif
Denis Vlasenko448d30e2008-06-27 00:24:11 +00005942
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005943/*
5944 * expandarg flags
5945 */
5946#define EXP_FULL 0x1 /* perform word splitting & file globbing */
5947#define EXP_TILDE 0x2 /* do normal tilde expansion */
5948#define EXP_VARTILDE 0x4 /* expand tildes in an assignment */
5949#define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */
Denys Vlasenkodb74c6c2016-10-24 21:12:33 +02005950/* ^^^^^^^^^^^^^^ this is meant to support constructs such as "cmd >file*.txt"
5951 * POSIX says for this case:
5952 * Pathname expansion shall not be performed on the word by a
5953 * non-interactive shell; an interactive shell may perform it, but shall
5954 * do so only when the expansion would result in one word.
5955 * Currently, our code complies to the above rule by never globbing
5956 * redirection filenames.
5957 * Bash performs globbing, unless it is non-interactive and in POSIX mode.
5958 * (this means that on a typical Linux distro, bash almost always
5959 * performs globbing, and thus diverges from what we do).
5960 */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005961#define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */
Denys Vlasenko216913c2018-04-02 12:35:04 +02005962#define EXP_VARTILDE2 0x20 /* expand tildes after colons only */
5963#define EXP_WORD 0x40 /* expand word in parameter expansion */
Denys Vlasenko440da972018-08-05 14:29:58 +02005964#define EXP_QUOTED 0x100 /* expand word in double quotes */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005965/*
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005966 * rmescape() flags
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005967 */
5968#define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
5969#define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005970#define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */
5971#define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */
5972
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005973/* Add CTLESC when necessary. */
Denys Vlasenko216913c2018-04-02 12:35:04 +02005974#define QUOTES_ESC (EXP_FULL | EXP_CASE)
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005975/* Do not skip NUL characters. */
5976#define QUOTES_KEEPNUL EXP_TILDE
5977
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005978/*
5979 * Structure specifying which parts of the string should be searched
5980 * for IFS characters.
5981 */
5982struct ifsregion {
5983 struct ifsregion *next; /* next region in list */
5984 int begoff; /* offset of start of region */
5985 int endoff; /* offset of end of region */
5986 int nulonly; /* search for nul bytes only */
5987};
5988
5989struct arglist {
5990 struct strlist *list;
5991 struct strlist **lastp;
5992};
5993
5994/* output of current string */
5995static char *expdest;
5996/* list of back quote expressions */
5997static struct nodelist *argbackq;
5998/* first struct in list of ifs regions */
5999static struct ifsregion ifsfirst;
6000/* last struct in list */
6001static struct ifsregion *ifslastp;
6002/* holds expanded arg list */
6003static struct arglist exparg;
6004
6005/*
6006 * Our own itoa().
Denys Vlasenkocf3a7962017-07-26 14:38:19 +02006007 * cvtnum() is used even if math support is off (to prepare $? values and such).
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006008 */
6009static int
6010cvtnum(arith_t num)
6011{
6012 int len;
6013
Denys Vlasenkocf3a7962017-07-26 14:38:19 +02006014 /* 32-bit and wider ints require buffer size of bytes*3 (or less) */
6015 len = sizeof(arith_t) * 3;
6016 /* If narrower: worst case, 1-byte ints: need 5 bytes: "-127<NUL>" */
6017 if (sizeof(arith_t) < 4) len += 2;
6018
6019 expdest = makestrspace(len, expdest);
6020 len = fmtstr(expdest, len, ARITH_FMT, num);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006021 STADJUST(len, expdest);
6022 return len;
6023}
6024
Denys Vlasenko455e4222016-10-27 14:45:13 +02006025/*
6026 * Break the argument string into pieces based upon IFS and add the
6027 * strings to the argument list. The regions of the string to be
6028 * searched for IFS characters have been stored by recordregion.
6029 */
6030static void
6031ifsbreakup(char *string, struct arglist *arglist)
6032{
6033 struct ifsregion *ifsp;
6034 struct strlist *sp;
6035 char *start;
6036 char *p;
6037 char *q;
6038 const char *ifs, *realifs;
6039 int ifsspc;
6040 int nulonly;
6041
6042 start = string;
6043 if (ifslastp != NULL) {
6044 ifsspc = 0;
6045 nulonly = 0;
6046 realifs = ifsset() ? ifsval() : defifs;
6047 ifsp = &ifsfirst;
6048 do {
Denys Vlasenko9a95df92018-04-02 14:27:50 +02006049 int afternul;
6050
Denys Vlasenko455e4222016-10-27 14:45:13 +02006051 p = string + ifsp->begoff;
Denys Vlasenko9a95df92018-04-02 14:27:50 +02006052 afternul = nulonly;
Denys Vlasenko455e4222016-10-27 14:45:13 +02006053 nulonly = ifsp->nulonly;
6054 ifs = nulonly ? nullstr : realifs;
6055 ifsspc = 0;
6056 while (p < string + ifsp->endoff) {
6057 q = p;
6058 if ((unsigned char)*p == CTLESC)
6059 p++;
6060 if (!strchr(ifs, *p)) {
6061 p++;
6062 continue;
6063 }
Denys Vlasenko9a95df92018-04-02 14:27:50 +02006064 if (!(afternul || nulonly))
Denys Vlasenko455e4222016-10-27 14:45:13 +02006065 ifsspc = (strchr(defifs, *p) != NULL);
6066 /* Ignore IFS whitespace at start */
6067 if (q == start && ifsspc) {
6068 p++;
6069 start = p;
6070 continue;
6071 }
6072 *q = '\0';
6073 sp = stzalloc(sizeof(*sp));
6074 sp->text = start;
6075 *arglist->lastp = sp;
6076 arglist->lastp = &sp->next;
6077 p++;
6078 if (!nulonly) {
6079 for (;;) {
6080 if (p >= string + ifsp->endoff) {
6081 break;
6082 }
6083 q = p;
6084 if ((unsigned char)*p == CTLESC)
6085 p++;
6086 if (strchr(ifs, *p) == NULL) {
6087 p = q;
6088 break;
6089 }
6090 if (strchr(defifs, *p) == NULL) {
6091 if (ifsspc) {
6092 p++;
6093 ifsspc = 0;
6094 } else {
6095 p = q;
6096 break;
6097 }
6098 } else
6099 p++;
6100 }
6101 }
6102 start = p;
6103 } /* while */
6104 ifsp = ifsp->next;
6105 } while (ifsp != NULL);
6106 if (nulonly)
6107 goto add;
6108 }
6109
6110 if (!*start)
6111 return;
6112
6113 add:
6114 sp = stzalloc(sizeof(*sp));
6115 sp->text = start;
6116 *arglist->lastp = sp;
6117 arglist->lastp = &sp->next;
6118}
6119
6120static void
6121ifsfree(void)
6122{
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02006123 struct ifsregion *p = ifsfirst.next;
6124
6125 if (!p)
6126 goto out;
Denys Vlasenko455e4222016-10-27 14:45:13 +02006127
6128 INT_OFF;
Denys Vlasenko455e4222016-10-27 14:45:13 +02006129 do {
6130 struct ifsregion *ifsp;
6131 ifsp = p->next;
6132 free(p);
6133 p = ifsp;
6134 } while (p);
Denys Vlasenko455e4222016-10-27 14:45:13 +02006135 ifsfirst.next = NULL;
6136 INT_ON;
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02006137 out:
6138 ifslastp = NULL;
Denys Vlasenko455e4222016-10-27 14:45:13 +02006139}
6140
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006141static size_t
6142esclen(const char *start, const char *p)
6143{
6144 size_t esc = 0;
6145
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006146 while (p > start && (unsigned char)*--p == CTLESC) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006147 esc++;
6148 }
6149 return esc;
6150}
6151
6152/*
6153 * Remove any CTLESC characters from a string.
6154 */
Denys Vlasenko740058b2018-01-09 17:01:00 +01006155#if !BASH_PATTERN_SUBST
6156#define rmescapes(str, flag, slash_position) \
6157 rmescapes(str, flag)
6158#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006159static char *
Denys Vlasenko740058b2018-01-09 17:01:00 +01006160rmescapes(char *str, int flag, int *slash_position)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006161{
Ron Yorston417622c2015-05-18 09:59:14 +02006162 static const char qchars[] ALIGN1 = {
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006163 IF_BASH_PATTERN_SUBST('/',) CTLESC, CTLQUOTEMARK, '\0' };
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00006164
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006165 char *p, *q, *r;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006166 unsigned protect_against_glob;
6167 unsigned globbing;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006168
Denys Vlasenko740058b2018-01-09 17:01:00 +01006169 p = strpbrk(str, qchars IF_BASH_PATTERN_SUBST(+ !slash_position));
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006170 if (!p)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006171 return str;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006172
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006173 q = p;
6174 r = str;
6175 if (flag & RMESCAPE_ALLOC) {
6176 size_t len = p - str;
6177 size_t fulllen = len + strlen(p) + 1;
6178
6179 if (flag & RMESCAPE_GROW) {
Colin Watson3963d942010-04-26 14:21:27 +02006180 int strloc = str - (char *)stackblock();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006181 r = makestrspace(fulllen, expdest);
Colin Watson3963d942010-04-26 14:21:27 +02006182 /* p and str may be invalidated by makestrspace */
6183 str = (char *)stackblock() + strloc;
6184 p = str + len;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006185 } else if (flag & RMESCAPE_HEAP) {
6186 r = ckmalloc(fulllen);
6187 } else {
6188 r = stalloc(fulllen);
6189 }
6190 q = r;
6191 if (len > 0) {
Denys Vlasenko5ace96a2017-07-23 21:46:02 +02006192 q = (char *)mempcpy(q, str, len);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006193 }
6194 }
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006195
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006196 globbing = flag & RMESCAPE_GLOB;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006197 protect_against_glob = globbing;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006198 while (*p) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006199 if ((unsigned char)*p == CTLQUOTEMARK) {
Denys Vlasenko216913c2018-04-02 12:35:04 +02006200// Note: protect_against_glob only affect whether
Denys Vlasenkofda9faf2017-07-05 19:10:21 +02006201// CTLESC,<ch> gets converted to <ch> or to \<ch>
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006202 p++;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006203 protect_against_glob = globbing;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006204 continue;
6205 }
Denys Vlasenko216913c2018-04-02 12:35:04 +02006206 if (*p == '\\') {
6207 /* naked back slash */
6208 protect_against_glob = 0;
6209 goto copy;
6210 }
Ron Yorston549deab2015-05-18 09:57:51 +02006211 if ((unsigned char)*p == CTLESC) {
6212 p++;
Denys Vlasenko13f20912016-09-25 20:54:25 +02006213#if DEBUG
6214 if (*p == '\0')
6215 ash_msg_and_raise_error("CTLESC at EOL (shouldn't happen)");
6216#endif
Ron Yorston549deab2015-05-18 09:57:51 +02006217 if (protect_against_glob) {
Denys Vlasenkofda9faf2017-07-05 19:10:21 +02006218 /*
6219 * We used to trust glob() and fnmatch() to eat
6220 * superfluous escapes (\z where z has no
6221 * special meaning anyway). But this causes
6222 * bugs such as string of one greek letter rho
Denys Vlasenkoed79a632017-07-05 19:20:43 +02006223 * (unicode-encoded as two bytes "cf,81")
Denys Vlasenkofda9faf2017-07-05 19:10:21 +02006224 * getting encoded as "cf,CTLESC,81"
6225 * and here, converted to "cf,\,81" -
6226 * which does not go well with some flavors
Denys Vlasenko92b8d9c2017-07-05 19:13:44 +02006227 * of fnmatch() in unicode locales
6228 * (for example, glibc <= 2.22).
Denys Vlasenkofda9faf2017-07-05 19:10:21 +02006229 *
6230 * Lets add "\" only on the chars which need it.
Denys Vlasenko4142f012017-07-05 22:19:28 +02006231 * Testcases for less obvious chars are shown.
Denys Vlasenkofda9faf2017-07-05 19:10:21 +02006232 */
6233 if (*p == '*'
6234 || *p == '?'
6235 || *p == '['
Denys Vlasenko8de5b9f2018-02-13 14:43:29 +01006236 || *p == '\\' /* case '\' in \\ ) echo ok;; *) echo WRONG;; esac */
6237 || *p == ']' /* case ']' in [a\]] ) echo ok;; *) echo WRONG;; esac */
6238 || *p == '-' /* case '-' in [a\-c]) echo ok;; *) echo WRONG;; esac */
6239 || *p == '!' /* case '!' in [\!] ) echo ok;; *) echo WRONG;; esac */
Denys Vlasenko4142f012017-07-05 22:19:28 +02006240 /* Some libc support [^negate], that's why "^" also needs love */
Denys Vlasenko8de5b9f2018-02-13 14:43:29 +01006241 || *p == '^' /* case '^' in [\^] ) echo ok;; *) echo WRONG;; esac */
Denys Vlasenkofda9faf2017-07-05 19:10:21 +02006242 ) {
6243 *q++ = '\\';
6244 }
Ron Yorston549deab2015-05-18 09:57:51 +02006245 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006246 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006247#if BASH_PATTERN_SUBST
Denys Vlasenko740058b2018-01-09 17:01:00 +01006248 else if (slash_position && p == str + *slash_position) {
6249 /* stop handling globbing */
6250 globbing = 0;
6251 *slash_position = q - r;
6252 slash_position = NULL;
Ron Yorston417622c2015-05-18 09:59:14 +02006253 }
6254#endif
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006255 protect_against_glob = globbing;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006256 copy:
6257 *q++ = *p++;
6258 }
6259 *q = '\0';
6260 if (flag & RMESCAPE_GROW) {
6261 expdest = r;
6262 STADJUST(q - r + 1, expdest);
6263 }
6264 return r;
6265}
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006266#define pmatch(a, b) !fnmatch((a), (b), 0)
6267
6268/*
6269 * Prepare a pattern for a expmeta (internal glob(3)) call.
6270 *
6271 * Returns an stalloced string.
6272 */
6273static char *
Ron Yorston549deab2015-05-18 09:57:51 +02006274preglob(const char *pattern, int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006275{
Denys Vlasenko740058b2018-01-09 17:01:00 +01006276 return rmescapes((char *)pattern, flag | RMESCAPE_GLOB, NULL);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006277}
6278
6279/*
6280 * Put a string on the stack.
6281 */
6282static void
6283memtodest(const char *p, size_t len, int syntax, int quotes)
6284{
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006285 char *q;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006286
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006287 if (!len)
6288 return;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006289
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006290 q = makestrspace((quotes & QUOTES_ESC) ? len * 2 : len, expdest);
6291
6292 do {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006293 unsigned char c = *p++;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006294 if (c) {
Denys Vlasenko2fe66b12016-12-12 17:39:12 +01006295 if (quotes & QUOTES_ESC) {
6296 int n = SIT(c, syntax);
6297 if (n == CCTL
Denys Vlasenkoeb54ca82018-08-07 18:54:52 +02006298 || (syntax != BASESYNTAX && n == CBACK)
Denys Vlasenko2fe66b12016-12-12 17:39:12 +01006299 ) {
6300 USTPUTC(CTLESC, q);
6301 }
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02006302 }
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006303 } else if (!(quotes & QUOTES_KEEPNUL))
6304 continue;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006305 USTPUTC(c, q);
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006306 } while (--len);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006307
6308 expdest = q;
6309}
6310
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006311static size_t
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006312strtodest(const char *p, int syntax, int quotes)
6313{
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006314 size_t len = strlen(p);
6315 memtodest(p, len, syntax, quotes);
6316 return len;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006317}
6318
6319/*
6320 * Record the fact that we have to scan this region of the
6321 * string for IFS characters.
6322 */
6323static void
6324recordregion(int start, int end, int nulonly)
6325{
6326 struct ifsregion *ifsp;
6327
6328 if (ifslastp == NULL) {
6329 ifsp = &ifsfirst;
6330 } else {
6331 INT_OFF;
Denis Vlasenko597906c2008-02-20 16:38:54 +00006332 ifsp = ckzalloc(sizeof(*ifsp));
6333 /*ifsp->next = NULL; - ckzalloc did it */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006334 ifslastp->next = ifsp;
6335 INT_ON;
6336 }
6337 ifslastp = ifsp;
6338 ifslastp->begoff = start;
6339 ifslastp->endoff = end;
6340 ifslastp->nulonly = nulonly;
6341}
6342
6343static void
6344removerecordregions(int endoff)
6345{
6346 if (ifslastp == NULL)
6347 return;
6348
6349 if (ifsfirst.endoff > endoff) {
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006350 while (ifsfirst.next) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006351 struct ifsregion *ifsp;
6352 INT_OFF;
6353 ifsp = ifsfirst.next->next;
6354 free(ifsfirst.next);
6355 ifsfirst.next = ifsp;
6356 INT_ON;
6357 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006358 if (ifsfirst.begoff > endoff) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006359 ifslastp = NULL;
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006360 } else {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006361 ifslastp = &ifsfirst;
6362 ifsfirst.endoff = endoff;
6363 }
6364 return;
6365 }
6366
6367 ifslastp = &ifsfirst;
6368 while (ifslastp->next && ifslastp->next->begoff < endoff)
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006369 ifslastp = ifslastp->next;
6370 while (ifslastp->next) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006371 struct ifsregion *ifsp;
6372 INT_OFF;
6373 ifsp = ifslastp->next->next;
6374 free(ifslastp->next);
6375 ifslastp->next = ifsp;
6376 INT_ON;
6377 }
6378 if (ifslastp->endoff > endoff)
6379 ifslastp->endoff = endoff;
6380}
6381
6382static char *
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006383exptilde(char *startp, char *p, int flags)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006384{
Denys Vlasenkocd716832009-11-28 22:14:02 +01006385 unsigned char c;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006386 char *name;
6387 struct passwd *pw;
6388 const char *home;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006389 int quotes = flags & QUOTES_ESC;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006390
6391 name = p + 1;
6392
6393 while ((c = *++p) != '\0') {
6394 switch (c) {
6395 case CTLESC:
6396 return startp;
6397 case CTLQUOTEMARK:
6398 return startp;
6399 case ':':
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006400 if (flags & EXP_VARTILDE)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006401 goto done;
6402 break;
6403 case '/':
6404 case CTLENDVAR:
6405 goto done;
6406 }
6407 }
6408 done:
6409 *p = '\0';
6410 if (*name == '\0') {
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02006411 home = lookupvar("HOME");
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006412 } else {
6413 pw = getpwnam(name);
6414 if (pw == NULL)
6415 goto lose;
6416 home = pw->pw_dir;
6417 }
6418 if (!home || !*home)
6419 goto lose;
6420 *p = c;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006421 strtodest(home, SQSYNTAX, quotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006422 return p;
6423 lose:
6424 *p = c;
6425 return startp;
6426}
6427
6428/*
6429 * Execute a command inside back quotes. If it's a builtin command, we
6430 * want to save its output in a block obtained from malloc. Otherwise
6431 * we fork off a subprocess and get the output of the command via a pipe.
6432 * Should be called with interrupts off.
6433 */
6434struct backcmd { /* result of evalbackcmd */
6435 int fd; /* file descriptor to read from */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006436 int nleft; /* number of chars in buffer */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00006437 char *buf; /* buffer */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006438 struct job *jp; /* job structure for command */
6439};
6440
6441/* These forward decls are needed to use "eval" code for backticks handling: */
Denys Vlasenko1e3e2cc2017-07-25 20:31:14 +02006442/* flags in argument to evaltree */
6443#define EV_EXIT 01 /* exit after evaluating tree */
6444#define EV_TESTED 02 /* exit status is checked; ignore -e flag */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02006445static int evaltree(union node *, int);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006446
Denys Vlasenko619d9b52017-07-28 15:28:33 +02006447/* An evaltree() which is known to never return.
6448 * Used to use an alias:
6449 * static int evaltreenr(union node *, int) __attribute__((alias("evaltree"),__noreturn__));
6450 * but clang was reported to "transfer" noreturn-ness to evaltree() as well.
6451 */
6452static ALWAYS_INLINE NORETURN void
6453evaltreenr(union node *n, int flags)
6454{
6455 evaltree(n, flags);
6456 bb_unreachable(abort());
6457 /* NOTREACHED */
6458}
6459
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02006460static void FAST_FUNC
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006461evalbackcmd(union node *n, struct backcmd *result)
6462{
Denys Vlasenko579ad102016-10-25 21:10:20 +02006463 int pip[2];
6464 struct job *jp;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006465
6466 result->fd = -1;
6467 result->buf = NULL;
6468 result->nleft = 0;
6469 result->jp = NULL;
Denys Vlasenko579ad102016-10-25 21:10:20 +02006470 if (n == NULL) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006471 goto out;
Denys Vlasenko579ad102016-10-25 21:10:20 +02006472 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006473
Denys Vlasenko579ad102016-10-25 21:10:20 +02006474 if (pipe(pip) < 0)
Denys Vlasenko12ffefb2017-08-23 14:52:56 +02006475 ash_msg_and_raise_perror("can't create pipe");
Denys Vlasenko579ad102016-10-25 21:10:20 +02006476 jp = makejob(/*n,*/ 1);
6477 if (forkshell(jp, n, FORK_NOJOB) == 0) {
Denys Vlasenko70392332016-10-27 02:31:55 +02006478 /* child */
Denys Vlasenko579ad102016-10-25 21:10:20 +02006479 FORCE_INT_ON;
6480 close(pip[0]);
6481 if (pip[1] != 1) {
6482 /*close(1);*/
Denys Vlasenko64774602016-10-26 15:24:30 +02006483 dup2_or_raise(pip[1], 1);
Denys Vlasenko579ad102016-10-25 21:10:20 +02006484 close(pip[1]);
6485 }
Denys Vlasenko960ca382016-10-25 18:12:15 +02006486/* TODO: eflag clearing makes the following not abort:
6487 * ash -c 'set -e; z=$(false;echo foo); echo $z'
6488 * which is what bash does (unless it is in POSIX mode).
6489 * dash deleted "eflag = 0" line in the commit
6490 * Date: Mon, 28 Jun 2010 17:11:58 +1000
6491 * [EVAL] Don't clear eflag in evalbackcmd
6492 * For now, preserve bash-like behavior, it seems to be somewhat more useful:
6493 */
Denys Vlasenko579ad102016-10-25 21:10:20 +02006494 eflag = 0;
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02006495 ifsfree();
Denys Vlasenko619d9b52017-07-28 15:28:33 +02006496 evaltreenr(n, EV_EXIT);
Denys Vlasenko579ad102016-10-25 21:10:20 +02006497 /* NOTREACHED */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006498 }
Denys Vlasenko70392332016-10-27 02:31:55 +02006499 /* parent */
Denys Vlasenko579ad102016-10-25 21:10:20 +02006500 close(pip[1]);
6501 result->fd = pip[0];
6502 result->jp = jp;
6503
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006504 out:
6505 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
6506 result->fd, result->buf, result->nleft, result->jp));
6507}
6508
6509/*
6510 * Expand stuff in backwards quotes.
6511 */
6512static void
Ron Yorston549deab2015-05-18 09:57:51 +02006513expbackq(union node *cmd, int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006514{
6515 struct backcmd in;
6516 int i;
6517 char buf[128];
6518 char *p;
6519 char *dest;
6520 int startloc;
Ron Yorston549deab2015-05-18 09:57:51 +02006521 int syntax = flag & EXP_QUOTED ? DQSYNTAX : BASESYNTAX;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006522 struct stackmark smark;
6523
6524 INT_OFF;
Denys Vlasenko60ca8342016-09-30 11:21:21 +02006525 startloc = expdest - (char *)stackblock();
6526 pushstackmark(&smark, startloc);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006527 evalbackcmd(cmd, &in);
6528 popstackmark(&smark);
6529
6530 p = in.buf;
6531 i = in.nleft;
6532 if (i == 0)
6533 goto read;
6534 for (;;) {
Ron Yorston549deab2015-05-18 09:57:51 +02006535 memtodest(p, i, syntax, flag & QUOTES_ESC);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006536 read:
6537 if (in.fd < 0)
6538 break;
Ron Yorston61d6ae22015-04-19 10:50:25 +01006539 i = nonblock_immune_read(in.fd, buf, sizeof(buf));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006540 TRACE(("expbackq: read returns %d\n", i));
6541 if (i <= 0)
6542 break;
6543 p = buf;
6544 }
6545
Denis Vlasenko60818682007-09-28 22:07:23 +00006546 free(in.buf);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006547 if (in.fd >= 0) {
6548 close(in.fd);
6549 back_exitstatus = waitforjob(in.jp);
6550 }
6551 INT_ON;
6552
6553 /* Eat all trailing newlines */
6554 dest = expdest;
6555 for (; dest > (char *)stackblock() && dest[-1] == '\n';)
6556 STUNPUTC(dest);
6557 expdest = dest;
6558
Ron Yorston549deab2015-05-18 09:57:51 +02006559 if (!(flag & EXP_QUOTED))
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006560 recordregion(startloc, dest - (char *)stackblock(), 0);
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006561 TRACE(("evalbackq: size:%d:'%.*s'\n",
6562 (int)((dest - (char *)stackblock()) - startloc),
6563 (int)((dest - (char *)stackblock()) - startloc),
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006564 stackblock() + startloc));
6565}
6566
Denys Vlasenko0b883582016-12-23 16:49:07 +01006567#if ENABLE_FEATURE_SH_MATH
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006568/*
6569 * Expand arithmetic expression. Backup to start of expression,
6570 * evaluate, place result in (backed up) result, adjust string position.
6571 */
6572static void
Ron Yorston549deab2015-05-18 09:57:51 +02006573expari(int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006574{
6575 char *p, *start;
6576 int begoff;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006577 int len;
6578
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006579 /* ifsfree(); */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006580
6581 /*
6582 * This routine is slightly over-complicated for
6583 * efficiency. Next we scan backwards looking for the
6584 * start of arithmetic.
6585 */
6586 start = stackblock();
6587 p = expdest - 1;
6588 *p = '\0';
6589 p--;
Denys Vlasenko940c7202011-03-02 04:07:14 +01006590 while (1) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006591 int esc;
6592
Denys Vlasenkocd716832009-11-28 22:14:02 +01006593 while ((unsigned char)*p != CTLARI) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006594 p--;
6595#if DEBUG
6596 if (p < start) {
6597 ash_msg_and_raise_error("missing CTLARI (shouldn't happen)");
6598 }
6599#endif
6600 }
6601
6602 esc = esclen(start, p);
6603 if (!(esc % 2)) {
6604 break;
6605 }
6606
6607 p -= esc + 1;
Denys Vlasenko940c7202011-03-02 04:07:14 +01006608 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006609
6610 begoff = p - start;
6611
6612 removerecordregions(begoff);
6613
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006614 expdest = p;
6615
Ron Yorston549deab2015-05-18 09:57:51 +02006616 if (flag & QUOTES_ESC)
Denys Vlasenko740058b2018-01-09 17:01:00 +01006617 rmescapes(p + 1, 0, NULL);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006618
Ron Yorston549deab2015-05-18 09:57:51 +02006619 len = cvtnum(ash_arith(p + 1));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006620
Ron Yorston549deab2015-05-18 09:57:51 +02006621 if (!(flag & EXP_QUOTED))
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006622 recordregion(begoff, begoff + len, 0);
6623}
6624#endif
6625
6626/* argstr needs it */
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02006627static char *evalvar(char *p, int flags);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006628
6629/*
6630 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
6631 * characters to allow for further processing. Otherwise treat
6632 * $@ like $* since no splitting will be performed.
6633 */
6634static void
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02006635argstr(char *p, int flags)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006636{
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00006637 static const char spclchars[] ALIGN1 = {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006638 '=',
6639 ':',
6640 CTLQUOTEMARK,
6641 CTLENDVAR,
6642 CTLESC,
6643 CTLVAR,
6644 CTLBACKQ,
Denys Vlasenko0b883582016-12-23 16:49:07 +01006645#if ENABLE_FEATURE_SH_MATH
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006646 CTLENDARI,
6647#endif
Denys Vlasenkocd716832009-11-28 22:14:02 +01006648 '\0'
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006649 };
6650 const char *reject = spclchars;
Ron Yorston3df47f92015-05-18 09:53:26 +02006651 int breakall = (flags & (EXP_WORD | EXP_QUOTED)) == EXP_WORD;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006652 int inquotes;
6653 size_t length;
6654 int startloc;
6655
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006656 if (!(flags & EXP_VARTILDE)) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006657 reject += 2;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006658 } else if (flags & EXP_VARTILDE2) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006659 reject++;
6660 }
6661 inquotes = 0;
6662 length = 0;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006663 if (flags & EXP_TILDE) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006664 char *q;
6665
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006666 flags &= ~EXP_TILDE;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006667 tilde:
6668 q = p;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006669 if (*q == '~')
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006670 p = exptilde(p, q, flags);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006671 }
6672 start:
6673 startloc = expdest - (char *)stackblock();
6674 for (;;) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006675 unsigned char c;
6676
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006677 length += strcspn(p + length, reject);
Denys Vlasenkocd716832009-11-28 22:14:02 +01006678 c = p[length];
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006679 if (c) {
6680 if (!(c & 0x80)
Denys Vlasenko0b883582016-12-23 16:49:07 +01006681 IF_FEATURE_SH_MATH(|| c == CTLENDARI)
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006682 ) {
6683 /* c == '=' || c == ':' || c == CTLENDARI */
6684 length++;
6685 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006686 }
6687 if (length > 0) {
6688 int newloc;
6689 expdest = stack_nputstr(p, length, expdest);
6690 newloc = expdest - (char *)stackblock();
6691 if (breakall && !inquotes && newloc > startloc) {
6692 recordregion(startloc, newloc, 0);
6693 }
6694 startloc = newloc;
6695 }
6696 p += length + 1;
6697 length = 0;
6698
6699 switch (c) {
6700 case '\0':
6701 goto breakloop;
6702 case '=':
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006703 if (flags & EXP_VARTILDE2) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006704 p--;
6705 continue;
6706 }
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006707 flags |= EXP_VARTILDE2;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006708 reject++;
6709 /* fall through */
6710 case ':':
6711 /*
6712 * sort of a hack - expand tildes in variable
6713 * assignments (after the first '=' and after ':'s).
6714 */
6715 if (*--p == '~') {
6716 goto tilde;
6717 }
6718 continue;
6719 }
6720
6721 switch (c) {
6722 case CTLENDVAR: /* ??? */
6723 goto breakloop;
6724 case CTLQUOTEMARK:
6725 /* "$@" syntax adherence hack */
Denys Vlasenko9a95df92018-04-02 14:27:50 +02006726 if (!inquotes && !memcmp(p, dolatstr + 1, DOLATSTRLEN - 1)) {
6727 p = evalvar(p + 1, flags | EXP_QUOTED) + 1;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006728 goto start;
6729 }
Denys Vlasenko9a95df92018-04-02 14:27:50 +02006730 inquotes ^= EXP_QUOTED;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006731 addquote:
Ron Yorston549deab2015-05-18 09:57:51 +02006732 if (flags & QUOTES_ESC) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006733 p--;
6734 length++;
6735 startloc++;
6736 }
6737 break;
6738 case CTLESC:
6739 startloc++;
6740 length++;
6741 goto addquote;
6742 case CTLVAR:
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02006743 TRACE(("argstr: evalvar('%s')\n", p));
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02006744 p = evalvar(p, flags | inquotes);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02006745 TRACE(("argstr: evalvar:'%s'\n", (char *)stackblock()));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006746 goto start;
6747 case CTLBACKQ:
Ron Yorston549deab2015-05-18 09:57:51 +02006748 expbackq(argbackq->n, flags | inquotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006749 argbackq = argbackq->next;
6750 goto start;
Denys Vlasenko0b883582016-12-23 16:49:07 +01006751#if ENABLE_FEATURE_SH_MATH
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006752 case CTLENDARI:
6753 p--;
Ron Yorston549deab2015-05-18 09:57:51 +02006754 expari(flags | inquotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006755 goto start;
6756#endif
6757 }
6758 }
Denys Vlasenko958581a2010-09-12 15:04:27 +02006759 breakloop: ;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006760}
6761
6762static char *
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006763scanleft(char *startp, char *rmesc, char *rmescend UNUSED_PARAM,
6764 char *pattern, int quotes, int zero)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006765{
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006766 char *loc, *loc2;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006767 char c;
6768
6769 loc = startp;
6770 loc2 = rmesc;
6771 do {
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006772 int match;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006773 const char *s = loc2;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006774
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006775 c = *loc2;
6776 if (zero) {
6777 *loc2 = '\0';
6778 s = rmesc;
6779 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006780 match = pmatch(pattern, s);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006781
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006782 *loc2 = c;
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006783 if (match)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006784 return loc;
Denys Vlasenkocd716832009-11-28 22:14:02 +01006785 if (quotes && (unsigned char)*loc == CTLESC)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006786 loc++;
6787 loc++;
6788 loc2++;
6789 } while (c);
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006790 return NULL;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006791}
6792
6793static char *
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006794scanright(char *startp, char *rmesc, char *rmescend,
6795 char *pattern, int quotes, int match_at_start)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006796{
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006797#if !ENABLE_ASH_OPTIMIZE_FOR_SIZE
6798 int try2optimize = match_at_start;
6799#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006800 int esc = 0;
6801 char *loc;
6802 char *loc2;
6803
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006804 /* If we called by "${v/pattern/repl}" or "${v//pattern/repl}":
6805 * startp="escaped_value_of_v" rmesc="raw_value_of_v"
6806 * rmescend=""(ptr to NUL in rmesc) pattern="pattern" quotes=match_at_start=1
6807 * Logic:
6808 * loc starts at NUL at the end of startp, loc2 starts at the end of rmesc,
6809 * and on each iteration they go back two/one char until they reach the beginning.
6810 * We try to find a match in "raw_value_of_v", "raw_value_of_", "raw_value_of" etc.
6811 */
6812 /* TODO: document in what other circumstances we are called. */
6813
6814 for (loc = pattern - 1, loc2 = rmescend; loc >= startp; loc2--) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006815 int match;
6816 char c = *loc2;
6817 const char *s = loc2;
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006818 if (match_at_start) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006819 *loc2 = '\0';
6820 s = rmesc;
6821 }
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006822 match = pmatch(pattern, s);
6823 //bb_error_msg("pmatch(pattern:'%s',s:'%s'):%d", pattern, s, match);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006824 *loc2 = c;
6825 if (match)
6826 return loc;
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006827#if !ENABLE_ASH_OPTIMIZE_FOR_SIZE
6828 if (try2optimize) {
6829 /* Maybe we can optimize this:
6830 * if pattern ends with unescaped *, we can avoid checking
Denys Vlasenko10ad6222017-04-17 16:13:32 +02006831 * shorter strings: if "foo*" doesn't match "raw_value_of_v",
6832 * it won't match truncated "raw_value_of_" strings too.
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006833 */
6834 unsigned plen = strlen(pattern);
6835 /* Does it end with "*"? */
6836 if (plen != 0 && pattern[--plen] == '*') {
6837 /* "xxxx*" is not escaped */
6838 /* "xxx\*" is escaped */
6839 /* "xx\\*" is not escaped */
6840 /* "x\\\*" is escaped */
6841 int slashes = 0;
6842 while (plen != 0 && pattern[--plen] == '\\')
6843 slashes++;
6844 if (!(slashes & 1))
6845 break; /* ends with unescaped "*" */
6846 }
6847 try2optimize = 0;
6848 }
6849#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006850 loc--;
6851 if (quotes) {
6852 if (--esc < 0) {
6853 esc = esclen(startp, loc);
6854 }
6855 if (esc % 2) {
6856 esc--;
6857 loc--;
6858 }
6859 }
6860 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006861 return NULL;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006862}
6863
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00006864static void varunset(const char *, const char *, const char *, int) NORETURN;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006865static void
6866varunset(const char *end, const char *var, const char *umsg, int varflags)
6867{
6868 const char *msg;
6869 const char *tail;
6870
6871 tail = nullstr;
6872 msg = "parameter not set";
6873 if (umsg) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006874 if ((unsigned char)*end == CTLENDVAR) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006875 if (varflags & VSNUL)
6876 tail = " or null";
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006877 } else {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006878 msg = umsg;
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006879 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006880 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006881 ash_msg_and_raise_error("%.*s: %s%s", (int)(end - var - 1), var, msg, tail);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006882}
6883
6884static const char *
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006885subevalvar(char *p, char *varname, int strloc, int subtype,
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02006886 int startloc, int varflags, int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006887{
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006888 struct nodelist *saveargbackq = argbackq;
Ron Yorston549deab2015-05-18 09:57:51 +02006889 int quotes = flag & QUOTES_ESC;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006890 char *startp;
6891 char *loc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006892 char *rmesc, *rmescend;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006893 char *str;
Denys Vlasenko0b4980c2012-09-25 12:49:29 +02006894 int amount, resetloc;
Denys Vlasenko740058b2018-01-09 17:01:00 +01006895 int argstr_flags;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006896 IF_BASH_PATTERN_SUBST(int workloc;)
Denys Vlasenko740058b2018-01-09 17:01:00 +01006897 IF_BASH_PATTERN_SUBST(int slash_pos;)
6898 IF_BASH_PATTERN_SUBST(char *repl;)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006899 int zero;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006900 char *(*scan)(char*, char*, char*, char*, int, int);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006901
Denys Vlasenko6040fe82010-09-12 15:03:16 +02006902 //bb_error_msg("subevalvar(p:'%s',varname:'%s',strloc:%d,subtype:%d,startloc:%d,varflags:%x,quotes:%d)",
6903 // p, varname, strloc, subtype, startloc, varflags, quotes);
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006904
Denys Vlasenko740058b2018-01-09 17:01:00 +01006905#if BASH_PATTERN_SUBST
Denys Vlasenkod1df1a72018-01-09 17:25:58 +01006906 /* For "${v/pattern/repl}", we must find the delimiter _before_
6907 * argstr() call expands possible variable references in pattern:
6908 * think about "v=a; a=a/; echo ${v/$a/r}" case.
6909 */
Denys Vlasenko740058b2018-01-09 17:01:00 +01006910 repl = NULL;
6911 if (subtype == VSREPLACE || subtype == VSREPLACEALL) {
6912 /* Find '/' and replace with NUL */
6913 repl = p;
Denys Vlasenkoc2aa2182018-08-04 22:25:28 +02006914 /* The pattern can't be empty.
6915 * IOW: if the first char after "${v//" is a slash,
6916 * it does not terminate the pattern - it's the first char of the pattern:
6917 * v=/dev/ram; echo ${v////-} prints -dev-ram (pattern is "/")
6918 * v=/dev/ram; echo ${v///r/-} prints /dev-am (pattern is "/r")
6919 */
6920 if (*repl == '/')
6921 repl++;
Denys Vlasenko740058b2018-01-09 17:01:00 +01006922 for (;;) {
Denys Vlasenko740058b2018-01-09 17:01:00 +01006923 if (*repl == '\0') {
6924 repl = NULL;
6925 break;
6926 }
6927 if (*repl == '/') {
6928 *repl = '\0';
6929 break;
6930 }
Denys Vlasenkoc2aa2182018-08-04 22:25:28 +02006931 /* Handle escaped slashes, e.g. "${v/\//_}" (they are CTLESC'ed by this point) */
Denys Vlasenkod1df1a72018-01-09 17:25:58 +01006932 if ((unsigned char)*repl == CTLESC && repl[1])
Denys Vlasenko740058b2018-01-09 17:01:00 +01006933 repl++;
Denys Vlasenko740058b2018-01-09 17:01:00 +01006934 repl++;
6935 }
6936 }
6937#endif
6938 argstr_flags = EXP_TILDE;
Denys Vlasenko216913c2018-04-02 12:35:04 +02006939 if (subtype != VSASSIGN
6940 && subtype != VSQUESTION
6941#if BASH_SUBSTR
6942 && subtype != VSSUBSTR
6943#endif
6944 ) {
6945 /* EXP_CASE keeps CTLESC's */
6946 argstr_flags = EXP_TILDE | EXP_CASE;
6947 }
Denys Vlasenko740058b2018-01-09 17:01:00 +01006948 argstr(p, argstr_flags);
Denys Vlasenko216913c2018-04-02 12:35:04 +02006949 //bb_error_msg("str0:'%s'", (char *)stackblock() + strloc);
Denys Vlasenko740058b2018-01-09 17:01:00 +01006950#if BASH_PATTERN_SUBST
6951 slash_pos = -1;
6952 if (repl) {
6953 slash_pos = expdest - ((char *)stackblock() + strloc);
6954 STPUTC('/', expdest);
Denys Vlasenko216913c2018-04-02 12:35:04 +02006955 //bb_error_msg("repl+1:'%s'", repl + 1);
6956 argstr(repl + 1, EXP_TILDE); /* EXP_TILDE: echo "${v/x/~}" expands ~ ! */
Denys Vlasenko740058b2018-01-09 17:01:00 +01006957 *repl = '/';
6958 }
6959#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006960 STPUTC('\0', expdest);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006961 argbackq = saveargbackq;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006962 startp = (char *)stackblock() + startloc;
Denys Vlasenko740058b2018-01-09 17:01:00 +01006963 //bb_error_msg("str1:'%s'", (char *)stackblock() + strloc);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006964
6965 switch (subtype) {
6966 case VSASSIGN:
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02006967 setvar0(varname, startp);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006968 amount = startp - expdest;
6969 STADJUST(amount, expdest);
6970 return startp;
6971
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006972 case VSQUESTION:
6973 varunset(p, varname, startp, varflags);
6974 /* NOTREACHED */
6975
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006976#if BASH_SUBSTR
Denys Vlasenko826360f2017-07-17 17:49:11 +02006977 case VSSUBSTR: {
6978 int pos, len, orig_len;
6979 char *colon;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006980
Denys Vlasenko826360f2017-07-17 17:49:11 +02006981 loc = str = stackblock() + strloc;
6982
Denys Vlasenko826360f2017-07-17 17:49:11 +02006983 /* Read POS in ${var:POS:LEN} */
6984 colon = strchr(loc, ':');
6985 if (colon) *colon = '\0';
Denys Vlasenkobaa41c72018-01-10 13:22:25 +01006986 pos = substr_atoi(loc);
Denys Vlasenko826360f2017-07-17 17:49:11 +02006987 if (colon) *colon = ':';
6988
6989 /* Read LEN in ${var:POS:LEN} */
6990 len = str - startp - 1;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006991 /* *loc != '\0', guaranteed by parser */
6992 if (quotes) {
6993 char *ptr;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006994 /* Adjust the length by the number of escapes */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006995 for (ptr = startp; ptr < (str - 1); ptr++) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006996 if ((unsigned char)*ptr == CTLESC) {
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006997 len--;
6998 ptr++;
6999 }
7000 }
7001 }
7002 orig_len = len;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007003 if (*loc++ == ':') {
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02007004 /* ${var::LEN} */
Denys Vlasenkobaa41c72018-01-10 13:22:25 +01007005 len = substr_atoi(loc);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007006 } else {
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02007007 /* Skip POS in ${var:POS:LEN} */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007008 len = orig_len;
Denys Vlasenkobaa41c72018-01-10 13:22:25 +01007009 while (*loc && *loc != ':')
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007010 loc++;
Denys Vlasenkobaa41c72018-01-10 13:22:25 +01007011 if (*loc++ == ':')
7012 len = substr_atoi(loc);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007013 }
Denys Vlasenko08a5dab2014-11-17 20:27:18 +01007014 if (pos < 0) {
7015 /* ${VAR:$((-n)):l} starts n chars from the end */
7016 pos = orig_len + pos;
7017 }
7018 if ((unsigned)pos >= orig_len) {
7019 /* apart from obvious ${VAR:999999:l},
7020 * covers ${VAR:$((-9999999)):l} - result is ""
Denys Vlasenko826360f2017-07-17 17:49:11 +02007021 * (bash compat)
Denys Vlasenko08a5dab2014-11-17 20:27:18 +01007022 */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007023 pos = 0;
7024 len = 0;
7025 }
Denys Vlasenko826360f2017-07-17 17:49:11 +02007026 if (len < 0) {
7027 /* ${VAR:N:-M} sets LEN to strlen()-M */
7028 len = (orig_len - pos) + len;
7029 }
7030 if ((unsigned)len > (orig_len - pos))
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007031 len = orig_len - pos;
7032
7033 for (str = startp; pos; str++, pos--) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01007034 if (quotes && (unsigned char)*str == CTLESC)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007035 str++;
7036 }
7037 for (loc = startp; len; len--) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01007038 if (quotes && (unsigned char)*str == CTLESC)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007039 *loc++ = *str++;
7040 *loc++ = *str++;
7041 }
7042 *loc = '\0';
7043 amount = loc - expdest;
7044 STADJUST(amount, expdest);
7045 return loc;
Denys Vlasenko826360f2017-07-17 17:49:11 +02007046 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01007047#endif /* BASH_SUBSTR */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007048 }
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02007049
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007050 resetloc = expdest - (char *)stackblock();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007051
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01007052#if BASH_PATTERN_SUBST
Denys Vlasenko740058b2018-01-09 17:01:00 +01007053 repl = NULL;
7054
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007055 /* We'll comeback here if we grow the stack while handling
7056 * a VSREPLACE or VSREPLACEALL, since our pointers into the
7057 * stack will need rebasing, and we'll need to remove our work
7058 * areas each time
7059 */
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01007060 restart:
7061#endif
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007062
7063 amount = expdest - ((char *)stackblock() + resetloc);
7064 STADJUST(-amount, expdest);
Denis Vlasenko29eb3592008-05-18 14:06:08 +00007065 startp = (char *)stackblock() + startloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007066
7067 rmesc = startp;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00007068 rmescend = (char *)stackblock() + strloc;
Denys Vlasenko740058b2018-01-09 17:01:00 +01007069 //bb_error_msg("str7:'%s'", rmescend);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007070 if (quotes) {
Denys Vlasenko740058b2018-01-09 17:01:00 +01007071//TODO: how to handle slash_pos here if string changes (shortens?)
7072 rmesc = rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW, NULL);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007073 if (rmesc != startp) {
7074 rmescend = expdest;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00007075 startp = (char *)stackblock() + startloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007076 }
7077 }
7078 rmescend--;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00007079 str = (char *)stackblock() + strloc;
Ron Yorston417622c2015-05-18 09:59:14 +02007080 /*
7081 * Example: v='a\bc'; echo ${v/\\b/_\\_\z_}
7082 * The result is a_\_z_c (not a\_\_z_c)!
7083 *
7084 * The search pattern and replace string treat backslashes differently!
Denys Vlasenko740058b2018-01-09 17:01:00 +01007085 * "&slash_pos" causes rmescapes() to work differently on the pattern
Ron Yorston417622c2015-05-18 09:59:14 +02007086 * and string. It's only used on the first call.
7087 */
Denys Vlasenko740058b2018-01-09 17:01:00 +01007088 //bb_error_msg("str8:'%s' slash_pos:%d", str, slash_pos);
7089 rmescapes(str, RMESCAPE_GLOB,
7090 repl ? NULL : (slash_pos < 0 ? NULL : &slash_pos)
7091 );
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007092
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01007093#if BASH_PATTERN_SUBST
Denys Vlasenko0b4980c2012-09-25 12:49:29 +02007094 workloc = expdest - (char *)stackblock();
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007095 if (subtype == VSREPLACE || subtype == VSREPLACEALL) {
Denys Vlasenko826360f2017-07-17 17:49:11 +02007096 int len;
Denys Vlasenkob76356b2010-03-13 16:19:04 +01007097 char *idx, *end;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007098
Denis Vlasenkod6855d12008-09-27 14:03:25 +00007099 if (!repl) {
Denys Vlasenko740058b2018-01-09 17:01:00 +01007100 //bb_error_msg("str9:'%s' slash_pos:%d", str, slash_pos);
Denys Vlasenkod1df1a72018-01-09 17:25:58 +01007101 repl = nullstr;
Denys Vlasenko740058b2018-01-09 17:01:00 +01007102 if (slash_pos >= 0) {
7103 repl = str + slash_pos;
Ron Yorston417622c2015-05-18 09:59:14 +02007104 *repl++ = '\0';
Denys Vlasenko740058b2018-01-09 17:01:00 +01007105 }
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007106 }
Ron Yorston417622c2015-05-18 09:59:14 +02007107 //bb_error_msg("str:'%s' repl:'%s'", str, repl);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007108
7109 /* If there's no pattern to match, return the expansion unmolested */
Denys Vlasenkob76356b2010-03-13 16:19:04 +01007110 if (str[0] == '\0')
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02007111 return NULL;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007112
7113 len = 0;
7114 idx = startp;
7115 end = str - 1;
7116 while (idx < end) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01007117 try_to_match:
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007118 loc = scanright(idx, rmesc, rmescend, str, quotes, 1);
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02007119 //bb_error_msg("scanright('%s'):'%s'", str, loc);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007120 if (!loc) {
7121 /* No match, advance */
Denys Vlasenkob76356b2010-03-13 16:19:04 +01007122 char *restart_detect = stackblock();
7123 skip_matching:
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007124 STPUTC(*idx, expdest);
Denys Vlasenkocd716832009-11-28 22:14:02 +01007125 if (quotes && (unsigned char)*idx == CTLESC) {
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007126 idx++;
7127 len++;
7128 STPUTC(*idx, expdest);
7129 }
7130 if (stackblock() != restart_detect)
7131 goto restart;
7132 idx++;
7133 len++;
7134 rmesc++;
Denys Vlasenkob76356b2010-03-13 16:19:04 +01007135 /* continue; - prone to quadratic behavior, smarter code: */
7136 if (idx >= end)
7137 break;
7138 if (str[0] == '*') {
7139 /* Pattern is "*foo". If "*foo" does not match "long_string",
7140 * it would never match "ong_string" etc, no point in trying.
7141 */
7142 goto skip_matching;
7143 }
7144 goto try_to_match;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007145 }
7146
7147 if (subtype == VSREPLACEALL) {
7148 while (idx < loc) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01007149 if (quotes && (unsigned char)*idx == CTLESC)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007150 idx++;
7151 idx++;
7152 rmesc++;
7153 }
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00007154 } else {
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007155 idx = loc;
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00007156 }
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007157
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02007158 //bb_error_msg("repl:'%s'", repl);
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007159 for (loc = (char*)repl; *loc; loc++) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01007160 char *restart_detect = stackblock();
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007161 if (quotes && *loc == '\\') {
7162 STPUTC(CTLESC, expdest);
7163 len++;
7164 }
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007165 STPUTC(*loc, expdest);
7166 if (stackblock() != restart_detect)
7167 goto restart;
7168 len++;
7169 }
7170
7171 if (subtype == VSREPLACE) {
Denys Vlasenkof02c82f2010-08-06 19:14:47 +02007172 //bb_error_msg("tail:'%s', quotes:%x", idx, quotes);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007173 while (*idx) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01007174 char *restart_detect = stackblock();
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007175 STPUTC(*idx, expdest);
7176 if (stackblock() != restart_detect)
7177 goto restart;
7178 len++;
7179 idx++;
7180 }
7181 break;
7182 }
7183 }
7184
7185 /* We've put the replaced text into a buffer at workloc, now
7186 * move it to the right place and adjust the stack.
7187 */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007188 STPUTC('\0', expdest);
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007189 startp = (char *)stackblock() + startloc;
7190 memmove(startp, (char *)stackblock() + workloc, len + 1);
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02007191 //bb_error_msg("startp:'%s'", startp);
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007192 amount = expdest - (startp + len);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007193 STADJUST(-amount, expdest);
7194 return startp;
7195 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01007196#endif /* BASH_PATTERN_SUBST */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007197
7198 subtype -= VSTRIMRIGHT;
7199#if DEBUG
7200 if (subtype < 0 || subtype > 7)
7201 abort();
7202#endif
Denys Vlasenkob76356b2010-03-13 16:19:04 +01007203 /* zero = (subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX) */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007204 zero = subtype >> 1;
7205 /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */
7206 scan = (subtype & 1) ^ zero ? scanleft : scanright;
7207
7208 loc = scan(startp, rmesc, rmescend, str, quotes, zero);
7209 if (loc) {
7210 if (zero) {
7211 memmove(startp, loc, str - loc);
7212 loc = startp + (str - loc) - 1;
7213 }
7214 *loc = '\0';
7215 amount = loc - expdest;
7216 STADJUST(amount, expdest);
7217 }
7218 return loc;
7219}
7220
7221/*
7222 * Add the value of a specialized variable to the stack string.
Denys Vlasenko4d8873f2009-10-04 03:14:41 +02007223 * name parameter (examples):
7224 * ash -c 'echo $1' name:'1='
7225 * ash -c 'echo $qwe' name:'qwe='
7226 * ash -c 'echo $$' name:'$='
7227 * ash -c 'echo ${$}' name:'$='
7228 * ash -c 'echo ${$##q}' name:'$=q'
7229 * ash -c 'echo ${#$}' name:'$='
7230 * note: examples with bad shell syntax:
7231 * ash -c 'echo ${#$1}' name:'$=1'
7232 * ash -c 'echo ${#1#}' name:'1=#'
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007233 */
Denys Vlasenkoadf922e2009-10-08 14:35:37 +02007234static NOINLINE ssize_t
Denys Vlasenko440da972018-08-05 14:29:58 +02007235varvalue(char *name, int varflags, int flags, int quoted)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007236{
Mike Frysinger98c52642009-04-02 10:02:37 +00007237 const char *p;
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01007238 int num;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007239 int i;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007240 ssize_t len = 0;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007241 int sep;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007242 int subtype = varflags & VSTYPE;
7243 int discard = subtype == VSPLUS || subtype == VSLENGTH;
7244 int quotes = (discard ? 0 : (flags & QUOTES_ESC)) | QUOTES_KEEPNUL;
Denys Vlasenko0aaaa502016-10-02 02:46:56 +02007245 int syntax;
7246
7247 sep = (flags & EXP_FULL) << CHAR_BIT;
7248 syntax = quoted ? DQSYNTAX : BASESYNTAX;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007249
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007250 switch (*name) {
7251 case '$':
7252 num = rootpid;
7253 goto numvar;
7254 case '?':
7255 num = exitstatus;
7256 goto numvar;
7257 case '#':
7258 num = shellparam.nparam;
7259 goto numvar;
7260 case '!':
7261 num = backgndpid;
7262 if (num == 0)
7263 return -1;
7264 numvar:
7265 len = cvtnum(num);
Denys Vlasenko4d8873f2009-10-04 03:14:41 +02007266 goto check_1char_name;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007267 case '-':
Mike Frysinger98c52642009-04-02 10:02:37 +00007268 expdest = makestrspace(NOPTS, expdest);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007269 for (i = NOPTS - 1; i >= 0; i--) {
Martijn Dekkerad4e9612018-03-31 18:15:59 +02007270 if (optlist[i] && optletters(i)) {
Mike Frysinger98c52642009-04-02 10:02:37 +00007271 USTPUTC(optletters(i), expdest);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007272 len++;
7273 }
7274 }
Denys Vlasenko4d8873f2009-10-04 03:14:41 +02007275 check_1char_name:
7276#if 0
7277 /* handles cases similar to ${#$1} */
7278 if (name[2] != '\0')
7279 raise_error_syntax("bad substitution");
7280#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007281 break;
Denys Vlasenko0aaaa502016-10-02 02:46:56 +02007282 case '@':
7283 if (quoted && sep)
7284 goto param;
7285 /* fall through */
7286 case '*': {
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01007287 char **ap;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007288 char sepc;
Denys Vlasenko440da972018-08-05 14:29:58 +02007289 char c;
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01007290
Denys Vlasenko440da972018-08-05 14:29:58 +02007291 /* We will set c to 0 or ~0 depending on whether
7292 * we're doing field splitting. We won't do field
7293 * splitting if either we're quoted or sep is zero.
7294 *
7295 * Instead of testing (quoted || !sep) the following
7296 * trick optimises away any branches by using the
7297 * fact that EXP_QUOTED (which is the only bit that
7298 * can be set in quoted) is the same as EXP_FULL <<
7299 * CHAR_BIT (which is the only bit that can be set
7300 * in sep).
7301 */
7302#if EXP_QUOTED >> CHAR_BIT != EXP_FULL
7303#error The following two lines expect EXP_QUOTED == EXP_FULL << CHAR_BIT
7304#endif
7305 c = !((quoted | ~sep) & EXP_QUOTED) - 1;
7306 sep &= ~quoted;
7307 sep |= ifsset() ? (unsigned char)(c & ifsval()[0]) : ' ';
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007308 param:
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007309 sepc = sep;
Denys Vlasenko0dd8e452016-10-01 21:02:06 +02007310 ap = shellparam.p;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007311 if (!ap)
7312 return -1;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02007313 while ((p = *ap++) != NULL) {
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007314 len += strtodest(p, syntax, quotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007315
7316 if (*ap && sep) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007317 len++;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007318 memtodest(&sepc, 1, syntax, quotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007319 }
7320 }
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007321 break;
Denys Vlasenko0aaaa502016-10-02 02:46:56 +02007322 } /* case '*' */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007323 case '0':
7324 case '1':
7325 case '2':
7326 case '3':
7327 case '4':
7328 case '5':
7329 case '6':
7330 case '7':
7331 case '8':
7332 case '9':
Denys Vlasenkoa00329c2009-08-30 20:05:10 +02007333 num = atoi(name); /* number(name) fails on ${N#str} etc */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007334 if (num < 0 || num > shellparam.nparam)
7335 return -1;
7336 p = num ? shellparam.p[num - 1] : arg0;
7337 goto value;
7338 default:
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00007339 /* NB: name has form "VAR=..." */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007340 p = lookupvar(name);
7341 value:
7342 if (!p)
7343 return -1;
7344
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007345 len = strtodest(p, syntax, quotes);
Denys Vlasenkoc76236f2014-12-29 00:04:18 +01007346#if ENABLE_UNICODE_SUPPORT
7347 if (subtype == VSLENGTH && len > 0) {
7348 reinit_unicode_for_ash();
7349 if (unicode_status == UNICODE_ON) {
Ron Yorston3e3bfb82016-03-18 11:29:19 +00007350 STADJUST(-len, expdest);
7351 discard = 0;
Denys Vlasenkoc76236f2014-12-29 00:04:18 +01007352 len = unicode_strlen(p);
7353 }
7354 }
7355#endif
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007356 break;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007357 }
7358
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007359 if (discard)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007360 STADJUST(-len, expdest);
7361 return len;
7362}
7363
7364/*
7365 * Expand a variable, and return a pointer to the next character in the
7366 * input string.
7367 */
7368static char *
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02007369evalvar(char *p, int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007370{
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00007371 char varflags;
7372 char subtype;
Ron Yorston549deab2015-05-18 09:57:51 +02007373 int quoted;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007374 char *var;
7375 int patloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007376 int startloc;
7377 ssize_t varlen;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007378
Denys Vlasenkob0d63382009-09-16 16:18:32 +02007379 varflags = (unsigned char) *p++;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007380 subtype = varflags & VSTYPE;
Denys Vlasenko88e15702016-10-26 01:55:56 +02007381
7382 if (!subtype)
7383 raise_error_syntax("bad substitution");
7384
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007385 quoted = flag & EXP_QUOTED;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007386 var = p;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007387 startloc = expdest - (char *)stackblock();
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02007388 p = strchr(p, '=') + 1; //TODO: use var_end(p)?
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007389
7390 again:
Denys Vlasenko440da972018-08-05 14:29:58 +02007391 varlen = varvalue(var, varflags, flag, quoted);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007392 if (varflags & VSNUL)
7393 varlen--;
7394
7395 if (subtype == VSPLUS) {
7396 varlen = -1 - varlen;
7397 goto vsplus;
7398 }
7399
7400 if (subtype == VSMINUS) {
7401 vsplus:
7402 if (varlen < 0) {
7403 argstr(
Denys Vlasenko6040fe82010-09-12 15:03:16 +02007404 p,
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02007405 flag | EXP_TILDE | EXP_WORD
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007406 );
7407 goto end;
7408 }
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007409 goto record;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007410 }
7411
7412 if (subtype == VSASSIGN || subtype == VSQUESTION) {
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007413 if (varlen >= 0)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007414 goto record;
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007415
7416 subevalvar(p, var, 0, subtype, startloc, varflags,
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02007417 flag & ~QUOTES_ESC);
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007418 varflags &= ~VSNUL;
7419 /*
7420 * Remove any recorded regions beyond
7421 * start of variable
7422 */
7423 removerecordregions(startloc);
7424 goto again;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007425 }
7426
7427 if (varlen < 0 && uflag)
7428 varunset(p, var, 0, 0);
7429
7430 if (subtype == VSLENGTH) {
Denys Vlasenkoc76236f2014-12-29 00:04:18 +01007431 cvtnum(varlen > 0 ? varlen : 0);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007432 goto record;
7433 }
7434
7435 if (subtype == VSNORMAL) {
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007436 record:
Denys Vlasenko440da972018-08-05 14:29:58 +02007437 if (quoted) {
7438 quoted = *var == '@' && shellparam.nparam;
7439 if (!quoted)
7440 goto end;
7441 }
Denys Vlasenko0dd8e452016-10-01 21:02:06 +02007442 recordregion(startloc, expdest - (char *)stackblock(), quoted);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007443 goto end;
7444 }
7445
7446#if DEBUG
7447 switch (subtype) {
7448 case VSTRIMLEFT:
7449 case VSTRIMLEFTMAX:
7450 case VSTRIMRIGHT:
7451 case VSTRIMRIGHTMAX:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01007452#if BASH_SUBSTR
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007453 case VSSUBSTR:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01007454#endif
7455#if BASH_PATTERN_SUBST
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007456 case VSREPLACE:
7457 case VSREPLACEALL:
7458#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007459 break;
7460 default:
7461 abort();
7462 }
7463#endif
7464
7465 if (varlen >= 0) {
7466 /*
7467 * Terminate the string and start recording the pattern
7468 * right after it
7469 */
7470 STPUTC('\0', expdest);
7471 patloc = expdest - (char *)stackblock();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02007472 if (NULL == subevalvar(p, /* varname: */ NULL, patloc, subtype,
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02007473 startloc, varflags, flag)) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007474 int amount = expdest - (
7475 (char *)stackblock() + patloc - 1
7476 );
7477 STADJUST(-amount, expdest);
7478 }
7479 /* Remove any recorded regions beyond start of variable */
7480 removerecordregions(startloc);
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007481 goto record;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007482 }
7483
7484 end:
7485 if (subtype != VSNORMAL) { /* skip to end of alternative */
7486 int nesting = 1;
7487 for (;;) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01007488 unsigned char c = *p++;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007489 if (c == CTLESC)
7490 p++;
Ron Yorston549deab2015-05-18 09:57:51 +02007491 else if (c == CTLBACKQ) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007492 if (varlen >= 0)
7493 argbackq = argbackq->next;
7494 } else if (c == CTLVAR) {
7495 if ((*p++ & VSTYPE) != VSNORMAL)
7496 nesting++;
7497 } else if (c == CTLENDVAR) {
7498 if (--nesting == 0)
7499 break;
7500 }
7501 }
7502 }
7503 return p;
7504}
7505
7506/*
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007507 * Add a file name to the list.
7508 */
7509static void
7510addfname(const char *name)
7511{
7512 struct strlist *sp;
7513
Denis Vlasenko597906c2008-02-20 16:38:54 +00007514 sp = stzalloc(sizeof(*sp));
Denys Vlasenko8e2bc472016-09-28 23:02:57 +02007515 sp->text = sstrdup(name);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007516 *exparg.lastp = sp;
7517 exparg.lastp = &sp->next;
7518}
7519
Felix Fietkaub5b21122017-01-31 21:58:55 +01007520/* Avoid glob() (and thus, stat() et al) for words like "echo" */
7521static int
7522hasmeta(const char *p)
7523{
7524 static const char chars[] ALIGN1 = {
7525 '*', '?', '[', '\\', CTLQUOTEMARK, CTLESC, 0
7526 };
7527
7528 for (;;) {
7529 p = strpbrk(p, chars);
7530 if (!p)
7531 break;
Denys Vlasenkoac61f442018-03-30 23:03:29 +02007532 switch ((unsigned char)*p) {
Felix Fietkaub5b21122017-01-31 21:58:55 +01007533 case CTLQUOTEMARK:
7534 for (;;) {
7535 p++;
Denys Vlasenkoac61f442018-03-30 23:03:29 +02007536 if ((unsigned char)*p == CTLQUOTEMARK)
Felix Fietkaub5b21122017-01-31 21:58:55 +01007537 break;
Denys Vlasenkoac61f442018-03-30 23:03:29 +02007538 if ((unsigned char)*p == CTLESC)
Felix Fietkaub5b21122017-01-31 21:58:55 +01007539 p++;
7540 if (*p == '\0') /* huh? */
7541 return 0;
7542 }
7543 break;
7544 case '\\':
7545 case CTLESC:
7546 p++;
7547 if (*p == '\0')
7548 return 0;
7549 break;
7550 case '[':
7551 if (!strchr(p + 1, ']')) {
7552 /* It's not a properly closed [] pattern,
7553 * but other metas may follow. Continue checking.
7554 * my[file* _is_ globbed by bash
7555 * and matches filenames like "my[file1".
7556 */
7557 break;
7558 }
7559 /* fallthrough */
7560 default:
7561 /* case '*': */
7562 /* case '?': */
7563 return 1;
7564 }
7565 p++;
7566 }
7567
7568 return 0;
7569}
7570
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007571/* If we want to use glob() from libc... */
Denys Vlasenko514b51d2016-10-01 14:33:08 +02007572#if !ENABLE_ASH_INTERNAL_GLOB
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007573
7574/* Add the result of glob() to the list */
7575static void
7576addglob(const glob_t *pglob)
7577{
7578 char **p = pglob->gl_pathv;
7579
7580 do {
7581 addfname(*p);
7582 } while (*++p);
7583}
7584static void
7585expandmeta(struct strlist *str /*, int flag*/)
7586{
7587 /* TODO - EXP_REDIR */
7588
7589 while (str) {
7590 char *p;
7591 glob_t pglob;
7592 int i;
7593
7594 if (fflag)
7595 goto nometa;
Denys Vlasenkod4f3db92016-10-30 18:41:01 +01007596
Felix Fietkaub5b21122017-01-31 21:58:55 +01007597 if (!hasmeta(str->text))
7598 goto nometa;
Denys Vlasenkod4f3db92016-10-30 18:41:01 +01007599
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007600 INT_OFF;
7601 p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP);
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007602// GLOB_NOMAGIC (GNU): if no *?[ chars in pattern, return it even if no match
7603// GLOB_NOCHECK: if no match, return unchanged pattern (sans \* escapes?)
7604//
7605// glibc 2.24.90 glob(GLOB_NOMAGIC) does not remove backslashes used for escaping:
7606// if you pass it "file\?", it returns "file\?", not "file?", if no match.
7607// Which means you need to unescape the string, right? Not so fast:
7608// if there _is_ a file named "file\?" (with backslash), it is returned
7609// as "file\?" too (whichever pattern you used to find it, say, "file*").
Denys Vlasenko10ad6222017-04-17 16:13:32 +02007610// You DON'T KNOW by looking at the result whether you need to unescape it.
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007611//
7612// Worse, globbing of "file\?" in a directory with two files, "file?" and "file\?",
7613// returns "file\?" - which is WRONG: "file\?" pattern matches "file?" file.
7614// Without GLOB_NOMAGIC, this works correctly ("file?" is returned as a match).
7615// With GLOB_NOMAGIC | GLOB_NOCHECK, this also works correctly.
7616// i = glob(p, GLOB_NOMAGIC | GLOB_NOCHECK, NULL, &pglob);
7617// i = glob(p, GLOB_NOMAGIC, NULL, &pglob);
7618 i = glob(p, 0, NULL, &pglob);
7619 //bb_error_msg("glob('%s'):%d '%s'...", p, i, pglob.gl_pathv ? pglob.gl_pathv[0] : "-");
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007620 if (p != str->text)
7621 free(p);
7622 switch (i) {
7623 case 0:
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007624#if 0 // glibc 2.24.90 bug? Patterns like "*/file", when match, don't set GLOB_MAGCHAR
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007625 /* GLOB_MAGCHAR is set if *?[ chars were seen (GNU) */
7626 if (!(pglob.gl_flags & GLOB_MAGCHAR))
7627 goto nometa2;
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007628#endif
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007629 addglob(&pglob);
7630 globfree(&pglob);
7631 INT_ON;
7632 break;
7633 case GLOB_NOMATCH:
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007634 //nometa2:
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007635 globfree(&pglob);
7636 INT_ON;
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007637 nometa:
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007638 *exparg.lastp = str;
Denys Vlasenko740058b2018-01-09 17:01:00 +01007639 rmescapes(str->text, 0, NULL);
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007640 exparg.lastp = &str->next;
7641 break;
7642 default: /* GLOB_NOSPACE */
7643 globfree(&pglob);
7644 INT_ON;
7645 ash_msg_and_raise_error(bb_msg_memory_exhausted);
7646 }
7647 str = str->next;
7648 }
7649}
7650
7651#else
Denys Vlasenko514b51d2016-10-01 14:33:08 +02007652/* ENABLE_ASH_INTERNAL_GLOB: Homegrown globbing code. (dash also has both, uses homegrown one.) */
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007653
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007654/*
7655 * Do metacharacter (i.e. *, ?, [...]) expansion.
7656 */
Denys Vlasenkod5f50452018-04-14 14:50:47 +02007657typedef struct exp_t {
7658 char *dir;
7659 unsigned dir_max;
7660} exp_t;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007661static void
Denys Vlasenkod5f50452018-04-14 14:50:47 +02007662expmeta(exp_t *exp, char *name, unsigned name_len, unsigned expdir_len)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007663{
Denys Vlasenkod5f50452018-04-14 14:50:47 +02007664#define expdir exp->dir
7665#define expdir_max exp->dir_max
7666 char *enddir = expdir + expdir_len;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007667 char *p;
7668 const char *cp;
7669 char *start;
7670 char *endname;
7671 int metaflag;
7672 struct stat statb;
7673 DIR *dirp;
7674 struct dirent *dp;
7675 int atend;
7676 int matchdot;
Ron Yorstonca25af92015-09-04 10:32:41 +01007677 int esc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007678
7679 metaflag = 0;
7680 start = name;
Ron Yorstonca25af92015-09-04 10:32:41 +01007681 for (p = name; esc = 0, *p; p += esc + 1) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007682 if (*p == '*' || *p == '?')
7683 metaflag = 1;
7684 else if (*p == '[') {
7685 char *q = p + 1;
7686 if (*q == '!')
7687 q++;
7688 for (;;) {
7689 if (*q == '\\')
7690 q++;
7691 if (*q == '/' || *q == '\0')
7692 break;
7693 if (*++q == ']') {
7694 metaflag = 1;
7695 break;
7696 }
7697 }
Ron Yorstonca25af92015-09-04 10:32:41 +01007698 } else {
Denys Vlasenkoeb54ca82018-08-07 18:54:52 +02007699 if (*p == '\\' && p[1])
Ron Yorstonca25af92015-09-04 10:32:41 +01007700 esc++;
7701 if (p[esc] == '/') {
7702 if (metaflag)
7703 break;
7704 start = p + esc + 1;
7705 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007706 }
7707 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007708 if (metaflag == 0) { /* we've reached the end of the file name */
Denys Vlasenkod5f50452018-04-14 14:50:47 +02007709 if (!expdir_len)
7710 return;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007711 p = name;
7712 do {
Denys Vlasenkoeb54ca82018-08-07 18:54:52 +02007713 if (*p == '\\' && p[1])
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007714 p++;
7715 *enddir++ = *p;
7716 } while (*p++);
Denys Vlasenkod5f50452018-04-14 14:50:47 +02007717 if (lstat(expdir, &statb) == 0)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007718 addfname(expdir);
7719 return;
7720 }
7721 endname = p;
7722 if (name < start) {
7723 p = name;
7724 do {
Denys Vlasenkoeb54ca82018-08-07 18:54:52 +02007725 if (*p == '\\' && p[1])
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007726 p++;
7727 *enddir++ = *p++;
7728 } while (p < start);
7729 }
Denys Vlasenkod5f50452018-04-14 14:50:47 +02007730 *enddir = '\0';
7731 cp = expdir;
7732 expdir_len = enddir - cp;
7733 if (!expdir_len)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007734 cp = ".";
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007735 dirp = opendir(cp);
7736 if (dirp == NULL)
7737 return;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007738 if (*endname == 0) {
7739 atend = 1;
7740 } else {
7741 atend = 0;
Ron Yorstonca25af92015-09-04 10:32:41 +01007742 *endname = '\0';
7743 endname += esc + 1;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007744 }
Denys Vlasenkod5f50452018-04-14 14:50:47 +02007745 name_len -= endname - name;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007746 matchdot = 0;
7747 p = start;
7748 if (*p == '\\')
7749 p++;
7750 if (*p == '.')
7751 matchdot++;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02007752 while (!pending_int && (dp = readdir(dirp)) != NULL) {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00007753 if (dp->d_name[0] == '.' && !matchdot)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007754 continue;
7755 if (pmatch(start, dp->d_name)) {
7756 if (atend) {
7757 strcpy(enddir, dp->d_name);
7758 addfname(expdir);
7759 } else {
Denys Vlasenkod5f50452018-04-14 14:50:47 +02007760 unsigned offset;
7761 unsigned len;
7762
7763 p = stpcpy(enddir, dp->d_name);
7764 *p = '/';
7765
7766 offset = p - expdir + 1;
7767 len = offset + name_len + NAME_MAX;
7768 if (len > expdir_max) {
7769 len += PATH_MAX;
7770 expdir = ckrealloc(expdir, len);
7771 expdir_max = len;
7772 }
7773
7774 expmeta(exp, endname, name_len, offset);
7775 enddir = expdir + expdir_len;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007776 }
7777 }
7778 }
7779 closedir(dirp);
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00007780 if (!atend)
Ron Yorstonca25af92015-09-04 10:32:41 +01007781 endname[-esc - 1] = esc ? '\\' : '/';
Denys Vlasenkod5f50452018-04-14 14:50:47 +02007782#undef expdir
7783#undef expdir_max
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007784}
7785
7786static struct strlist *
7787msort(struct strlist *list, int len)
7788{
7789 struct strlist *p, *q = NULL;
7790 struct strlist **lpp;
7791 int half;
7792 int n;
7793
7794 if (len <= 1)
7795 return list;
7796 half = len >> 1;
7797 p = list;
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +00007798 for (n = half; --n >= 0;) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007799 q = p;
7800 p = p->next;
7801 }
7802 q->next = NULL; /* terminate first half of list */
7803 q = msort(list, half); /* sort first half of list */
7804 p = msort(p, len - half); /* sort second half */
7805 lpp = &list;
7806 for (;;) {
7807#if ENABLE_LOCALE_SUPPORT
7808 if (strcoll(p->text, q->text) < 0)
7809#else
7810 if (strcmp(p->text, q->text) < 0)
7811#endif
7812 {
7813 *lpp = p;
7814 lpp = &p->next;
7815 p = *lpp;
7816 if (p == NULL) {
7817 *lpp = q;
7818 break;
7819 }
7820 } else {
7821 *lpp = q;
7822 lpp = &q->next;
7823 q = *lpp;
7824 if (q == NULL) {
7825 *lpp = p;
7826 break;
7827 }
7828 }
7829 }
7830 return list;
7831}
7832
7833/*
7834 * Sort the results of file name expansion. It calculates the number of
7835 * strings to sort and then calls msort (short for merge sort) to do the
7836 * work.
7837 */
7838static struct strlist *
7839expsort(struct strlist *str)
7840{
7841 int len;
7842 struct strlist *sp;
7843
7844 len = 0;
7845 for (sp = str; sp; sp = sp->next)
7846 len++;
7847 return msort(str, len);
7848}
7849
7850static void
Denis Vlasenko68404f12008-03-17 09:00:54 +00007851expandmeta(struct strlist *str /*, int flag*/)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007852{
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007853 /* TODO - EXP_REDIR */
7854
7855 while (str) {
Denys Vlasenkod5f50452018-04-14 14:50:47 +02007856 exp_t exp;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007857 struct strlist **savelastp;
7858 struct strlist *sp;
7859 char *p;
Denys Vlasenkod5f50452018-04-14 14:50:47 +02007860 unsigned len;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007861
7862 if (fflag)
7863 goto nometa;
Felix Fietkaub5b21122017-01-31 21:58:55 +01007864 if (!hasmeta(str->text))
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007865 goto nometa;
7866 savelastp = exparg.lastp;
7867
7868 INT_OFF;
Ron Yorston549deab2015-05-18 09:57:51 +02007869 p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP);
Denys Vlasenkod5f50452018-04-14 14:50:47 +02007870 len = strlen(p);
7871 exp.dir_max = len + PATH_MAX;
7872 exp.dir = ckmalloc(exp.dir_max);
7873
7874 expmeta(&exp, p, len, 0);
7875 free(exp.dir);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007876 if (p != str->text)
7877 free(p);
7878 INT_ON;
7879 if (exparg.lastp == savelastp) {
7880 /*
7881 * no matches
7882 */
7883 nometa:
7884 *exparg.lastp = str;
Denys Vlasenko740058b2018-01-09 17:01:00 +01007885 rmescapes(str->text, 0, NULL);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007886 exparg.lastp = &str->next;
7887 } else {
7888 *exparg.lastp = NULL;
7889 *savelastp = sp = expsort(*savelastp);
7890 while (sp->next != NULL)
7891 sp = sp->next;
7892 exparg.lastp = &sp->next;
7893 }
7894 str = str->next;
7895 }
7896}
Denys Vlasenko514b51d2016-10-01 14:33:08 +02007897#endif /* ENABLE_ASH_INTERNAL_GLOB */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007898
7899/*
7900 * Perform variable substitution and command substitution on an argument,
7901 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
7902 * perform splitting and file name expansion. When arglist is NULL, perform
7903 * here document expansion.
7904 */
7905static void
7906expandarg(union node *arg, struct arglist *arglist, int flag)
7907{
7908 struct strlist *sp;
7909 char *p;
7910
7911 argbackq = arg->narg.backquote;
7912 STARTSTACKSTR(expdest);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02007913 TRACE(("expandarg: argstr('%s',flags:%x)\n", arg->narg.text, flag));
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02007914 argstr(arg->narg.text, flag);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007915 p = _STPUTC('\0', expdest);
7916 expdest = p - 1;
7917 if (arglist == NULL) {
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02007918 /* here document expanded */
7919 goto out;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007920 }
7921 p = grabstackstr(p);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02007922 TRACE(("expandarg: p:'%s'\n", p));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007923 exparg.lastp = &exparg.list;
7924 /*
7925 * TODO - EXP_REDIR
7926 */
7927 if (flag & EXP_FULL) {
7928 ifsbreakup(p, &exparg);
7929 *exparg.lastp = NULL;
7930 exparg.lastp = &exparg.list;
Denis Vlasenko68404f12008-03-17 09:00:54 +00007931 expandmeta(exparg.list /*, flag*/);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007932 } else {
Denis Vlasenko597906c2008-02-20 16:38:54 +00007933 sp = stzalloc(sizeof(*sp));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007934 sp->text = p;
7935 *exparg.lastp = sp;
7936 exparg.lastp = &sp->next;
7937 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007938 *exparg.lastp = NULL;
7939 if (exparg.list) {
7940 *arglist->lastp = exparg.list;
7941 arglist->lastp = exparg.lastp;
7942 }
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02007943
7944 out:
7945 ifsfree();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007946}
7947
7948/*
7949 * Expand shell variables and backquotes inside a here document.
7950 */
7951static void
7952expandhere(union node *arg, int fd)
7953{
Ron Yorston549deab2015-05-18 09:57:51 +02007954 expandarg(arg, (struct arglist *)NULL, EXP_QUOTED);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007955 full_write(fd, stackblock(), expdest - (char *)stackblock());
7956}
7957
7958/*
7959 * Returns true if the pattern matches the string.
7960 */
7961static int
7962patmatch(char *pattern, const char *string)
7963{
Denys Vlasenkobd43c672017-07-05 23:12:15 +02007964 char *p = preglob(pattern, 0);
Denys Vlasenko4476c702017-08-15 15:27:41 +02007965 int r = pmatch(p, string);
7966 //bb_error_msg("!fnmatch(pattern:'%s',str:'%s',0):%d", p, string, r);
7967 return r;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007968}
7969
7970/*
7971 * See if a pattern matches in a case statement.
7972 */
7973static int
7974casematch(union node *pattern, char *val)
7975{
7976 struct stackmark smark;
7977 int result;
7978
7979 setstackmark(&smark);
7980 argbackq = pattern->narg.backquote;
7981 STARTSTACKSTR(expdest);
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02007982 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007983 STACKSTRNUL(expdest);
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02007984 ifsfree();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007985 result = patmatch(stackblock(), val);
7986 popstackmark(&smark);
7987 return result;
7988}
7989
7990
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007991/* ============ find_command */
7992
7993struct builtincmd {
7994 const char *name;
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02007995 int (*builtin)(int, char **) FAST_FUNC;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007996 /* unsigned flags; */
7997};
7998#define IS_BUILTIN_SPECIAL(b) ((b)->name[0] & 1)
Denis Vlasenkoe26b2782008-02-12 07:40:29 +00007999/* "regular" builtins always take precedence over commands,
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008000 * regardless of PATH=....%builtin... position */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008001#define IS_BUILTIN_REGULAR(b) ((b)->name[0] & 2)
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008002#define IS_BUILTIN_ASSIGN(b) ((b)->name[0] & 4)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008003
8004struct cmdentry {
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00008005 smallint cmdtype; /* CMDxxx */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008006 union param {
8007 int index;
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00008008 /* index >= 0 for commands without path (slashes) */
8009 /* (TODO: what exactly does the value mean? PATH position?) */
8010 /* index == -1 for commands with slashes */
8011 /* index == (-2 - applet_no) for NOFORK applets */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008012 const struct builtincmd *cmd;
8013 struct funcnode *func;
8014 } u;
8015};
8016/* values of cmdtype */
8017#define CMDUNKNOWN -1 /* no entry in table for command */
8018#define CMDNORMAL 0 /* command is an executable program */
8019#define CMDFUNCTION 1 /* command is a shell function */
8020#define CMDBUILTIN 2 /* command is a shell builtin */
8021
8022/* action to find_command() */
8023#define DO_ERR 0x01 /* prints errors */
8024#define DO_ABS 0x02 /* checks absolute paths */
8025#define DO_NOFUNC 0x04 /* don't return shell functions, for command */
8026#define DO_ALTPATH 0x08 /* using alternate path */
8027#define DO_ALTBLTIN 0x20 /* %builtin in alt. path */
8028
8029static void find_command(char *, struct cmdentry *, int, const char *);
8030
8031
8032/* ============ Hashing commands */
8033
8034/*
8035 * When commands are first encountered, they are entered in a hash table.
8036 * This ensures that a full path search will not have to be done for them
8037 * on each invocation.
8038 *
8039 * We should investigate converting to a linear search, even though that
8040 * would make the command name "hash" a misnomer.
8041 */
8042
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008043struct tblentry {
8044 struct tblentry *next; /* next entry in hash chain */
8045 union param param; /* definition of builtin function */
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00008046 smallint cmdtype; /* CMDxxx */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008047 char rehash; /* if set, cd done since entry created */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00008048 char cmdname[1]; /* name of command */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008049};
8050
Denis Vlasenko01631112007-12-16 17:20:38 +00008051static struct tblentry **cmdtable;
8052#define INIT_G_cmdtable() do { \
8053 cmdtable = xzalloc(CMDTABLESIZE * sizeof(cmdtable[0])); \
8054} while (0)
8055
8056static int builtinloc = -1; /* index in path of %builtin, or -1 */
8057
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008058
8059static void
Denys Vlasenko00a1dbd2017-07-29 01:20:53 +02008060tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) const char *cmd, char **argv, char **envp)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008061{
Denis Vlasenko80d14be2007-04-10 23:03:30 +00008062#if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00008063 if (applet_no >= 0) {
Denis Vlasenkob7304742008-10-20 08:15:51 +00008064 if (APPLET_IS_NOEXEC(applet_no)) {
Denys Vlasenko7df28bb2010-06-18 14:23:47 +02008065 clearenv();
Denis Vlasenkob7304742008-10-20 08:15:51 +00008066 while (*envp)
8067 putenv(*envp++);
Denys Vlasenko035486c2017-07-31 04:09:19 +02008068 popredir(/*drop:*/ 1);
Denys Vlasenko80e8e3c2017-08-07 19:24:57 +02008069 run_noexec_applet_and_exit(applet_no, cmd, argv);
Denis Vlasenkob7304742008-10-20 08:15:51 +00008070 }
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00008071 /* re-exec ourselves with the new arguments */
8072 execve(bb_busybox_exec_path, argv, envp);
8073 /* If they called chroot or otherwise made the binary no longer
8074 * executable, fall through */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008075 }
8076#endif
8077
8078 repeat:
8079#ifdef SYSV
8080 do {
8081 execve(cmd, argv, envp);
8082 } while (errno == EINTR);
8083#else
8084 execve(cmd, argv, envp);
8085#endif
Ron Yorstonca82b532018-11-01 11:45:03 +01008086
Denys Vlasenko00a1dbd2017-07-29 01:20:53 +02008087 if (cmd != bb_busybox_exec_path && errno == ENOEXEC) {
Denys Vlasenkoaefe1c22011-03-07 12:02:40 +01008088 /* Run "cmd" as a shell script:
8089 * http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html
8090 * "If the execve() function fails with ENOEXEC, the shell
8091 * shall execute a command equivalent to having a shell invoked
8092 * with the command name as its first operand,
8093 * with any remaining arguments passed to the new shell"
8094 *
8095 * That is, do not use $SHELL, user's shell, or /bin/sh;
8096 * just call ourselves.
Denys Vlasenko2bef5262011-12-16 00:25:17 +01008097 *
8098 * Note that bash reads ~80 chars of the file, and if it sees
8099 * a zero byte before it sees newline, it doesn't try to
8100 * interpret it, but fails with "cannot execute binary file"
Denys Vlasenkocda6ea92011-12-16 00:44:36 +01008101 * message and exit code 126. For one, this prevents attempts
8102 * to interpret foreign ELF binaries as shell scripts.
Denys Vlasenkoaefe1c22011-03-07 12:02:40 +01008103 */
Denys Vlasenko00a1dbd2017-07-29 01:20:53 +02008104 argv[0] = (char*) cmd;
8105 cmd = bb_busybox_exec_path;
Denys Vlasenko65a8b852016-10-26 22:29:11 +02008106 /* NB: this is only possible because all callers of shellexec()
8107 * ensure that the argv[-1] slot exists!
8108 */
8109 argv--;
8110 argv[0] = (char*) "ash";
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008111 goto repeat;
8112 }
8113}
8114
8115/*
8116 * Exec a program. Never returns. If you change this routine, you may
8117 * have to change the find_command routine as well.
Denys Vlasenko65a8b852016-10-26 22:29:11 +02008118 * argv[-1] must exist and be writable! See tryexec() for why.
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008119 */
Denys Vlasenkoe139ae32017-04-12 21:02:33 +02008120static void shellexec(char *prog, char **argv, const char *path, int idx) NORETURN;
8121static void shellexec(char *prog, char **argv, const char *path, int idx)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008122{
8123 char *cmdname;
8124 int e;
8125 char **envp;
8126 int exerrno;
Denys Vlasenko83f103b2011-12-20 06:10:35 +01008127 int applet_no = -1; /* used only by FEATURE_SH_STANDALONE */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008128
Denys Vlasenkoa5060b82017-11-03 14:16:25 +01008129 envp = listvars(VEXPORT, VUNSET, /*strlist:*/ NULL, /*end:*/ NULL);
Denys Vlasenkoe139ae32017-04-12 21:02:33 +02008130 if (strchr(prog, '/') != NULL
Denis Vlasenko80d14be2007-04-10 23:03:30 +00008131#if ENABLE_FEATURE_SH_STANDALONE
Denys Vlasenkoe139ae32017-04-12 21:02:33 +02008132 || (applet_no = find_applet_by_name(prog)) >= 0
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008133#endif
8134 ) {
Denys Vlasenkoe139ae32017-04-12 21:02:33 +02008135 tryexec(IF_FEATURE_SH_STANDALONE(applet_no,) prog, argv, envp);
Denys Vlasenko83f103b2011-12-20 06:10:35 +01008136 if (applet_no >= 0) {
8137 /* We tried execing ourself, but it didn't work.
8138 * Maybe /proc/self/exe doesn't exist?
8139 * Try $PATH search.
8140 */
8141 goto try_PATH;
8142 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008143 e = errno;
8144 } else {
Denys Vlasenko83f103b2011-12-20 06:10:35 +01008145 try_PATH:
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008146 e = ENOENT;
Denys Vlasenkoe139ae32017-04-12 21:02:33 +02008147 while ((cmdname = path_advance(&path, prog)) != NULL) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008148 if (--idx < 0 && pathopt == NULL) {
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00008149 tryexec(IF_FEATURE_SH_STANDALONE(-1,) cmdname, argv, envp);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008150 if (errno != ENOENT && errno != ENOTDIR)
8151 e = errno;
8152 }
8153 stunalloc(cmdname);
8154 }
8155 }
8156
8157 /* Map to POSIX errors */
8158 switch (e) {
Denys Vlasenko2596f412018-08-05 18:04:09 +02008159 default:
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008160 exerrno = 126;
8161 break;
Denys Vlasenko2596f412018-08-05 18:04:09 +02008162 case ELOOP:
8163 case ENAMETOOLONG:
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008164 case ENOENT:
Denys Vlasenko2596f412018-08-05 18:04:09 +02008165 case ENOTDIR:
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008166 exerrno = 127;
8167 break;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008168 }
8169 exitstatus = exerrno;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02008170 TRACE(("shellexec failed for %s, errno %d, suppress_int %d\n",
Denys Vlasenkoe139ae32017-04-12 21:02:33 +02008171 prog, e, suppress_int));
8172 ash_msg_and_raise(EXEXIT, "%s: %s", prog, errmsg(e, "not found"));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008173 /* NOTREACHED */
8174}
8175
8176static void
8177printentry(struct tblentry *cmdp)
8178{
8179 int idx;
8180 const char *path;
8181 char *name;
8182
8183 idx = cmdp->param.index;
8184 path = pathval();
8185 do {
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02008186 name = path_advance(&path, cmdp->cmdname);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008187 stunalloc(name);
8188 } while (--idx >= 0);
8189 out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr));
8190}
8191
8192/*
8193 * Clear out command entries. The argument specifies the first entry in
8194 * PATH which has changed.
8195 */
8196static void
8197clearcmdentry(int firstchange)
8198{
8199 struct tblentry **tblp;
8200 struct tblentry **pp;
8201 struct tblentry *cmdp;
8202
8203 INT_OFF;
8204 for (tblp = cmdtable; tblp < &cmdtable[CMDTABLESIZE]; tblp++) {
8205 pp = tblp;
8206 while ((cmdp = *pp) != NULL) {
8207 if ((cmdp->cmdtype == CMDNORMAL &&
8208 cmdp->param.index >= firstchange)
8209 || (cmdp->cmdtype == CMDBUILTIN &&
8210 builtinloc >= firstchange)
8211 ) {
8212 *pp = cmdp->next;
8213 free(cmdp);
8214 } else {
8215 pp = &cmdp->next;
8216 }
8217 }
8218 }
8219 INT_ON;
8220}
8221
8222/*
8223 * Locate a command in the command hash table. If "add" is nonzero,
8224 * add the command to the table if it is not already present. The
8225 * variable "lastcmdentry" is set to point to the address of the link
8226 * pointing to the entry, so that delete_cmd_entry can delete the
8227 * entry.
8228 *
8229 * Interrupts must be off if called with add != 0.
8230 */
8231static struct tblentry **lastcmdentry;
8232
8233static struct tblentry *
8234cmdlookup(const char *name, int add)
8235{
8236 unsigned int hashval;
8237 const char *p;
8238 struct tblentry *cmdp;
8239 struct tblentry **pp;
8240
8241 p = name;
8242 hashval = (unsigned char)*p << 4;
8243 while (*p)
8244 hashval += (unsigned char)*p++;
8245 hashval &= 0x7FFF;
8246 pp = &cmdtable[hashval % CMDTABLESIZE];
8247 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
8248 if (strcmp(cmdp->cmdname, name) == 0)
8249 break;
8250 pp = &cmdp->next;
8251 }
8252 if (add && cmdp == NULL) {
Denis Vlasenkob07a4962008-06-22 13:16:23 +00008253 cmdp = *pp = ckzalloc(sizeof(struct tblentry)
8254 + strlen(name)
8255 /* + 1 - already done because
8256 * tblentry::cmdname is char[1] */);
Denis Vlasenko597906c2008-02-20 16:38:54 +00008257 /*cmdp->next = NULL; - ckzalloc did it */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008258 cmdp->cmdtype = CMDUNKNOWN;
8259 strcpy(cmdp->cmdname, name);
8260 }
8261 lastcmdentry = pp;
8262 return cmdp;
8263}
8264
8265/*
8266 * Delete the command entry returned on the last lookup.
8267 */
8268static void
8269delete_cmd_entry(void)
8270{
8271 struct tblentry *cmdp;
8272
8273 INT_OFF;
8274 cmdp = *lastcmdentry;
8275 *lastcmdentry = cmdp->next;
8276 if (cmdp->cmdtype == CMDFUNCTION)
8277 freefunc(cmdp->param.func);
8278 free(cmdp);
8279 INT_ON;
8280}
8281
8282/*
8283 * Add a new command entry, replacing any existing command entry for
8284 * the same name - except special builtins.
8285 */
8286static void
8287addcmdentry(char *name, struct cmdentry *entry)
8288{
8289 struct tblentry *cmdp;
8290
8291 cmdp = cmdlookup(name, 1);
8292 if (cmdp->cmdtype == CMDFUNCTION) {
8293 freefunc(cmdp->param.func);
8294 }
8295 cmdp->cmdtype = entry->cmdtype;
8296 cmdp->param = entry->u;
8297 cmdp->rehash = 0;
8298}
8299
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02008300static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00008301hashcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008302{
8303 struct tblentry **pp;
8304 struct tblentry *cmdp;
8305 int c;
8306 struct cmdentry entry;
8307 char *name;
8308
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008309 if (nextopt("r") != '\0') {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008310 clearcmdentry(0);
8311 return 0;
8312 }
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008313
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008314 if (*argptr == NULL) {
8315 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
8316 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
8317 if (cmdp->cmdtype == CMDNORMAL)
8318 printentry(cmdp);
8319 }
8320 }
8321 return 0;
8322 }
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008323
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008324 c = 0;
8325 while ((name = *argptr) != NULL) {
8326 cmdp = cmdlookup(name, 0);
8327 if (cmdp != NULL
8328 && (cmdp->cmdtype == CMDNORMAL
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008329 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))
8330 ) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008331 delete_cmd_entry();
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008332 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008333 find_command(name, &entry, DO_ERR, pathval());
8334 if (entry.cmdtype == CMDUNKNOWN)
8335 c = 1;
8336 argptr++;
8337 }
8338 return c;
8339}
8340
8341/*
8342 * Called when a cd is done. Marks all commands so the next time they
8343 * are executed they will be rehashed.
8344 */
8345static void
8346hashcd(void)
8347{
8348 struct tblentry **pp;
8349 struct tblentry *cmdp;
8350
8351 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
8352 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008353 if (cmdp->cmdtype == CMDNORMAL
8354 || (cmdp->cmdtype == CMDBUILTIN
Denys Vlasenkoe4dcba12010-10-28 18:57:19 +02008355 && !IS_BUILTIN_REGULAR(cmdp->param.cmd)
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008356 && builtinloc > 0)
8357 ) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008358 cmdp->rehash = 1;
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008359 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008360 }
8361 }
8362}
8363
8364/*
8365 * Fix command hash table when PATH changed.
8366 * Called before PATH is changed. The argument is the new value of PATH;
8367 * pathval() still returns the old value at this point.
8368 * Called with interrupts off.
8369 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02008370static void FAST_FUNC
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008371changepath(const char *new)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008372{
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008373 const char *old;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008374 int firstchange;
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008375 int idx;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008376 int idx_bltin;
8377
8378 old = pathval();
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008379 firstchange = 9999; /* assume no change */
8380 idx = 0;
8381 idx_bltin = -1;
8382 for (;;) {
8383 if (*old != *new) {
8384 firstchange = idx;
8385 if ((*old == '\0' && *new == ':')
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +02008386 || (*old == ':' && *new == '\0')
8387 ) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008388 firstchange++;
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +02008389 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008390 old = new; /* ignore subsequent differences */
8391 }
8392 if (*new == '\0')
8393 break;
8394 if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin"))
8395 idx_bltin = idx;
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008396 if (*new == ':')
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008397 idx++;
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +02008398 new++;
8399 old++;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008400 }
8401 if (builtinloc < 0 && idx_bltin >= 0)
8402 builtinloc = idx_bltin; /* zap builtins */
8403 if (builtinloc >= 0 && idx_bltin < 0)
8404 firstchange = 0;
8405 clearcmdentry(firstchange);
8406 builtinloc = idx_bltin;
8407}
Ron Yorston95ebcf72015-11-03 09:42:23 +00008408enum {
8409 TEOF,
8410 TNL,
8411 TREDIR,
8412 TWORD,
8413 TSEMI,
8414 TBACKGND,
8415 TAND,
8416 TOR,
8417 TPIPE,
8418 TLP,
8419 TRP,
8420 TENDCASE,
8421 TENDBQUOTE,
8422 TNOT,
8423 TCASE,
8424 TDO,
8425 TDONE,
8426 TELIF,
8427 TELSE,
8428 TESAC,
8429 TFI,
8430 TFOR,
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01008431#if BASH_FUNCTION
Ron Yorston95ebcf72015-11-03 09:42:23 +00008432 TFUNCTION,
8433#endif
8434 TIF,
8435 TIN,
8436 TTHEN,
8437 TUNTIL,
8438 TWHILE,
8439 TBEGIN,
8440 TEND
8441};
Denis Vlasenkob07a4962008-06-22 13:16:23 +00008442typedef smallint token_id_t;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008443
Denys Vlasenko888527c2016-10-02 16:54:17 +02008444/* Nth bit indicates if token marks the end of a list */
8445enum {
8446 tokendlist = 0
8447 /* 0 */ | (1u << TEOF)
8448 /* 1 */ | (0u << TNL)
8449 /* 2 */ | (0u << TREDIR)
8450 /* 3 */ | (0u << TWORD)
8451 /* 4 */ | (0u << TSEMI)
8452 /* 5 */ | (0u << TBACKGND)
8453 /* 6 */ | (0u << TAND)
8454 /* 7 */ | (0u << TOR)
8455 /* 8 */ | (0u << TPIPE)
8456 /* 9 */ | (0u << TLP)
8457 /* 10 */ | (1u << TRP)
8458 /* 11 */ | (1u << TENDCASE)
8459 /* 12 */ | (1u << TENDBQUOTE)
8460 /* 13 */ | (0u << TNOT)
8461 /* 14 */ | (0u << TCASE)
8462 /* 15 */ | (1u << TDO)
8463 /* 16 */ | (1u << TDONE)
8464 /* 17 */ | (1u << TELIF)
8465 /* 18 */ | (1u << TELSE)
8466 /* 19 */ | (1u << TESAC)
8467 /* 20 */ | (1u << TFI)
8468 /* 21 */ | (0u << TFOR)
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01008469#if BASH_FUNCTION
Denys Vlasenko888527c2016-10-02 16:54:17 +02008470 /* 22 */ | (0u << TFUNCTION)
Denys Vlasenko80729a42016-10-02 22:33:15 +02008471#endif
Denys Vlasenko888527c2016-10-02 16:54:17 +02008472 /* 23 */ | (0u << TIF)
8473 /* 24 */ | (0u << TIN)
8474 /* 25 */ | (1u << TTHEN)
8475 /* 26 */ | (0u << TUNTIL)
8476 /* 27 */ | (0u << TWHILE)
8477 /* 28 */ | (0u << TBEGIN)
8478 /* 29 */ | (1u << TEND)
8479 , /* thus far 29 bits used */
8480};
8481
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008482static const char *const tokname_array[] = {
Denys Vlasenko888527c2016-10-02 16:54:17 +02008483 "end of file",
8484 "newline",
8485 "redirection",
8486 "word",
8487 ";",
8488 "&",
8489 "&&",
8490 "||",
8491 "|",
8492 "(",
8493 ")",
8494 ";;",
8495 "`",
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008496#define KWDOFFSET 13
8497 /* the following are keywords */
Denys Vlasenko888527c2016-10-02 16:54:17 +02008498 "!",
8499 "case",
8500 "do",
8501 "done",
8502 "elif",
8503 "else",
8504 "esac",
8505 "fi",
8506 "for",
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01008507#if BASH_FUNCTION
Denys Vlasenko888527c2016-10-02 16:54:17 +02008508 "function",
Ron Yorston95ebcf72015-11-03 09:42:23 +00008509#endif
Denys Vlasenko888527c2016-10-02 16:54:17 +02008510 "if",
8511 "in",
8512 "then",
8513 "until",
8514 "while",
8515 "{",
8516 "}",
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008517};
8518
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008519/* Wrapper around strcmp for qsort/bsearch/... */
8520static int
8521pstrcmp(const void *a, const void *b)
8522{
Denys Vlasenko888527c2016-10-02 16:54:17 +02008523 return strcmp((char*)a, *(char**)b);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008524}
8525
8526static const char *const *
8527findkwd(const char *s)
8528{
8529 return bsearch(s, tokname_array + KWDOFFSET,
Denis Vlasenko80b8b392007-06-25 10:55:35 +00008530 ARRAY_SIZE(tokname_array) - KWDOFFSET,
8531 sizeof(tokname_array[0]), pstrcmp);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008532}
8533
8534/*
8535 * Locate and print what a word is...
8536 */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008537static int
Ron Yorston3f221112015-08-03 13:47:33 +01008538describe_command(char *command, const char *path, int describe_command_verbose)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008539{
8540 struct cmdentry entry;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008541#if ENABLE_ASH_ALIAS
8542 const struct alias *ap;
8543#endif
Ron Yorston3f221112015-08-03 13:47:33 +01008544
8545 path = path ? path : pathval();
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008546
8547 if (describe_command_verbose) {
8548 out1str(command);
8549 }
8550
8551 /* First look at the keywords */
8552 if (findkwd(command)) {
8553 out1str(describe_command_verbose ? " is a shell keyword" : command);
8554 goto out;
8555 }
8556
8557#if ENABLE_ASH_ALIAS
8558 /* Then look at the aliases */
8559 ap = lookupalias(command, 0);
8560 if (ap != NULL) {
Denis Vlasenko46846e22007-05-20 13:08:31 +00008561 if (!describe_command_verbose) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008562 out1str("alias ");
8563 printalias(ap);
8564 return 0;
8565 }
Denis Vlasenko46846e22007-05-20 13:08:31 +00008566 out1fmt(" is an alias for %s", ap->val);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008567 goto out;
8568 }
8569#endif
Youfu Zhang6683d1c2017-05-26 15:31:29 +08008570 /* Brute force */
8571 find_command(command, &entry, DO_ABS, path);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008572
8573 switch (entry.cmdtype) {
8574 case CMDNORMAL: {
8575 int j = entry.u.index;
8576 char *p;
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00008577 if (j < 0) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008578 p = command;
8579 } else {
8580 do {
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02008581 p = path_advance(&path, command);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008582 stunalloc(p);
8583 } while (--j >= 0);
8584 }
8585 if (describe_command_verbose) {
Youfu Zhang6683d1c2017-05-26 15:31:29 +08008586 out1fmt(" is %s", p);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008587 } else {
8588 out1str(p);
8589 }
8590 break;
8591 }
8592
8593 case CMDFUNCTION:
8594 if (describe_command_verbose) {
Denys Vlasenko63c42af2018-07-24 17:08:04 +02008595 /*out1str(" is a shell function");*/
8596 out1str(" is a function"); /* bash says this */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008597 } else {
8598 out1str(command);
8599 }
8600 break;
8601
8602 case CMDBUILTIN:
8603 if (describe_command_verbose) {
8604 out1fmt(" is a %sshell builtin",
8605 IS_BUILTIN_SPECIAL(entry.u.cmd) ?
8606 "special " : nullstr
8607 );
8608 } else {
8609 out1str(command);
8610 }
8611 break;
8612
8613 default:
8614 if (describe_command_verbose) {
8615 out1str(": not found\n");
8616 }
8617 return 127;
8618 }
8619 out:
Denys Vlasenko285ad152009-12-04 23:02:27 +01008620 out1str("\n");
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008621 return 0;
8622}
8623
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02008624static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00008625typecmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008626{
Denis Vlasenko46846e22007-05-20 13:08:31 +00008627 int i = 1;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008628 int err = 0;
Denis Vlasenko46846e22007-05-20 13:08:31 +00008629 int verbose = 1;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008630
Denis Vlasenko46846e22007-05-20 13:08:31 +00008631 /* type -p ... ? (we don't bother checking for 'p') */
Denis Vlasenko1fc62382007-06-25 22:55:34 +00008632 if (argv[1] && argv[1][0] == '-') {
Denis Vlasenko46846e22007-05-20 13:08:31 +00008633 i++;
8634 verbose = 0;
8635 }
Denis Vlasenko68404f12008-03-17 09:00:54 +00008636 while (argv[i]) {
Ron Yorston3f221112015-08-03 13:47:33 +01008637 err |= describe_command(argv[i++], NULL, verbose);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008638 }
8639 return err;
8640}
8641
8642#if ENABLE_ASH_CMDCMD
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008643/* Is it "command [-p] PROG ARGS" bltin, no other opts? Return ptr to "PROG" if yes */
8644static char **
8645parse_command_args(char **argv, const char **path)
8646{
8647 char *cp, c;
8648
8649 for (;;) {
8650 cp = *++argv;
8651 if (!cp)
8652 return NULL;
8653 if (*cp++ != '-')
8654 break;
8655 c = *cp++;
8656 if (!c)
8657 break;
8658 if (c == '-' && !*cp) {
8659 if (!*++argv)
8660 return NULL;
8661 break;
8662 }
8663 do {
8664 switch (c) {
8665 case 'p':
8666 *path = bb_default_path;
8667 break;
8668 default:
8669 /* run 'typecmd' for other options */
8670 return NULL;
8671 }
8672 c = *cp++;
8673 } while (c);
8674 }
8675 return argv;
8676}
8677
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02008678static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00008679commandcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008680{
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008681 char *cmd;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008682 int c;
8683 enum {
8684 VERIFY_BRIEF = 1,
8685 VERIFY_VERBOSE = 2,
8686 } verify = 0;
Ron Yorston3f221112015-08-03 13:47:33 +01008687 const char *path = NULL;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008688
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008689 /* "command [-p] PROG ARGS" (that is, without -V or -v)
8690 * never reaches this function.
8691 */
8692
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008693 while ((c = nextopt("pvV")) != '\0')
8694 if (c == 'V')
8695 verify |= VERIFY_VERBOSE;
8696 else if (c == 'v')
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008697 /*verify |= VERIFY_BRIEF*/;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008698#if DEBUG
8699 else if (c != 'p')
8700 abort();
8701#endif
Ron Yorston3f221112015-08-03 13:47:33 +01008702 else
8703 path = bb_default_path;
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008704
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00008705 /* Mimic bash: just "command -v" doesn't complain, it's a nop */
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008706 cmd = *argptr;
8707 if (/*verify && */ cmd)
8708 return describe_command(cmd, path, verify /* - VERIFY_BRIEF*/);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008709
8710 return 0;
8711}
8712#endif
8713
8714
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008715/*static int funcblocksize; // size of structures in function */
8716/*static int funcstringsize; // size of strings in node */
Denis Vlasenko340299a2008-11-21 10:36:36 +00008717static void *funcblock; /* block to allocate function from */
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008718static char *funcstring_end; /* end of block to allocate strings from */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008719
Denys Vlasenko3e134eb2016-04-22 18:09:21 +02008720static const uint8_t nodesize[N_NUMBER] ALIGN1 = {
Denis Vlasenko340299a2008-11-21 10:36:36 +00008721 [NCMD ] = SHELL_ALIGN(sizeof(struct ncmd)),
8722 [NPIPE ] = SHELL_ALIGN(sizeof(struct npipe)),
8723 [NREDIR ] = SHELL_ALIGN(sizeof(struct nredir)),
8724 [NBACKGND ] = SHELL_ALIGN(sizeof(struct nredir)),
8725 [NSUBSHELL] = SHELL_ALIGN(sizeof(struct nredir)),
8726 [NAND ] = SHELL_ALIGN(sizeof(struct nbinary)),
8727 [NOR ] = SHELL_ALIGN(sizeof(struct nbinary)),
8728 [NSEMI ] = SHELL_ALIGN(sizeof(struct nbinary)),
8729 [NIF ] = SHELL_ALIGN(sizeof(struct nif)),
8730 [NWHILE ] = SHELL_ALIGN(sizeof(struct nbinary)),
8731 [NUNTIL ] = SHELL_ALIGN(sizeof(struct nbinary)),
8732 [NFOR ] = SHELL_ALIGN(sizeof(struct nfor)),
8733 [NCASE ] = SHELL_ALIGN(sizeof(struct ncase)),
8734 [NCLIST ] = SHELL_ALIGN(sizeof(struct nclist)),
8735 [NDEFUN ] = SHELL_ALIGN(sizeof(struct narg)),
8736 [NARG ] = SHELL_ALIGN(sizeof(struct narg)),
8737 [NTO ] = SHELL_ALIGN(sizeof(struct nfile)),
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01008738#if BASH_REDIR_OUTPUT
Denis Vlasenko340299a2008-11-21 10:36:36 +00008739 [NTO2 ] = SHELL_ALIGN(sizeof(struct nfile)),
Denis Vlasenkocc5feab2008-11-22 01:32:40 +00008740#endif
Denis Vlasenko340299a2008-11-21 10:36:36 +00008741 [NCLOBBER ] = SHELL_ALIGN(sizeof(struct nfile)),
8742 [NFROM ] = SHELL_ALIGN(sizeof(struct nfile)),
8743 [NFROMTO ] = SHELL_ALIGN(sizeof(struct nfile)),
8744 [NAPPEND ] = SHELL_ALIGN(sizeof(struct nfile)),
8745 [NTOFD ] = SHELL_ALIGN(sizeof(struct ndup)),
8746 [NFROMFD ] = SHELL_ALIGN(sizeof(struct ndup)),
8747 [NHERE ] = SHELL_ALIGN(sizeof(struct nhere)),
8748 [NXHERE ] = SHELL_ALIGN(sizeof(struct nhere)),
8749 [NNOT ] = SHELL_ALIGN(sizeof(struct nnot)),
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008750};
8751
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008752static int calcsize(int funcblocksize, union node *n);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008753
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008754static int
8755sizenodelist(int funcblocksize, struct nodelist *lp)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008756{
8757 while (lp) {
8758 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008759 funcblocksize = calcsize(funcblocksize, lp->n);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008760 lp = lp->next;
8761 }
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008762 return funcblocksize;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008763}
8764
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008765static int
8766calcsize(int funcblocksize, union node *n)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008767{
8768 if (n == NULL)
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008769 return funcblocksize;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008770 funcblocksize += nodesize[n->type];
8771 switch (n->type) {
8772 case NCMD:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008773 funcblocksize = calcsize(funcblocksize, n->ncmd.redirect);
8774 funcblocksize = calcsize(funcblocksize, n->ncmd.args);
8775 funcblocksize = calcsize(funcblocksize, n->ncmd.assign);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008776 break;
8777 case NPIPE:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008778 funcblocksize = sizenodelist(funcblocksize, n->npipe.cmdlist);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008779 break;
8780 case NREDIR:
8781 case NBACKGND:
8782 case NSUBSHELL:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008783 funcblocksize = calcsize(funcblocksize, n->nredir.redirect);
8784 funcblocksize = calcsize(funcblocksize, n->nredir.n);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008785 break;
8786 case NAND:
8787 case NOR:
8788 case NSEMI:
8789 case NWHILE:
8790 case NUNTIL:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008791 funcblocksize = calcsize(funcblocksize, n->nbinary.ch2);
8792 funcblocksize = calcsize(funcblocksize, n->nbinary.ch1);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008793 break;
8794 case NIF:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008795 funcblocksize = calcsize(funcblocksize, n->nif.elsepart);
8796 funcblocksize = calcsize(funcblocksize, n->nif.ifpart);
8797 funcblocksize = calcsize(funcblocksize, n->nif.test);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008798 break;
8799 case NFOR:
Denys Vlasenko561639a2016-10-07 04:28:33 +02008800 funcblocksize += SHELL_ALIGN(strlen(n->nfor.var) + 1); /* was funcstringsize += ... */
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008801 funcblocksize = calcsize(funcblocksize, n->nfor.body);
8802 funcblocksize = calcsize(funcblocksize, n->nfor.args);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008803 break;
8804 case NCASE:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008805 funcblocksize = calcsize(funcblocksize, n->ncase.cases);
8806 funcblocksize = calcsize(funcblocksize, n->ncase.expr);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008807 break;
8808 case NCLIST:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008809 funcblocksize = calcsize(funcblocksize, n->nclist.body);
8810 funcblocksize = calcsize(funcblocksize, n->nclist.pattern);
8811 funcblocksize = calcsize(funcblocksize, n->nclist.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008812 break;
8813 case NDEFUN:
Denys Vlasenko675d24a2018-01-27 22:02:05 +01008814 funcblocksize = calcsize(funcblocksize, n->ndefun.body);
8815 funcblocksize += SHELL_ALIGN(strlen(n->ndefun.text) + 1);
8816 break;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008817 case NARG:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008818 funcblocksize = sizenodelist(funcblocksize, n->narg.backquote);
Denys Vlasenko561639a2016-10-07 04:28:33 +02008819 funcblocksize += SHELL_ALIGN(strlen(n->narg.text) + 1); /* was funcstringsize += ... */
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008820 funcblocksize = calcsize(funcblocksize, n->narg.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008821 break;
8822 case NTO:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01008823#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00008824 case NTO2:
8825#endif
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008826 case NCLOBBER:
8827 case NFROM:
8828 case NFROMTO:
8829 case NAPPEND:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008830 funcblocksize = calcsize(funcblocksize, n->nfile.fname);
8831 funcblocksize = calcsize(funcblocksize, n->nfile.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008832 break;
8833 case NTOFD:
8834 case NFROMFD:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008835 funcblocksize = calcsize(funcblocksize, n->ndup.vname);
8836 funcblocksize = calcsize(funcblocksize, n->ndup.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008837 break;
8838 case NHERE:
8839 case NXHERE:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008840 funcblocksize = calcsize(funcblocksize, n->nhere.doc);
8841 funcblocksize = calcsize(funcblocksize, n->nhere.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008842 break;
8843 case NNOT:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008844 funcblocksize = calcsize(funcblocksize, n->nnot.com);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008845 break;
8846 };
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008847 return funcblocksize;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008848}
8849
8850static char *
8851nodeckstrdup(char *s)
8852{
Denys Vlasenko561639a2016-10-07 04:28:33 +02008853 funcstring_end -= SHELL_ALIGN(strlen(s) + 1);
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008854 return strcpy(funcstring_end, s);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008855}
8856
8857static union node *copynode(union node *);
8858
8859static struct nodelist *
8860copynodelist(struct nodelist *lp)
8861{
8862 struct nodelist *start;
8863 struct nodelist **lpp;
8864
8865 lpp = &start;
8866 while (lp) {
8867 *lpp = funcblock;
8868 funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist));
8869 (*lpp)->n = copynode(lp->n);
8870 lp = lp->next;
8871 lpp = &(*lpp)->next;
8872 }
8873 *lpp = NULL;
8874 return start;
8875}
8876
8877static union node *
8878copynode(union node *n)
8879{
8880 union node *new;
8881
8882 if (n == NULL)
8883 return NULL;
8884 new = funcblock;
8885 funcblock = (char *) funcblock + nodesize[n->type];
8886
8887 switch (n->type) {
8888 case NCMD:
8889 new->ncmd.redirect = copynode(n->ncmd.redirect);
8890 new->ncmd.args = copynode(n->ncmd.args);
8891 new->ncmd.assign = copynode(n->ncmd.assign);
Denys Vlasenko675d24a2018-01-27 22:02:05 +01008892 new->ncmd.linno = n->ncmd.linno;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008893 break;
8894 case NPIPE:
8895 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00008896 new->npipe.pipe_backgnd = n->npipe.pipe_backgnd;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008897 break;
8898 case NREDIR:
8899 case NBACKGND:
8900 case NSUBSHELL:
8901 new->nredir.redirect = copynode(n->nredir.redirect);
8902 new->nredir.n = copynode(n->nredir.n);
Denys Vlasenko675d24a2018-01-27 22:02:05 +01008903 new->nredir.linno = n->nredir.linno;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008904 break;
8905 case NAND:
8906 case NOR:
8907 case NSEMI:
8908 case NWHILE:
8909 case NUNTIL:
8910 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8911 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8912 break;
8913 case NIF:
8914 new->nif.elsepart = copynode(n->nif.elsepart);
8915 new->nif.ifpart = copynode(n->nif.ifpart);
8916 new->nif.test = copynode(n->nif.test);
8917 break;
8918 case NFOR:
8919 new->nfor.var = nodeckstrdup(n->nfor.var);
8920 new->nfor.body = copynode(n->nfor.body);
8921 new->nfor.args = copynode(n->nfor.args);
Denys Vlasenko675d24a2018-01-27 22:02:05 +01008922 new->nfor.linno = n->nfor.linno;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008923 break;
8924 case NCASE:
8925 new->ncase.cases = copynode(n->ncase.cases);
8926 new->ncase.expr = copynode(n->ncase.expr);
Denys Vlasenko675d24a2018-01-27 22:02:05 +01008927 new->ncase.linno = n->ncase.linno;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008928 break;
8929 case NCLIST:
8930 new->nclist.body = copynode(n->nclist.body);
8931 new->nclist.pattern = copynode(n->nclist.pattern);
8932 new->nclist.next = copynode(n->nclist.next);
8933 break;
8934 case NDEFUN:
Denys Vlasenko675d24a2018-01-27 22:02:05 +01008935 new->ndefun.body = copynode(n->ndefun.body);
8936 new->ndefun.text = nodeckstrdup(n->ndefun.text);
8937 new->ndefun.linno = n->ndefun.linno;
8938 break;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008939 case NARG:
8940 new->narg.backquote = copynodelist(n->narg.backquote);
8941 new->narg.text = nodeckstrdup(n->narg.text);
8942 new->narg.next = copynode(n->narg.next);
8943 break;
8944 case NTO:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01008945#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00008946 case NTO2:
8947#endif
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008948 case NCLOBBER:
8949 case NFROM:
8950 case NFROMTO:
8951 case NAPPEND:
8952 new->nfile.fname = copynode(n->nfile.fname);
8953 new->nfile.fd = n->nfile.fd;
8954 new->nfile.next = copynode(n->nfile.next);
8955 break;
8956 case NTOFD:
8957 case NFROMFD:
8958 new->ndup.vname = copynode(n->ndup.vname);
8959 new->ndup.dupfd = n->ndup.dupfd;
8960 new->ndup.fd = n->ndup.fd;
8961 new->ndup.next = copynode(n->ndup.next);
8962 break;
8963 case NHERE:
8964 case NXHERE:
8965 new->nhere.doc = copynode(n->nhere.doc);
8966 new->nhere.fd = n->nhere.fd;
8967 new->nhere.next = copynode(n->nhere.next);
8968 break;
8969 case NNOT:
8970 new->nnot.com = copynode(n->nnot.com);
8971 break;
8972 };
8973 new->type = n->type;
8974 return new;
8975}
8976
8977/*
8978 * Make a copy of a parse tree.
8979 */
8980static struct funcnode *
8981copyfunc(union node *n)
8982{
8983 struct funcnode *f;
8984 size_t blocksize;
8985
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008986 /*funcstringsize = 0;*/
8987 blocksize = offsetof(struct funcnode, n) + calcsize(0, n);
8988 f = ckzalloc(blocksize /* + funcstringsize */);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008989 funcblock = (char *) f + offsetof(struct funcnode, n);
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008990 funcstring_end = (char *) f + blocksize;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008991 copynode(n);
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008992 /* f->count = 0; - ckzalloc did it */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008993 return f;
8994}
8995
8996/*
8997 * Define a shell function.
8998 */
8999static void
Denys Vlasenko7aec8682016-10-25 20:26:02 +02009000defun(union node *func)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009001{
9002 struct cmdentry entry;
9003
9004 INT_OFF;
9005 entry.cmdtype = CMDFUNCTION;
9006 entry.u.func = copyfunc(func);
Denys Vlasenko675d24a2018-01-27 22:02:05 +01009007 addcmdentry(func->ndefun.text, &entry);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009008 INT_ON;
9009}
9010
Denis Vlasenko4b875702009-03-19 13:30:04 +00009011/* Reasons for skipping commands (see comment on breakcmd routine) */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009012#define SKIPBREAK (1 << 0)
9013#define SKIPCONT (1 << 1)
9014#define SKIPFUNC (1 << 2)
Denis Vlasenko4b875702009-03-19 13:30:04 +00009015static smallint evalskip; /* set to SKIPxxx if we are skipping commands */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009016static int skipcount; /* number of levels to skip */
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +00009017static int loopnest; /* current loop nesting level */
Denys Vlasenko675d24a2018-01-27 22:02:05 +01009018static int funcline; /* starting line number of current function, or 0 if not in a function */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009019
Denis Vlasenko4b875702009-03-19 13:30:04 +00009020/* Forward decl way out to parsing code - dotrap needs it */
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009021static int evalstring(char *s, int flags);
Denis Vlasenkofc06f292007-02-23 21:09:35 +00009022
Denis Vlasenko4b875702009-03-19 13:30:04 +00009023/* Called to execute a trap.
9024 * Single callsite - at the end of evaltree().
Denys Vlasenkob563f622010-09-25 17:15:13 +02009025 * If we return non-zero, evaltree raises EXEXIT exception.
Denis Vlasenko4b875702009-03-19 13:30:04 +00009026 *
9027 * Perhaps we should avoid entering new trap handlers
9028 * while we are executing a trap handler. [is it a TODO?]
Denis Vlasenkofc06f292007-02-23 21:09:35 +00009029 */
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02009030static void
Denis Vlasenkofc06f292007-02-23 21:09:35 +00009031dotrap(void)
9032{
Denis Vlasenko4b875702009-03-19 13:30:04 +00009033 uint8_t *g;
9034 int sig;
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02009035 uint8_t last_status;
Denis Vlasenkofc06f292007-02-23 21:09:35 +00009036
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02009037 if (!pending_sig)
9038 return;
9039
9040 last_status = exitstatus;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02009041 pending_sig = 0;
Denys Vlasenkode892052016-10-02 01:49:13 +02009042 barrier();
Denis Vlasenkofc06f292007-02-23 21:09:35 +00009043
Denis Vlasenko653d8e72009-03-19 21:59:35 +00009044 TRACE(("dotrap entered\n"));
Denis Vlasenko4b875702009-03-19 13:30:04 +00009045 for (sig = 1, g = gotsig; sig < NSIG; sig++, g++) {
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02009046 char *p;
Denis Vlasenkofc06f292007-02-23 21:09:35 +00009047
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02009048 if (!*g)
Denis Vlasenkofc06f292007-02-23 21:09:35 +00009049 continue;
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02009050
9051 if (evalskip) {
9052 pending_sig = sig;
9053 break;
9054 }
9055
9056 p = trap[sig];
Denis Vlasenko4b875702009-03-19 13:30:04 +00009057 /* non-trapped SIGINT is handled separately by raise_interrupt,
9058 * don't upset it by resetting gotsig[SIGINT-1] */
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02009059 if (sig == SIGINT && !p)
Denis Vlasenko4b875702009-03-19 13:30:04 +00009060 continue;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00009061
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02009062 TRACE(("sig %d is active, will run handler '%s'\n", sig, p));
Denis Vlasenko4b875702009-03-19 13:30:04 +00009063 *g = 0;
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02009064 if (!p)
Denis Vlasenko4b875702009-03-19 13:30:04 +00009065 continue;
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02009066 evalstring(p, 0);
Denis Vlasenkofc06f292007-02-23 21:09:35 +00009067 }
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02009068 exitstatus = last_status;
9069 TRACE(("dotrap returns\n"));
Denis Vlasenkofc06f292007-02-23 21:09:35 +00009070}
9071
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00009072/* forward declarations - evaluation is fairly recursive business... */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009073static int evalloop(union node *, int);
9074static int evalfor(union node *, int);
9075static int evalcase(union node *, int);
9076static int evalsubshell(union node *, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009077static void expredir(union node *);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009078static int evalpipe(union node *, int);
9079static int evalcommand(union node *, int);
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009080static int evalbltin(const struct builtincmd *, int, char **, int);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009081static void prehash(union node *);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009082
Eric Andersen62483552001-07-10 06:09:16 +00009083/*
Eric Andersenc470f442003-07-28 09:56:35 +00009084 * Evaluate a parse tree. The value is left in the global variable
9085 * exitstatus.
Eric Andersen62483552001-07-10 06:09:16 +00009086 */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009087static int
Eric Andersenc470f442003-07-28 09:56:35 +00009088evaltree(union node *n, int flags)
Eric Andersen62483552001-07-10 06:09:16 +00009089{
Eric Andersenc470f442003-07-28 09:56:35 +00009090 int checkexit = 0;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009091 int (*evalfn)(union node *, int);
Ron Yorstonf55161a2019-02-25 08:29:38 +00009092 struct stackmark smark;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009093 int status = 0;
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00009094
Ron Yorstonf55161a2019-02-25 08:29:38 +00009095 setstackmark(&smark);
9096
Eric Andersenc470f442003-07-28 09:56:35 +00009097 if (n == NULL) {
9098 TRACE(("evaltree(NULL) called\n"));
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02009099 goto out;
Eric Andersen62483552001-07-10 06:09:16 +00009100 }
Denis Vlasenko653d8e72009-03-19 21:59:35 +00009101 TRACE(("evaltree(%p: %d, %d) called\n", n, n->type, flags));
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00009102
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02009103 dotrap();
9104
Eric Andersenc470f442003-07-28 09:56:35 +00009105 switch (n->type) {
9106 default:
Denis Vlasenkoa7189f02006-11-17 20:29:00 +00009107#if DEBUG
Eric Andersenc470f442003-07-28 09:56:35 +00009108 out1fmt("Node type = %d\n", n->type);
Denys Vlasenko8131eea2009-11-02 14:19:51 +01009109 fflush_all();
Eric Andersenc470f442003-07-28 09:56:35 +00009110 break;
9111#endif
9112 case NNOT:
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009113 status = !evaltree(n->nnot.com, EV_TESTED);
Eric Andersenc470f442003-07-28 09:56:35 +00009114 goto setstatus;
9115 case NREDIR:
Denys Vlasenko675d24a2018-01-27 22:02:05 +01009116 errlinno = lineno = n->nredir.linno;
9117 if (funcline)
9118 lineno -= funcline - 1;
Eric Andersenc470f442003-07-28 09:56:35 +00009119 expredir(n->nredir.redirect);
Denys Vlasenko1c79aeb2017-07-29 22:51:52 +02009120 pushredir(n->nredir.redirect);
Eric Andersenc470f442003-07-28 09:56:35 +00009121 status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
9122 if (!status) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009123 status = evaltree(n->nredir.n, flags & EV_TESTED);
Eric Andersenc470f442003-07-28 09:56:35 +00009124 }
Denys Vlasenkoeaf94362016-10-25 21:46:03 +02009125 if (n->nredir.redirect)
Denys Vlasenko035486c2017-07-31 04:09:19 +02009126 popredir(/*drop:*/ 0);
Eric Andersenc470f442003-07-28 09:56:35 +00009127 goto setstatus;
9128 case NCMD:
9129 evalfn = evalcommand;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009130 checkexit:
Eric Andersenc470f442003-07-28 09:56:35 +00009131 if (eflag && !(flags & EV_TESTED))
9132 checkexit = ~0;
9133 goto calleval;
9134 case NFOR:
9135 evalfn = evalfor;
9136 goto calleval;
9137 case NWHILE:
9138 case NUNTIL:
9139 evalfn = evalloop;
9140 goto calleval;
9141 case NSUBSHELL:
9142 case NBACKGND:
9143 evalfn = evalsubshell;
Denys Vlasenkocf98b0c2016-10-25 18:19:39 +02009144 goto checkexit;
Eric Andersenc470f442003-07-28 09:56:35 +00009145 case NPIPE:
9146 evalfn = evalpipe;
9147 goto checkexit;
9148 case NCASE:
9149 evalfn = evalcase;
9150 goto calleval;
9151 case NAND:
9152 case NOR:
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00009153 case NSEMI: {
9154
Eric Andersenc470f442003-07-28 09:56:35 +00009155#if NAND + 1 != NOR
9156#error NAND + 1 != NOR
9157#endif
9158#if NOR + 1 != NSEMI
9159#error NOR + 1 != NSEMI
9160#endif
Denis Vlasenko87d5fd92008-07-26 13:48:35 +00009161 unsigned is_or = n->type - NAND;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009162 status = evaltree(
Eric Andersenc470f442003-07-28 09:56:35 +00009163 n->nbinary.ch1,
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00009164 (flags | ((is_or >> 1) - 1)) & EV_TESTED
Eric Andersenc470f442003-07-28 09:56:35 +00009165 );
Denys Vlasenkobc1a0082016-10-02 15:31:33 +02009166 if ((!status) == is_or || evalskip)
Eric Andersenc470f442003-07-28 09:56:35 +00009167 break;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009168 n = n->nbinary.ch2;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009169 evaln:
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009170 evalfn = evaltree;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009171 calleval:
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009172 status = evalfn(n, flags);
9173 goto setstatus;
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00009174 }
Eric Andersenc470f442003-07-28 09:56:35 +00009175 case NIF:
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009176 status = evaltree(n->nif.test, EV_TESTED);
Eric Andersenc470f442003-07-28 09:56:35 +00009177 if (evalskip)
9178 break;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009179 if (!status) {
Eric Andersenc470f442003-07-28 09:56:35 +00009180 n = n->nif.ifpart;
9181 goto evaln;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00009182 }
9183 if (n->nif.elsepart) {
Eric Andersenc470f442003-07-28 09:56:35 +00009184 n = n->nif.elsepart;
9185 goto evaln;
9186 }
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009187 status = 0;
9188 goto setstatus;
Eric Andersenc470f442003-07-28 09:56:35 +00009189 case NDEFUN:
Denys Vlasenko7aec8682016-10-25 20:26:02 +02009190 defun(n);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009191 /* Not necessary. To test it:
9192 * "false; f() { qwerty; }; echo $?" should print 0.
9193 */
9194 /* status = 0; */
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009195 setstatus:
Eric Andersenc470f442003-07-28 09:56:35 +00009196 exitstatus = status;
9197 break;
9198 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009199 out:
Denys Vlasenkob563f622010-09-25 17:15:13 +02009200 /* Order of checks below is important:
9201 * signal handlers trigger before exit caused by "set -e".
9202 */
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02009203 dotrap();
9204
9205 if (checkexit & status)
Denis Vlasenkob012b102007-02-19 22:43:01 +00009206 raise_exception(EXEXIT);
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02009207 if (flags & EV_EXIT)
9208 raise_exception(EXEXIT);
Denis Vlasenko653d8e72009-03-19 21:59:35 +00009209
Ron Yorstonf55161a2019-02-25 08:29:38 +00009210 popstackmark(&smark);
Denis Vlasenko653d8e72009-03-19 21:59:35 +00009211 TRACE(("leaving evaltree (no interrupts)\n"));
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009212 return exitstatus;
Eric Andersen62483552001-07-10 06:09:16 +00009213}
9214
Denys Vlasenko37dc08b2016-10-02 04:38:07 +02009215static int
9216skiploop(void)
Denys Vlasenko35ec8182016-10-01 19:56:52 +02009217{
9218 int skip = evalskip;
9219
9220 switch (skip) {
9221 case 0:
9222 break;
9223 case SKIPBREAK:
9224 case SKIPCONT:
9225 if (--skipcount <= 0) {
9226 evalskip = 0;
9227 break;
9228 }
9229 skip = SKIPBREAK;
9230 break;
9231 }
9232 return skip;
9233}
9234
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009235static int
Eric Andersenc470f442003-07-28 09:56:35 +00009236evalloop(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00009237{
Denys Vlasenko35ec8182016-10-01 19:56:52 +02009238 int skip;
Eric Andersencb57d552001-06-28 07:25:16 +00009239 int status;
9240
9241 loopnest++;
9242 status = 0;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009243 flags &= EV_TESTED;
Denys Vlasenko35ec8182016-10-01 19:56:52 +02009244 do {
Eric Andersenc470f442003-07-28 09:56:35 +00009245 int i;
9246
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009247 i = evaltree(n->nbinary.ch1, EV_TESTED);
Denys Vlasenko35ec8182016-10-01 19:56:52 +02009248 skip = skiploop();
9249 if (skip == SKIPFUNC)
9250 status = i;
9251 if (skip)
9252 continue;
Eric Andersenc470f442003-07-28 09:56:35 +00009253 if (n->type != NWHILE)
9254 i = !i;
9255 if (i != 0)
9256 break;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009257 status = evaltree(n->nbinary.ch2, flags);
Denys Vlasenko35ec8182016-10-01 19:56:52 +02009258 skip = skiploop();
9259 } while (!(skip & ~SKIPCONT));
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009260 loopnest--;
9261
9262 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00009263}
9264
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009265static int
Eric Andersenc470f442003-07-28 09:56:35 +00009266evalfor(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00009267{
9268 struct arglist arglist;
9269 union node *argp;
9270 struct strlist *sp;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009271 int status = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00009272
Denys Vlasenko675d24a2018-01-27 22:02:05 +01009273 errlinno = lineno = n->ncase.linno;
9274 if (funcline)
9275 lineno -= funcline - 1;
9276
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00009277 arglist.list = NULL;
Eric Andersencb57d552001-06-28 07:25:16 +00009278 arglist.lastp = &arglist.list;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009279 for (argp = n->nfor.args; argp; argp = argp->narg.next) {
Ron Yorston549deab2015-05-18 09:57:51 +02009280 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
Eric Andersencb57d552001-06-28 07:25:16 +00009281 }
9282 *arglist.lastp = NULL;
9283
Eric Andersencb57d552001-06-28 07:25:16 +00009284 loopnest++;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009285 flags &= EV_TESTED;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009286 for (sp = arglist.list; sp; sp = sp->next) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009287 setvar0(n->nfor.var, sp->text);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009288 status = evaltree(n->nfor.body, flags);
Denys Vlasenko35ec8182016-10-01 19:56:52 +02009289 if (skiploop() & ~SKIPCONT)
Eric Andersencb57d552001-06-28 07:25:16 +00009290 break;
Eric Andersencb57d552001-06-28 07:25:16 +00009291 }
9292 loopnest--;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009293
9294 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00009295}
9296
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009297static int
Eric Andersenc470f442003-07-28 09:56:35 +00009298evalcase(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00009299{
9300 union node *cp;
9301 union node *patp;
9302 struct arglist arglist;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009303 int status = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00009304
Denys Vlasenko675d24a2018-01-27 22:02:05 +01009305 errlinno = lineno = n->ncase.linno;
9306 if (funcline)
9307 lineno -= funcline - 1;
9308
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00009309 arglist.list = NULL;
Eric Andersencb57d552001-06-28 07:25:16 +00009310 arglist.lastp = &arglist.list;
Eric Andersencb57d552001-06-28 07:25:16 +00009311 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009312 for (cp = n->ncase.cases; cp && evalskip == 0; cp = cp->nclist.next) {
9313 for (patp = cp->nclist.pattern; patp; patp = patp->narg.next) {
Eric Andersencb57d552001-06-28 07:25:16 +00009314 if (casematch(patp, arglist.list->text)) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009315 /* Ensure body is non-empty as otherwise
9316 * EV_EXIT may prevent us from setting the
9317 * exit status.
9318 */
9319 if (evalskip == 0 && cp->nclist.body) {
9320 status = evaltree(cp->nclist.body, flags);
Eric Andersencb57d552001-06-28 07:25:16 +00009321 }
9322 goto out;
9323 }
9324 }
9325 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009326 out:
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009327 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00009328}
9329
Eric Andersenc470f442003-07-28 09:56:35 +00009330/*
9331 * Kick off a subshell to evaluate a tree.
9332 */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009333static int
Eric Andersenc470f442003-07-28 09:56:35 +00009334evalsubshell(union node *n, int flags)
9335{
9336 struct job *jp;
Denys Vlasenko098b7132017-01-11 19:59:03 +01009337 int backgnd = (n->type == NBACKGND); /* FORK_BG(1) if yes, else FORK_FG(0) */
Eric Andersenc470f442003-07-28 09:56:35 +00009338 int status;
9339
Denys Vlasenko675d24a2018-01-27 22:02:05 +01009340 errlinno = lineno = n->nredir.linno;
9341 if (funcline)
9342 lineno -= funcline - 1;
9343
Eric Andersenc470f442003-07-28 09:56:35 +00009344 expredir(n->nredir.redirect);
Denys Vlasenko238bf182010-05-18 15:49:07 +02009345 if (!backgnd && (flags & EV_EXIT) && !may_have_traps)
Eric Andersenc470f442003-07-28 09:56:35 +00009346 goto nofork;
Denis Vlasenkob012b102007-02-19 22:43:01 +00009347 INT_OFF;
Denys Vlasenko098b7132017-01-11 19:59:03 +01009348 if (backgnd == FORK_FG)
9349 get_tty_state();
Denis Vlasenko68404f12008-03-17 09:00:54 +00009350 jp = makejob(/*n,*/ 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009351 if (forkshell(jp, n, backgnd) == 0) {
Denys Vlasenko238bf182010-05-18 15:49:07 +02009352 /* child */
Denis Vlasenkob012b102007-02-19 22:43:01 +00009353 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +00009354 flags |= EV_EXIT;
9355 if (backgnd)
Denys Vlasenko238bf182010-05-18 15:49:07 +02009356 flags &= ~EV_TESTED;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00009357 nofork:
Eric Andersenc470f442003-07-28 09:56:35 +00009358 redirect(n->nredir.redirect, 0);
9359 evaltreenr(n->nredir.n, flags);
9360 /* never returns */
9361 }
Denys Vlasenko70392332016-10-27 02:31:55 +02009362 /* parent */
Eric Andersenc470f442003-07-28 09:56:35 +00009363 status = 0;
Denys Vlasenko098b7132017-01-11 19:59:03 +01009364 if (backgnd == FORK_FG)
Eric Andersenc470f442003-07-28 09:56:35 +00009365 status = waitforjob(jp);
Denis Vlasenkob012b102007-02-19 22:43:01 +00009366 INT_ON;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009367 return status;
Eric Andersenc470f442003-07-28 09:56:35 +00009368}
9369
Eric Andersenc470f442003-07-28 09:56:35 +00009370/*
9371 * Compute the names of the files in a redirection list.
9372 */
Denis Vlasenko99eb8502007-02-23 21:09:49 +00009373static void fixredir(union node *, const char *, int);
Eric Andersenc470f442003-07-28 09:56:35 +00009374static void
9375expredir(union node *n)
9376{
9377 union node *redir;
9378
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009379 for (redir = n; redir; redir = redir->nfile.next) {
Eric Andersenc470f442003-07-28 09:56:35 +00009380 struct arglist fn;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009381
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00009382 fn.list = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00009383 fn.lastp = &fn.list;
9384 switch (redir->type) {
9385 case NFROMTO:
9386 case NFROM:
9387 case NTO:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01009388#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00009389 case NTO2:
9390#endif
Eric Andersenc470f442003-07-28 09:56:35 +00009391 case NCLOBBER:
9392 case NAPPEND:
9393 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02009394 TRACE(("expredir expanded to '%s'\n", fn.list->text));
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01009395#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00009396 store_expfname:
9397#endif
Denys Vlasenko7c4b13e2013-01-17 13:02:27 +01009398#if 0
9399// By the design of stack allocator, the loop of this kind:
9400// while true; do while true; do break; done </dev/null; done
9401// will look like a memory leak: ash plans to free expfname's
9402// of "/dev/null" as soon as it finishes running the loop
9403// (in this case, never).
9404// This "fix" is wrong:
Jon Tollefson4ba6c5d2012-11-13 19:26:53 +01009405 if (redir->nfile.expfname)
9406 stunalloc(redir->nfile.expfname);
Denys Vlasenko7c4b13e2013-01-17 13:02:27 +01009407// It results in corrupted state of stacked allocations.
9408#endif
Eric Andersenc470f442003-07-28 09:56:35 +00009409 redir->nfile.expfname = fn.list->text;
9410 break;
9411 case NFROMFD:
Denis Vlasenko559691a2008-10-05 18:39:31 +00009412 case NTOFD: /* >& */
Eric Andersenc470f442003-07-28 09:56:35 +00009413 if (redir->ndup.vname) {
9414 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009415 if (fn.list == NULL)
Denis Vlasenkob012b102007-02-19 22:43:01 +00009416 ash_msg_and_raise_error("redir error");
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01009417#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00009418//FIXME: we used expandarg with different args!
9419 if (!isdigit_str9(fn.list->text)) {
9420 /* >&file, not >&fd */
9421 if (redir->nfile.fd != 1) /* 123>&file - BAD */
9422 ash_msg_and_raise_error("redir error");
9423 redir->type = NTO2;
9424 goto store_expfname;
9425 }
9426#endif
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009427 fixredir(redir, fn.list->text, 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009428 }
9429 break;
9430 }
9431 }
9432}
9433
Eric Andersencb57d552001-06-28 07:25:16 +00009434/*
Eric Andersencb57d552001-06-28 07:25:16 +00009435 * Evaluate a pipeline. All the processes in the pipeline are children
9436 * of the process creating the pipeline. (This differs from some versions
9437 * of the shell, which make the last process in a pipeline the parent
9438 * of all the rest.)
9439 */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009440static int
Eric Andersenc470f442003-07-28 09:56:35 +00009441evalpipe(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00009442{
9443 struct job *jp;
9444 struct nodelist *lp;
9445 int pipelen;
9446 int prevfd;
9447 int pip[2];
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009448 int status = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00009449
Eric Andersenc470f442003-07-28 09:56:35 +00009450 TRACE(("evalpipe(0x%lx) called\n", (long)n));
Eric Andersencb57d552001-06-28 07:25:16 +00009451 pipelen = 0;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009452 for (lp = n->npipe.cmdlist; lp; lp = lp->next)
Eric Andersencb57d552001-06-28 07:25:16 +00009453 pipelen++;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009454 flags |= EV_EXIT;
Denis Vlasenkob012b102007-02-19 22:43:01 +00009455 INT_OFF;
Denys Vlasenko098b7132017-01-11 19:59:03 +01009456 if (n->npipe.pipe_backgnd == 0)
9457 get_tty_state();
Denis Vlasenko68404f12008-03-17 09:00:54 +00009458 jp = makejob(/*n,*/ pipelen);
Eric Andersencb57d552001-06-28 07:25:16 +00009459 prevfd = -1;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009460 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009461 prehash(lp->n);
Eric Andersencb57d552001-06-28 07:25:16 +00009462 pip[1] = -1;
9463 if (lp->next) {
9464 if (pipe(pip) < 0) {
9465 close(prevfd);
Denys Vlasenko12ffefb2017-08-23 14:52:56 +02009466 ash_msg_and_raise_perror("can't create pipe");
Eric Andersencb57d552001-06-28 07:25:16 +00009467 }
9468 }
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00009469 if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) {
Denys Vlasenko70392332016-10-27 02:31:55 +02009470 /* child */
Denis Vlasenkob012b102007-02-19 22:43:01 +00009471 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +00009472 if (pip[1] >= 0) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009473 close(pip[0]);
Eric Andersencb57d552001-06-28 07:25:16 +00009474 }
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009475 if (prevfd > 0) {
9476 dup2(prevfd, 0);
9477 close(prevfd);
9478 }
9479 if (pip[1] > 1) {
9480 dup2(pip[1], 1);
9481 close(pip[1]);
9482 }
Eric Andersenc470f442003-07-28 09:56:35 +00009483 evaltreenr(lp->n, flags);
9484 /* never returns */
Eric Andersencb57d552001-06-28 07:25:16 +00009485 }
Denys Vlasenko70392332016-10-27 02:31:55 +02009486 /* parent */
Eric Andersencb57d552001-06-28 07:25:16 +00009487 if (prevfd >= 0)
9488 close(prevfd);
9489 prevfd = pip[0];
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +00009490 /* Don't want to trigger debugging */
9491 if (pip[1] != -1)
9492 close(pip[1]);
Eric Andersencb57d552001-06-28 07:25:16 +00009493 }
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00009494 if (n->npipe.pipe_backgnd == 0) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009495 status = waitforjob(jp);
9496 TRACE(("evalpipe: job done exit status %d\n", status));
Eric Andersencb57d552001-06-28 07:25:16 +00009497 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00009498 INT_ON;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009499
9500 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00009501}
9502
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009503/*
9504 * Controls whether the shell is interactive or not.
9505 */
9506static void
9507setinteractive(int on)
9508{
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009509 static smallint is_interactive;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009510
9511 if (++on == is_interactive)
9512 return;
9513 is_interactive = on;
9514 setsignal(SIGINT);
9515 setsignal(SIGQUIT);
9516 setsignal(SIGTERM);
9517#if !ENABLE_FEATURE_SH_EXTRA_QUIET
9518 if (is_interactive > 1) {
9519 /* Looks like they want an interactive shell */
Denis Vlasenkoca525b42007-06-13 12:27:17 +00009520 static smallint did_banner;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009521
Denis Vlasenkoca525b42007-06-13 12:27:17 +00009522 if (!did_banner) {
Denys Vlasenkoc34c0332009-09-29 12:25:30 +02009523 /* note: ash and hush share this string */
9524 out1fmt("\n\n%s %s\n"
Denys Vlasenko2ec34962014-09-08 16:52:39 +02009525 IF_ASH_HELP("Enter 'help' for a list of built-in commands.\n")
9526 "\n",
Denys Vlasenkoc34c0332009-09-29 12:25:30 +02009527 bb_banner,
9528 "built-in shell (ash)"
9529 );
Denis Vlasenkoca525b42007-06-13 12:27:17 +00009530 did_banner = 1;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009531 }
9532 }
9533#endif
9534}
9535
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009536static void
9537optschanged(void)
9538{
9539#if DEBUG
9540 opentrace();
9541#endif
9542 setinteractive(iflag);
9543 setjobctl(mflag);
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009544#if ENABLE_FEATURE_EDITING_VI
9545 if (viflag)
9546 line_input_state->flags |= VI_MODE;
9547 else
9548 line_input_state->flags &= ~VI_MODE;
9549#else
9550 viflag = 0; /* forcibly keep the option off */
9551#endif
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009552}
9553
Denys Vlasenkob8ab27b2017-07-26 19:22:34 +02009554struct localvar_list {
9555 struct localvar_list *next;
9556 struct localvar *lv;
9557};
9558
9559static struct localvar_list *localvar_stack;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009560
9561/*
9562 * Called after a function returns.
9563 * Interrupts must be off.
9564 */
9565static void
Denys Vlasenko981a0562017-07-26 19:53:11 +02009566poplocalvars(int keep)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009567{
Denys Vlasenkob8ab27b2017-07-26 19:22:34 +02009568 struct localvar_list *ll;
9569 struct localvar *lvp, *next;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009570 struct var *vp;
9571
Denys Vlasenkob8ab27b2017-07-26 19:22:34 +02009572 INT_OFF;
9573 ll = localvar_stack;
9574 localvar_stack = ll->next;
9575
9576 next = ll->lv;
9577 free(ll);
9578
9579 while ((lvp = next) != NULL) {
9580 next = lvp->next;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009581 vp = lvp->vp;
Denys Vlasenkob563f622010-09-25 17:15:13 +02009582 TRACE(("poplocalvar %s\n", vp ? vp->var_text : "-"));
Denys Vlasenko981a0562017-07-26 19:53:11 +02009583 if (keep) {
9584 int bits = VSTRFIXED;
9585
9586 if (lvp->flags != VUNSET) {
9587 if (vp->var_text == lvp->text)
9588 bits |= VTEXTFIXED;
9589 else if (!(lvp->flags & (VTEXTFIXED|VSTACK)))
9590 free((char*)lvp->text);
9591 }
9592
9593 vp->flags &= ~bits;
9594 vp->flags |= (lvp->flags & bits);
9595
9596 if ((vp->flags &
9597 (VEXPORT|VREADONLY|VSTRFIXED|VUNSET)) == VUNSET)
9598 unsetvar(vp->var_text);
9599 } else if (vp == NULL) { /* $- saved */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009600 memcpy(optlist, lvp->text, sizeof(optlist));
9601 free((char*)lvp->text);
9602 optschanged();
Denys Vlasenkod5b500c2017-07-26 19:25:40 +02009603 } else if (lvp->flags == VUNSET) {
9604 vp->flags &= ~(VSTRFIXED|VREADONLY);
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009605 unsetvar(vp->var_text);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009606 } else {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009607 if (vp->var_func)
9608 vp->var_func(var_end(lvp->text));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009609 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009610 free((char*)vp->var_text);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009611 vp->flags = lvp->flags;
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009612 vp->var_text = lvp->text;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009613 }
9614 free(lvp);
9615 }
Denys Vlasenkob8ab27b2017-07-26 19:22:34 +02009616 INT_ON;
9617}
9618
9619/*
9620 * Create a new localvar environment.
9621 */
Denys Vlasenko484fc202017-07-26 19:55:31 +02009622static struct localvar_list *
Denys Vlasenkob8ab27b2017-07-26 19:22:34 +02009623pushlocalvars(void)
9624{
9625 struct localvar_list *ll;
9626
9627 INT_OFF;
9628 ll = ckzalloc(sizeof(*ll));
9629 /*ll->lv = NULL; - zalloc did it */
9630 ll->next = localvar_stack;
9631 localvar_stack = ll;
9632 INT_ON;
Denys Vlasenko484fc202017-07-26 19:55:31 +02009633
9634 return ll->next;
9635}
9636
9637static void
9638unwindlocalvars(struct localvar_list *stop)
9639{
9640 while (localvar_stack != stop)
9641 poplocalvars(0);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009642}
9643
9644static int
9645evalfun(struct funcnode *func, int argc, char **argv, int flags)
9646{
9647 volatile struct shparam saveparam;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009648 struct jmploc *volatile savehandler;
9649 struct jmploc jmploc;
9650 int e;
Denys Vlasenko675d24a2018-01-27 22:02:05 +01009651 int savefuncline;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009652
9653 saveparam = shellparam;
Denys Vlasenko675d24a2018-01-27 22:02:05 +01009654 savefuncline = funcline;
Denys Vlasenkoa2d121c2016-09-30 11:30:11 +02009655 savehandler = exception_handler;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009656 e = setjmp(jmploc.loc);
9657 if (e) {
9658 goto funcdone;
9659 }
9660 INT_OFF;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009661 exception_handler = &jmploc;
Denis Vlasenko01631112007-12-16 17:20:38 +00009662 shellparam.malloced = 0;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009663 func->count++;
Denys Vlasenko675d24a2018-01-27 22:02:05 +01009664 funcline = func->n.ndefun.linno;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009665 INT_ON;
9666 shellparam.nparam = argc - 1;
9667 shellparam.p = argv + 1;
9668#if ENABLE_ASH_GETOPTS
9669 shellparam.optind = 1;
9670 shellparam.optoff = -1;
9671#endif
Denys Vlasenko675d24a2018-01-27 22:02:05 +01009672 evaltree(func->n.ndefun.body, flags & EV_TESTED);
Denis Vlasenko01631112007-12-16 17:20:38 +00009673 funcdone:
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009674 INT_OFF;
Denys Vlasenko675d24a2018-01-27 22:02:05 +01009675 funcline = savefuncline;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009676 freefunc(func);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009677 freeparam(&shellparam);
9678 shellparam = saveparam;
9679 exception_handler = savehandler;
9680 INT_ON;
9681 evalskip &= ~SKIPFUNC;
9682 return e;
9683}
9684
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009685/*
9686 * Make a variable a local variable. When a variable is made local, it's
9687 * value and flags are saved in a localvar structure. The saved values
9688 * will be restored when the shell function returns. We handle the name
Denys Vlasenkoe0a4e102015-05-13 02:20:14 +02009689 * "-" as a special case: it makes changes to "set +-options" local
9690 * (options will be restored on return from the function).
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009691 */
9692static void
9693mklocal(char *name)
9694{
9695 struct localvar *lvp;
9696 struct var **vpp;
9697 struct var *vp;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009698 char *eq = strchr(name, '=');
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009699
9700 INT_OFF;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009701 /* Cater for duplicate "local". Examples:
9702 * x=0; f() { local x=1; echo $x; local x; echo $x; }; f; echo $x
9703 * x=0; f() { local x=1; echo $x; local x=2; echo $x; }; f; echo $x
9704 */
Denys Vlasenkob8ab27b2017-07-26 19:22:34 +02009705 lvp = localvar_stack->lv;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009706 while (lvp) {
Eugene Rudoy1285aa62015-04-26 23:32:00 +02009707 if (lvp->vp && varcmp(lvp->vp->var_text, name) == 0) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009708 if (eq)
9709 setvareq(name, 0);
9710 /* else:
9711 * it's a duplicate "local VAR" declaration, do nothing
9712 */
Denys Vlasenko06b11492016-11-04 16:43:18 +01009713 goto ret;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009714 }
9715 lvp = lvp->next;
9716 }
9717
9718 lvp = ckzalloc(sizeof(*lvp));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009719 if (LONE_DASH(name)) {
9720 char *p;
9721 p = ckmalloc(sizeof(optlist));
9722 lvp->text = memcpy(p, optlist, sizeof(optlist));
9723 vp = NULL;
9724 } else {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009725 vpp = hashvar(name);
9726 vp = *findvar(vpp, name);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009727 if (vp == NULL) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009728 /* variable did not exist yet */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009729 if (eq)
Denys Vlasenkod04fc712017-07-26 20:06:48 +02009730 vp = setvareq(name, VSTRFIXED);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009731 else
Denys Vlasenkod04fc712017-07-26 20:06:48 +02009732 vp = setvar(name, NULL, VSTRFIXED);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009733 lvp->flags = VUNSET;
9734 } else {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009735 lvp->text = vp->var_text;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009736 lvp->flags = vp->flags;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009737 /* make sure neither "struct var" nor string gets freed
9738 * during (un)setting:
9739 */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009740 vp->flags |= VSTRFIXED|VTEXTFIXED;
9741 if (eq)
9742 setvareq(name, 0);
Denys Vlasenko109ee5d2014-03-16 18:41:11 +01009743 else
9744 /* "local VAR" unsets VAR: */
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009745 setvar0(name, NULL);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009746 }
9747 }
9748 lvp->vp = vp;
Denys Vlasenkob8ab27b2017-07-26 19:22:34 +02009749 lvp->next = localvar_stack->lv;
9750 localvar_stack->lv = lvp;
Denys Vlasenko06b11492016-11-04 16:43:18 +01009751 ret:
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009752 INT_ON;
9753}
9754
9755/*
9756 * The "local" command.
9757 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009758static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009759localcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009760{
9761 char *name;
9762
Denys Vlasenkob8ab27b2017-07-26 19:22:34 +02009763 if (!localvar_stack)
Ron Yorstonef2386b2015-10-29 16:19:14 +00009764 ash_msg_and_raise_error("not in a function");
9765
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009766 argv = argptr;
9767 while ((name = *argv++) != NULL) {
9768 mklocal(name);
9769 }
9770 return 0;
9771}
9772
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009773static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009774falsecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009775{
9776 return 1;
9777}
9778
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009779static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009780truecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009781{
9782 return 0;
9783}
9784
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009785static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009786execcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009787{
Denys Vlasenko6c149f42017-04-12 21:31:32 +02009788 optionarg = NULL;
9789 while (nextopt("a:") != '\0')
9790 /* nextopt() sets optionarg to "-a ARGV0" */;
9791
9792 argv = argptr;
9793 if (argv[0]) {
9794 char *prog;
9795
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009796 iflag = 0; /* exit on error */
9797 mflag = 0;
9798 optschanged();
Denys Vlasenkoe5814a52016-07-16 18:33:55 +02009799 /* We should set up signals for "exec CMD"
9800 * the same way as for "CMD" without "exec".
9801 * But optschanged->setinteractive->setsignal
9802 * still thought we are a root shell. Therefore, for example,
9803 * SIGQUIT is still set to IGN. Fix it:
9804 */
9805 shlvl++;
9806 setsignal(SIGQUIT);
9807 /*setsignal(SIGTERM); - unnecessary because of iflag=0 */
9808 /*setsignal(SIGTSTP); - unnecessary because of mflag=0 */
9809 /*setsignal(SIGTTOU); - unnecessary because of mflag=0 */
9810
Denys Vlasenko6c149f42017-04-12 21:31:32 +02009811 prog = argv[0];
9812 if (optionarg)
9813 argv[0] = optionarg;
9814 shellexec(prog, argv, pathval(), 0);
Denys Vlasenkoe5814a52016-07-16 18:33:55 +02009815 /* NOTREACHED */
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009816 }
9817 return 0;
9818}
9819
9820/*
9821 * The return command.
9822 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009823static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009824returncmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009825{
9826 /*
9827 * If called outside a function, do what ksh does;
9828 * skip the rest of the file.
9829 */
Denys Vlasenko6a0710e2016-09-30 14:18:34 +02009830 evalskip = SKIPFUNC;
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009831 return argv[1] ? number(argv[1]) : exitstatus;
9832}
9833
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009834/* Forward declarations for builtintab[] */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009835static int breakcmd(int, char **) FAST_FUNC;
9836static int dotcmd(int, char **) FAST_FUNC;
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009837static int evalcmd(int, char **, int) FAST_FUNC;
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009838static int exitcmd(int, char **) FAST_FUNC;
9839static int exportcmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009840#if ENABLE_ASH_GETOPTS
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009841static int getoptscmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009842#endif
Denys Vlasenko2ec34962014-09-08 16:52:39 +02009843#if ENABLE_ASH_HELP
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009844static int helpcmd(int, char **) FAST_FUNC;
Denis Vlasenko52764022007-02-24 13:42:56 +00009845#endif
Flemming Madsend96ffda2013-04-07 18:47:24 +02009846#if MAX_HISTORY
9847static int historycmd(int, char **) FAST_FUNC;
9848#endif
Denys Vlasenko0b883582016-12-23 16:49:07 +01009849#if ENABLE_FEATURE_SH_MATH
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009850static int letcmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009851#endif
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009852static int readcmd(int, char **) FAST_FUNC;
9853static int setcmd(int, char **) FAST_FUNC;
9854static int shiftcmd(int, char **) FAST_FUNC;
9855static int timescmd(int, char **) FAST_FUNC;
9856static int trapcmd(int, char **) FAST_FUNC;
9857static int umaskcmd(int, char **) FAST_FUNC;
9858static int unsetcmd(int, char **) FAST_FUNC;
9859static int ulimitcmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009860
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009861#define BUILTIN_NOSPEC "0"
9862#define BUILTIN_SPECIAL "1"
9863#define BUILTIN_REGULAR "2"
9864#define BUILTIN_SPEC_REG "3"
9865#define BUILTIN_ASSIGN "4"
9866#define BUILTIN_SPEC_ASSG "5"
9867#define BUILTIN_REG_ASSG "6"
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009868#define BUILTIN_SPEC_REG_ASSG "7"
9869
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009870/* Stubs for calling non-FAST_FUNC's */
Denys Vlasenko265062d2017-01-10 15:13:30 +01009871#if ENABLE_ASH_ECHO
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009872static int FAST_FUNC echocmd(int argc, char **argv) { return echo_main(argc, argv); }
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009873#endif
Denys Vlasenko265062d2017-01-10 15:13:30 +01009874#if ENABLE_ASH_PRINTF
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009875static int FAST_FUNC printfcmd(int argc, char **argv) { return printf_main(argc, argv); }
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009876#endif
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01009877#if ENABLE_ASH_TEST || BASH_TEST2
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009878static int FAST_FUNC testcmd(int argc, char **argv) { return test_main(argc, argv); }
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009879#endif
Denis Vlasenko468aea22008-04-01 14:47:57 +00009880
Denis Vlasenkof7d56652008-03-25 05:51:41 +00009881/* Keep these in proper order since it is searched via bsearch() */
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009882static const struct builtincmd builtintab[] = {
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009883 { BUILTIN_SPEC_REG "." , dotcmd },
9884 { BUILTIN_SPEC_REG ":" , truecmd },
Denys Vlasenko265062d2017-01-10 15:13:30 +01009885#if ENABLE_ASH_TEST
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009886 { BUILTIN_REGULAR "[" , testcmd },
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01009887#endif
9888#if BASH_TEST2
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009889 { BUILTIN_REGULAR "[[" , testcmd },
Denis Vlasenko80591b02008-03-25 07:49:43 +00009890#endif
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009891#if ENABLE_ASH_ALIAS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009892 { BUILTIN_REG_ASSG "alias" , aliascmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009893#endif
9894#if JOBS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009895 { BUILTIN_REGULAR "bg" , fg_bgcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009896#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009897 { BUILTIN_SPEC_REG "break" , breakcmd },
9898 { BUILTIN_REGULAR "cd" , cdcmd },
9899 { BUILTIN_NOSPEC "chdir" , cdcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009900#if ENABLE_ASH_CMDCMD
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009901 { BUILTIN_REGULAR "command" , commandcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009902#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009903 { BUILTIN_SPEC_REG "continue", breakcmd },
Denys Vlasenko265062d2017-01-10 15:13:30 +01009904#if ENABLE_ASH_ECHO
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009905 { BUILTIN_REGULAR "echo" , echocmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009906#endif
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009907 { BUILTIN_SPEC_REG "eval" , NULL }, /*evalcmd() has a differing prototype*/
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009908 { BUILTIN_SPEC_REG "exec" , execcmd },
9909 { BUILTIN_SPEC_REG "exit" , exitcmd },
9910 { BUILTIN_SPEC_REG_ASSG "export" , exportcmd },
9911 { BUILTIN_REGULAR "false" , falsecmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009912#if JOBS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009913 { BUILTIN_REGULAR "fg" , fg_bgcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009914#endif
9915#if ENABLE_ASH_GETOPTS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009916 { BUILTIN_REGULAR "getopts" , getoptscmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009917#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009918 { BUILTIN_NOSPEC "hash" , hashcmd },
Denys Vlasenko2ec34962014-09-08 16:52:39 +02009919#if ENABLE_ASH_HELP
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009920 { BUILTIN_NOSPEC "help" , helpcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009921#endif
Flemming Madsend96ffda2013-04-07 18:47:24 +02009922#if MAX_HISTORY
9923 { BUILTIN_NOSPEC "history" , historycmd },
9924#endif
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009925#if JOBS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009926 { BUILTIN_REGULAR "jobs" , jobscmd },
9927 { BUILTIN_REGULAR "kill" , killcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009928#endif
Denys Vlasenko0b883582016-12-23 16:49:07 +01009929#if ENABLE_FEATURE_SH_MATH
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009930 { BUILTIN_NOSPEC "let" , letcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009931#endif
Denys Vlasenko85241c72017-07-26 20:00:08 +02009932 { BUILTIN_SPEC_REG_ASSG "local" , localcmd },
Denys Vlasenko265062d2017-01-10 15:13:30 +01009933#if ENABLE_ASH_PRINTF
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009934 { BUILTIN_REGULAR "printf" , printfcmd },
Denis Vlasenkocd2663f2008-06-01 22:36:39 +00009935#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009936 { BUILTIN_NOSPEC "pwd" , pwdcmd },
9937 { BUILTIN_REGULAR "read" , readcmd },
9938 { BUILTIN_SPEC_REG_ASSG "readonly", exportcmd },
9939 { BUILTIN_SPEC_REG "return" , returncmd },
9940 { BUILTIN_SPEC_REG "set" , setcmd },
9941 { BUILTIN_SPEC_REG "shift" , shiftcmd },
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01009942#if BASH_SOURCE
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009943 { BUILTIN_SPEC_REG "source" , dotcmd },
Denys Vlasenko82731b42010-05-17 17:49:52 +02009944#endif
Denys Vlasenko265062d2017-01-10 15:13:30 +01009945#if ENABLE_ASH_TEST
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009946 { BUILTIN_REGULAR "test" , testcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009947#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009948 { BUILTIN_SPEC_REG "times" , timescmd },
9949 { BUILTIN_SPEC_REG "trap" , trapcmd },
9950 { BUILTIN_REGULAR "true" , truecmd },
9951 { BUILTIN_NOSPEC "type" , typecmd },
9952 { BUILTIN_NOSPEC "ulimit" , ulimitcmd },
9953 { BUILTIN_REGULAR "umask" , umaskcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009954#if ENABLE_ASH_ALIAS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009955 { BUILTIN_REGULAR "unalias" , unaliascmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009956#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009957 { BUILTIN_SPEC_REG "unset" , unsetcmd },
9958 { BUILTIN_REGULAR "wait" , waitcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009959};
9960
Denis Vlasenko80591b02008-03-25 07:49:43 +00009961/* Should match the above table! */
9962#define COMMANDCMD (builtintab + \
Denys Vlasenko928e2a72016-09-29 00:30:31 +02009963 /* . : */ 2 + \
Denys Vlasenko265062d2017-01-10 15:13:30 +01009964 /* [ */ 1 * ENABLE_ASH_TEST + \
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01009965 /* [[ */ 1 * BASH_TEST2 + \
Denys Vlasenko928e2a72016-09-29 00:30:31 +02009966 /* alias */ 1 * ENABLE_ASH_ALIAS + \
9967 /* bg */ 1 * ENABLE_ASH_JOB_CONTROL + \
9968 /* break cd cddir */ 3)
9969#define EVALCMD (COMMANDCMD + \
9970 /* command */ 1 * ENABLE_ASH_CMDCMD + \
9971 /* continue */ 1 + \
Denys Vlasenko265062d2017-01-10 15:13:30 +01009972 /* echo */ 1 * ENABLE_ASH_ECHO + \
Denys Vlasenko928e2a72016-09-29 00:30:31 +02009973 0)
9974#define EXECCMD (EVALCMD + \
9975 /* eval */ 1)
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009976
9977/*
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009978 * Search the table of builtin commands.
9979 */
Denys Vlasenko888527c2016-10-02 16:54:17 +02009980static int
9981pstrcmp1(const void *a, const void *b)
9982{
9983 return strcmp((char*)a, *(char**)b + 1);
9984}
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009985static struct builtincmd *
9986find_builtin(const char *name)
9987{
9988 struct builtincmd *bp;
9989
9990 bp = bsearch(
Denis Vlasenko80b8b392007-06-25 10:55:35 +00009991 name, builtintab, ARRAY_SIZE(builtintab), sizeof(builtintab[0]),
Denys Vlasenko888527c2016-10-02 16:54:17 +02009992 pstrcmp1
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009993 );
9994 return bp;
9995}
9996
9997/*
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009998 * Execute a simple command.
9999 */
Denys Vlasenko1c5eb882018-08-05 17:07:26 +020010000static void unwindfiles(struct parsefile *stop);
Denis Vlasenko4fe15f32007-02-23 01:05:26 +000010001static int
10002isassignment(const char *p)
Paul Foxc3850c82005-07-20 18:23:39 +000010003{
10004 const char *q = endofname(p);
10005 if (p == q)
10006 return 0;
10007 return *q == '=';
10008}
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010009static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010010bltincmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenko4fe15f32007-02-23 01:05:26 +000010011{
10012 /* Preserve exitstatus of a previous possible redirection
10013 * as POSIX mandates */
10014 return back_exitstatus;
10015}
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020010016static int
Eric Andersenc470f442003-07-28 09:56:35 +000010017evalcommand(union node *cmd, int flags)
10018{
Denis Vlasenko0e6f6612008-02-15 15:02:15 +000010019 static const struct builtincmd null_bltin = {
10020 "\0\0", bltincmd /* why three NULs? */
Denis Vlasenko4fe15f32007-02-23 01:05:26 +000010021 };
Denys Vlasenko484fc202017-07-26 19:55:31 +020010022 struct localvar_list *localvar_stop;
Denys Vlasenko1c5eb882018-08-05 17:07:26 +020010023 struct parsefile *file_stop;
Denys Vlasenko1c79aeb2017-07-29 22:51:52 +020010024 struct redirtab *redir_stop;
Eric Andersenc470f442003-07-28 09:56:35 +000010025 union node *argp;
10026 struct arglist arglist;
10027 struct arglist varlist;
10028 char **argv;
10029 int argc;
Glenn L McGrath7b8765c2003-08-29 07:29:30 +000010030 const struct strlist *sp;
Eric Andersenc470f442003-07-28 09:56:35 +000010031 struct cmdentry cmdentry;
10032 struct job *jp;
10033 char *lastarg;
10034 const char *path;
10035 int spclbltin;
Eric Andersenc470f442003-07-28 09:56:35 +000010036 int status;
10037 char **nargv;
Denis Vlasenko34c73c42008-08-16 11:48:02 +000010038 smallint cmd_is_exec;
Eric Andersenc470f442003-07-28 09:56:35 +000010039
Denys Vlasenko675d24a2018-01-27 22:02:05 +010010040 errlinno = lineno = cmd->ncmd.linno;
10041 if (funcline)
10042 lineno -= funcline - 1;
10043
Eric Andersenc470f442003-07-28 09:56:35 +000010044 /* First expand the arguments. */
10045 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
Denys Vlasenko484fc202017-07-26 19:55:31 +020010046 localvar_stop = pushlocalvars();
Denys Vlasenko1c5eb882018-08-05 17:07:26 +020010047 file_stop = g_parsefile;
Eric Andersenc470f442003-07-28 09:56:35 +000010048 back_exitstatus = 0;
10049
10050 cmdentry.cmdtype = CMDBUILTIN;
Denis Vlasenko0e6f6612008-02-15 15:02:15 +000010051 cmdentry.u.cmd = &null_bltin;
Eric Andersenc470f442003-07-28 09:56:35 +000010052 varlist.lastp = &varlist.list;
10053 *varlist.lastp = NULL;
10054 arglist.lastp = &arglist.list;
10055 *arglist.lastp = NULL;
10056
10057 argc = 0;
Denis Vlasenkob012b102007-02-19 22:43:01 +000010058 if (cmd->ncmd.args) {
Denys Vlasenkod07a15b2017-07-30 16:51:05 +020010059 struct builtincmd *bcmd;
10060 smallint pseudovarflag;
10061
Paul Foxc3850c82005-07-20 18:23:39 +000010062 bcmd = find_builtin(cmd->ncmd.args->narg.text);
10063 pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd);
Paul Foxc3850c82005-07-20 18:23:39 +000010064
Denys Vlasenkod07a15b2017-07-30 16:51:05 +020010065 for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) {
10066 struct strlist **spp;
Eric Andersenc470f442003-07-28 09:56:35 +000010067
Denys Vlasenkod07a15b2017-07-30 16:51:05 +020010068 spp = arglist.lastp;
10069 if (pseudovarflag && isassignment(argp->narg.text))
10070 expandarg(argp, &arglist, EXP_VARTILDE);
10071 else
10072 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
Paul Foxc3850c82005-07-20 18:23:39 +000010073
Denys Vlasenkod07a15b2017-07-30 16:51:05 +020010074 for (sp = *spp; sp; sp = sp->next)
10075 argc++;
10076 }
Eric Andersenc470f442003-07-28 09:56:35 +000010077 }
10078
Denys Vlasenko65a8b852016-10-26 22:29:11 +020010079 /* Reserve one extra spot at the front for shellexec. */
10080 nargv = stalloc(sizeof(char *) * (argc + 2));
10081 argv = ++nargv;
Denis Vlasenko2da584f2007-02-19 22:44:05 +000010082 for (sp = arglist.list; sp; sp = sp->next) {
Eric Andersenc470f442003-07-28 09:56:35 +000010083 TRACE(("evalcommand arg: %s\n", sp->text));
10084 *nargv++ = sp->text;
10085 }
10086 *nargv = NULL;
10087
10088 lastarg = NULL;
Denys Vlasenko675d24a2018-01-27 22:02:05 +010010089 if (iflag && funcline == 0 && argc > 0)
Eric Andersenc470f442003-07-28 09:56:35 +000010090 lastarg = nargv[-1];
10091
10092 expredir(cmd->ncmd.redirect);
Denys Vlasenko1c79aeb2017-07-29 22:51:52 +020010093 redir_stop = pushredir(cmd->ncmd.redirect);
Denys Vlasenkod07a15b2017-07-30 16:51:05 +020010094 preverrout_fd = 2;
Denys Vlasenkof8cdc7a2017-08-04 15:24:49 +020010095 if (BASH_XTRACEFD && xflag) {
10096 /* NB: bash closes fd == $BASH_XTRACEFD when it is changed.
10097 * we do not emulate this. We only use its value.
10098 */
10099 const char *xtracefd = lookupvar("BASH_XTRACEFD");
10100 if (xtracefd && is_number(xtracefd))
10101 preverrout_fd = atoi(xtracefd);
10102
10103 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010104 status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH | REDIR_SAVEFD2);
Eric Andersenc470f442003-07-28 09:56:35 +000010105
Denys Vlasenko8837c5d2010-06-02 12:56:18 +020010106 path = vpath.var_text;
Eric Andersenc470f442003-07-28 09:56:35 +000010107 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
10108 struct strlist **spp;
10109 char *p;
10110
10111 spp = varlist.lastp;
10112 expandarg(argp, &varlist, EXP_VARTILDE);
10113
Denys Vlasenko981a0562017-07-26 19:53:11 +020010114 mklocal((*spp)->text);
10115
Eric Andersenc470f442003-07-28 09:56:35 +000010116 /*
10117 * Modify the command lookup path, if a PATH= assignment
10118 * is present
10119 */
10120 p = (*spp)->text;
Denys Vlasenko8837c5d2010-06-02 12:56:18 +020010121 if (varcmp(p, path) == 0)
Eric Andersenc470f442003-07-28 09:56:35 +000010122 path = p;
10123 }
10124
10125 /* Print the command if xflag is set. */
10126 if (xflag) {
Denys Vlasenko42ba7572017-07-21 13:20:14 +020010127 const char *pfx = "";
Eric Andersenc470f442003-07-28 09:56:35 +000010128
Denys Vlasenko46999802017-07-29 21:12:29 +020010129 fdprintf(preverrout_fd, "%s", expandstr(ps4val(), DQSYNTAX));
Denys Vlasenko42ba7572017-07-21 13:20:14 +020010130
Glenn L McGrath7b8765c2003-08-29 07:29:30 +000010131 sp = varlist.list;
Denys Vlasenko42ba7572017-07-21 13:20:14 +020010132 while (sp) {
10133 char *varval = sp->text;
10134 char *eq = strchrnul(varval, '=');
10135 if (*eq)
10136 eq++;
10137 fdprintf(preverrout_fd, "%s%.*s%s",
10138 pfx,
10139 (int)(eq - varval), varval,
10140 maybe_single_quote(eq)
10141 );
10142 sp = sp->next;
10143 pfx = " ";
10144 }
10145
10146 sp = arglist.list;
10147 while (sp) {
10148 fdprintf(preverrout_fd, "%s%s",
10149 pfx,
10150 /* always quote if matches reserved word: */
10151 findkwd(sp->text)
10152 ? single_quote(sp->text)
10153 : maybe_single_quote(sp->text)
10154 );
10155 sp = sp->next;
10156 pfx = " ";
Glenn L McGrath7b8765c2003-08-29 07:29:30 +000010157 }
Denis Vlasenko0e6f6612008-02-15 15:02:15 +000010158 safe_write(preverrout_fd, "\n", 1);
Eric Andersenc470f442003-07-28 09:56:35 +000010159 }
10160
10161 cmd_is_exec = 0;
10162 spclbltin = -1;
10163
10164 /* Now locate the command. */
10165 if (argc) {
Eric Andersenc470f442003-07-28 09:56:35 +000010166 int cmd_flag = DO_ERR;
Denys Vlasenko0b4980c2012-09-25 12:49:29 +020010167#if ENABLE_ASH_CMDCMD
10168 const char *oldpath = path + 5;
10169#endif
Eric Andersenc470f442003-07-28 09:56:35 +000010170 path += 5;
Eric Andersenc470f442003-07-28 09:56:35 +000010171 for (;;) {
10172 find_command(argv[0], &cmdentry, cmd_flag, path);
10173 if (cmdentry.cmdtype == CMDUNKNOWN) {
Denys Vlasenko8131eea2009-11-02 14:19:51 +010010174 flush_stdout_stderr();
Denis Vlasenko6514c5e2008-07-24 13:41:37 +000010175 status = 127;
Eric Andersenc470f442003-07-28 09:56:35 +000010176 goto bail;
10177 }
10178
10179 /* implement bltin and command here */
10180 if (cmdentry.cmdtype != CMDBUILTIN)
10181 break;
10182 if (spclbltin < 0)
10183 spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd);
10184 if (cmdentry.u.cmd == EXECCMD)
Denis Vlasenko34c73c42008-08-16 11:48:02 +000010185 cmd_is_exec = 1;
Denis Vlasenko131ae172007-02-18 13:00:19 +000010186#if ENABLE_ASH_CMDCMD
Eric Andersenc470f442003-07-28 09:56:35 +000010187 if (cmdentry.u.cmd == COMMANDCMD) {
Eric Andersenc470f442003-07-28 09:56:35 +000010188 path = oldpath;
10189 nargv = parse_command_args(argv, &path);
10190 if (!nargv)
10191 break;
Denys Vlasenkocac4d002016-10-01 03:02:25 +020010192 /* It's "command [-p] PROG ARGS" (that is, no -Vv).
10193 * nargv => "PROG". path is updated if -p.
10194 */
Eric Andersenc470f442003-07-28 09:56:35 +000010195 argc -= nargv - argv;
10196 argv = nargv;
10197 cmd_flag |= DO_NOFUNC;
10198 } else
10199#endif
10200 break;
10201 }
10202 }
10203
10204 if (status) {
Ron Yorstonea7d2f62017-01-03 11:18:23 +010010205 bail:
10206 exitstatus = status;
10207
Eric Andersenc470f442003-07-28 09:56:35 +000010208 /* We have a redirection error. */
10209 if (spclbltin > 0)
Denis Vlasenkob012b102007-02-19 22:43:01 +000010210 raise_exception(EXERROR);
Ron Yorstonea7d2f62017-01-03 11:18:23 +010010211
Eric Andersenc470f442003-07-28 09:56:35 +000010212 goto out;
10213 }
10214
10215 /* Execute the command. */
10216 switch (cmdentry.cmdtype) {
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +020010217 default: {
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +000010218
Denys Vlasenko1750d3a2018-01-15 00:41:04 +010010219#if ENABLE_FEATURE_SH_STANDALONE \
10220 && ENABLE_FEATURE_SH_NOFORK \
10221 && NUM_APPLETS > 1
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +020010222/* (1) BUG: if variables are set, we need to fork, or save/restore them
10223 * around run_nofork_applet() call.
10224 * (2) Should this check also be done in forkshell()?
10225 * (perhaps it should, so that "VAR=VAL nofork" at least avoids exec...)
10226 */
Denis Vlasenko7465dbc2008-04-13 02:25:53 +000010227 /* find_command() encodes applet_no as (-2 - applet_no) */
10228 int applet_no = (- cmdentry.u.index - 2);
Denis Vlasenko9bc80d72008-04-12 20:07:53 +000010229 if (applet_no >= 0 && APPLET_IS_NOFORK(applet_no)) {
Denys Vlasenkoa5060b82017-11-03 14:16:25 +010010230 char **sv_environ;
10231
10232 INT_OFF;
10233 sv_environ = environ;
10234 environ = listvars(VEXPORT, VUNSET, varlist.list, /*end:*/ NULL);
Denys Vlasenkod329e342017-08-04 14:50:03 +020010235 /*
10236 * Run <applet>_main().
10237 * Signals (^C) can't interrupt here.
10238 * Otherwise we can mangle stdio or malloc internal state.
10239 * This makes applets which can run for a long time
10240 * and/or wait for user input ineligible for NOFORK:
10241 * for example, "yes" or "rm" (rm -i waits for input).
10242 */
Ron Yorston5ccb0e92016-10-20 12:24:02 +010010243 status = run_nofork_applet(applet_no, argv);
Denys Vlasenkoa5060b82017-11-03 14:16:25 +010010244 environ = sv_environ;
Denys Vlasenkod329e342017-08-04 14:50:03 +020010245 /*
10246 * Try enabling NOFORK for "yes" applet.
10247 * ^C _will_ stop it (write returns EINTR),
10248 * but this causes stdout FILE to be stuck
10249 * and needing clearerr(). What if other applets
10250 * also can get EINTRs? Do we need to switch
10251 * our signals to SA_RESTART?
10252 */
10253 /*clearerr(stdout);*/
10254 INT_ON;
Denis Vlasenko9bc80d72008-04-12 20:07:53 +000010255 break;
10256 }
Denis Vlasenko9bc80d72008-04-12 20:07:53 +000010257#endif
Denys Vlasenkocfd392b2017-08-03 19:56:29 +020010258 /* Can we avoid forking? For example, very last command
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +020010259 * in a script or a subshell does not need forking,
10260 * we can just exec it.
10261 */
Denys Vlasenko238bf182010-05-18 15:49:07 +020010262 if (!(flags & EV_EXIT) || may_have_traps) {
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +020010263 /* No, forking off a child is necessary */
Denis Vlasenkob012b102007-02-19 22:43:01 +000010264 INT_OFF;
Denys Vlasenko098b7132017-01-11 19:59:03 +010010265 get_tty_state();
Denis Vlasenko68404f12008-03-17 09:00:54 +000010266 jp = makejob(/*cmd,*/ 1);
Eric Andersenc470f442003-07-28 09:56:35 +000010267 if (forkshell(jp, cmd, FORK_FG) != 0) {
Denys Vlasenko238bf182010-05-18 15:49:07 +020010268 /* parent */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020010269 status = waitforjob(jp);
Denis Vlasenkob012b102007-02-19 22:43:01 +000010270 INT_ON;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020010271 TRACE(("forked child exited with %d\n", status));
Eric Andersenc470f442003-07-28 09:56:35 +000010272 break;
10273 }
Denys Vlasenko238bf182010-05-18 15:49:07 +020010274 /* child */
Denis Vlasenkob012b102007-02-19 22:43:01 +000010275 FORCE_INT_ON;
Denys Vlasenkoc7f95d22010-05-18 15:52:23 +020010276 /* fall through to exec'ing external program */
Eric Andersenc470f442003-07-28 09:56:35 +000010277 }
10278 listsetvar(varlist.list, VEXPORT|VSTACK);
Denys Vlasenkoe139ae32017-04-12 21:02:33 +020010279 shellexec(argv[0], argv, path, cmdentry.u.index);
Eric Andersenc470f442003-07-28 09:56:35 +000010280 /* NOTREACHED */
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +020010281 } /* default */
Eric Andersenc470f442003-07-28 09:56:35 +000010282 case CMDBUILTIN:
Denys Vlasenko85241c72017-07-26 20:00:08 +020010283 if (spclbltin > 0 || argc == 0) {
10284 poplocalvars(1);
10285 if (cmd_is_exec && argc > 1)
10286 listsetvar(varlist.list, VEXPORT);
10287 }
Denys Vlasenko981a0562017-07-26 19:53:11 +020010288
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +000010289 /* Tight loop with builtins only:
10290 * "while kill -0 $child; do true; done"
10291 * will never exit even if $child died, unless we do this
10292 * to reap the zombie and make kill detect that it's gone: */
10293 dowait(DOWAIT_NONBLOCK, NULL);
10294
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020010295 if (evalbltin(cmdentry.u.cmd, argc, argv, flags)) {
Denys Vlasenkoc0663c72016-10-27 21:09:01 +020010296 if (exception_type == EXERROR && spclbltin <= 0) {
10297 FORCE_INT_ON;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020010298 goto readstatus;
Eric Andersenc470f442003-07-28 09:56:35 +000010299 }
Denys Vlasenkoc0663c72016-10-27 21:09:01 +020010300 raise:
10301 longjmp(exception_handler->loc, 1);
Eric Andersenc470f442003-07-28 09:56:35 +000010302 }
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020010303 goto readstatus;
Eric Andersenc470f442003-07-28 09:56:35 +000010304
10305 case CMDFUNCTION:
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +000010306 /* See above for the rationale */
10307 dowait(DOWAIT_NONBLOCK, NULL);
Eric Andersenc470f442003-07-28 09:56:35 +000010308 if (evalfun(cmdentry.u.func, argc, argv, flags))
10309 goto raise;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020010310 readstatus:
10311 status = exitstatus;
Eric Andersenc470f442003-07-28 09:56:35 +000010312 break;
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +020010313 } /* switch */
Eric Andersenc470f442003-07-28 09:56:35 +000010314
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010315 out:
Denys Vlasenkoeaf94362016-10-25 21:46:03 +020010316 if (cmd->ncmd.redirect)
Denys Vlasenko035486c2017-07-31 04:09:19 +020010317 popredir(/*drop:*/ cmd_is_exec);
Denys Vlasenko1c79aeb2017-07-29 22:51:52 +020010318 unwindredir(redir_stop);
Denys Vlasenko1c5eb882018-08-05 17:07:26 +020010319 unwindfiles(file_stop);
Denys Vlasenko484fc202017-07-26 19:55:31 +020010320 unwindlocalvars(localvar_stop);
Denis Vlasenko6514c5e2008-07-24 13:41:37 +000010321 if (lastarg) {
Eric Andersenc470f442003-07-28 09:56:35 +000010322 /* dsl: I think this is intended to be used to support
10323 * '_' in 'vi' command mode during line editing...
10324 * However I implemented that within libedit itself.
10325 */
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020010326 setvar0("_", lastarg);
Denis Vlasenko6514c5e2008-07-24 13:41:37 +000010327 }
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020010328
10329 return status;
Eric Andersenc470f442003-07-28 09:56:35 +000010330}
10331
10332static int
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020010333evalbltin(const struct builtincmd *cmd, int argc, char **argv, int flags)
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010334{
Eric Andersenc470f442003-07-28 09:56:35 +000010335 char *volatile savecmdname;
10336 struct jmploc *volatile savehandler;
10337 struct jmploc jmploc;
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020010338 int status;
Eric Andersenc470f442003-07-28 09:56:35 +000010339 int i;
10340
10341 savecmdname = commandname;
Denys Vlasenkoa2d121c2016-09-30 11:30:11 +020010342 savehandler = exception_handler;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010343 i = setjmp(jmploc.loc);
10344 if (i)
Eric Andersenc470f442003-07-28 09:56:35 +000010345 goto cmddone;
Denis Vlasenko2da584f2007-02-19 22:44:05 +000010346 exception_handler = &jmploc;
Eric Andersenc470f442003-07-28 09:56:35 +000010347 commandname = argv[0];
10348 argptr = argv + 1;
10349 optptr = NULL; /* initialize nextopt */
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020010350 if (cmd == EVALCMD)
10351 status = evalcmd(argc, argv, flags);
10352 else
10353 status = (*cmd->builtin)(argc, argv);
Denis Vlasenkob012b102007-02-19 22:43:01 +000010354 flush_stdout_stderr();
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020010355 status |= ferror(stdout);
10356 exitstatus = status;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010357 cmddone:
Rob Landleyf296f0b2006-07-06 01:09:21 +000010358 clearerr(stdout);
Eric Andersenc470f442003-07-28 09:56:35 +000010359 commandname = savecmdname;
Denis Vlasenko2da584f2007-02-19 22:44:05 +000010360 exception_handler = savehandler;
Eric Andersenc470f442003-07-28 09:56:35 +000010361
10362 return i;
10363}
10364
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010365static int
10366goodname(const char *p)
Glenn L McGrath16e45d72004-02-04 08:24:39 +000010367{
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +020010368 return endofname(p)[0] == '\0';
Glenn L McGrath16e45d72004-02-04 08:24:39 +000010369}
10370
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010371
Glenn L McGrath50812ff2002-08-23 13:14:48 +000010372/*
10373 * Search for a command. This is called before we fork so that the
10374 * location of the command will be available in the parent as well as
Glenn L McGrath16e45d72004-02-04 08:24:39 +000010375 * the child. The check for "goodname" is an overly conservative
10376 * check that the name will not be subject to expansion.
Glenn L McGrath50812ff2002-08-23 13:14:48 +000010377 */
Eric Andersenc470f442003-07-28 09:56:35 +000010378static void
10379prehash(union node *n)
Glenn L McGrath50812ff2002-08-23 13:14:48 +000010380{
10381 struct cmdentry entry;
10382
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000010383 if (n->type == NCMD && n->ncmd.args && goodname(n->ncmd.args->narg.text))
10384 find_command(n->ncmd.args->narg.text, &entry, 0, pathval());
Glenn L McGrath50812ff2002-08-23 13:14:48 +000010385}
10386
Eric Andersencb57d552001-06-28 07:25:16 +000010387
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000010388/* ============ Builtin commands
10389 *
10390 * Builtin commands whose functions are closely tied to evaluation
10391 * are implemented here.
Eric Andersencb57d552001-06-28 07:25:16 +000010392 */
10393
10394/*
Eric Andersencb57d552001-06-28 07:25:16 +000010395 * Handle break and continue commands. Break, continue, and return are
10396 * all handled by setting the evalskip flag. The evaluation routines
10397 * above all check this flag, and if it is set they start skipping
10398 * commands rather than executing them. The variable skipcount is
10399 * the number of loops to break/continue, or the number of function
10400 * levels to return. (The latter is always 1.) It should probably
10401 * be an error to break out of more loops than exist, but it isn't
10402 * in the standard shell so we don't make it one here.
10403 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010404static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010405breakcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000010406{
Denis Vlasenko68404f12008-03-17 09:00:54 +000010407 int n = argv[1] ? number(argv[1]) : 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010408
Aaron Lehmann2aef3a62001-12-31 06:03:12 +000010409 if (n <= 0)
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +020010410 ash_msg_and_raise_error(msg_illnum, argv[1]);
Eric Andersencb57d552001-06-28 07:25:16 +000010411 if (n > loopnest)
10412 n = loopnest;
10413 if (n > 0) {
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000010414 evalskip = (**argv == 'c') ? SKIPCONT : SKIPBREAK;
Eric Andersencb57d552001-06-28 07:25:16 +000010415 skipcount = n;
10416 }
10417 return 0;
10418}
10419
Eric Andersenc470f442003-07-28 09:56:35 +000010420
Denys Vlasenko70392332016-10-27 02:31:55 +020010421/*
Eric Andersen90898442003-08-06 11:20:52 +000010422 * This implements the input routines used by the parser.
Eric Andersencb57d552001-06-28 07:25:16 +000010423 */
Denis Vlasenko99eb8502007-02-23 21:09:49 +000010424
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010425enum {
10426 INPUT_PUSH_FILE = 1,
10427 INPUT_NOFILE_OK = 2,
10428};
Eric Andersencb57d552001-06-28 07:25:16 +000010429
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010430static smallint checkkwd;
Denis Vlasenko99eb8502007-02-23 21:09:49 +000010431/* values of checkkwd variable */
10432#define CHKALIAS 0x1
10433#define CHKKWD 0x2
10434#define CHKNL 0x4
Denys Vlasenkoa7328982017-07-29 19:57:28 +020010435#define CHKEOFMARK 0x8
Denis Vlasenko99eb8502007-02-23 21:09:49 +000010436
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010437/*
10438 * Push a string back onto the input at this current parsefile level.
10439 * We handle aliases this way.
10440 */
10441#if !ENABLE_ASH_ALIAS
10442#define pushstring(s, ap) pushstring(s)
10443#endif
10444static void
10445pushstring(char *s, struct alias *ap)
10446{
10447 struct strpush *sp;
10448 int len;
10449
10450 len = strlen(s);
10451 INT_OFF;
10452 if (g_parsefile->strpush) {
10453 sp = ckzalloc(sizeof(*sp));
10454 sp->prev = g_parsefile->strpush;
10455 } else {
10456 sp = &(g_parsefile->basestrpush);
10457 }
10458 g_parsefile->strpush = sp;
10459 sp->prev_string = g_parsefile->next_to_pgetc;
10460 sp->prev_left_in_line = g_parsefile->left_in_line;
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010461 sp->unget = g_parsefile->unget;
10462 memcpy(sp->lastc, g_parsefile->lastc, sizeof(sp->lastc));
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010463#if ENABLE_ASH_ALIAS
10464 sp->ap = ap;
10465 if (ap) {
10466 ap->flag |= ALIASINUSE;
10467 sp->string = s;
10468 }
10469#endif
10470 g_parsefile->next_to_pgetc = s;
10471 g_parsefile->left_in_line = len;
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010472 g_parsefile->unget = 0;
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010473 INT_ON;
10474}
10475
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010476static void
10477popstring(void)
Eric Andersenc470f442003-07-28 09:56:35 +000010478{
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010479 struct strpush *sp = g_parsefile->strpush;
Eric Andersenc470f442003-07-28 09:56:35 +000010480
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010481 INT_OFF;
Denis Vlasenko131ae172007-02-18 13:00:19 +000010482#if ENABLE_ASH_ALIAS
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010483 if (sp->ap) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010484 if (g_parsefile->next_to_pgetc[-1] == ' '
10485 || g_parsefile->next_to_pgetc[-1] == '\t'
10486 ) {
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010487 checkkwd |= CHKALIAS;
Glenn L McGrath28939ad2004-07-21 10:20:19 +000010488 }
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010489 if (sp->string != sp->ap->val) {
10490 free(sp->string);
10491 }
10492 sp->ap->flag &= ~ALIASINUSE;
10493 if (sp->ap->flag & ALIASDEAD) {
10494 unalias(sp->ap->name);
10495 }
Glenn L McGrath28939ad2004-07-21 10:20:19 +000010496 }
Denis Vlasenko8e1c7152007-01-22 07:21:38 +000010497#endif
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010498 g_parsefile->next_to_pgetc = sp->prev_string;
10499 g_parsefile->left_in_line = sp->prev_left_in_line;
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010500 g_parsefile->unget = sp->unget;
10501 memcpy(g_parsefile->lastc, sp->lastc, sizeof(sp->lastc));
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010502 g_parsefile->strpush = sp->prev;
10503 if (sp != &(g_parsefile->basestrpush))
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010504 free(sp);
10505 INT_ON;
10506}
Denis Vlasenko8e1c7152007-01-22 07:21:38 +000010507
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010508static int
10509preadfd(void)
Eric Andersencb57d552001-06-28 07:25:16 +000010510{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010511 int nr;
Denis Vlasenko6a0ad252008-07-25 13:34:05 +000010512 char *buf = g_parsefile->buf;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010513
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010514 g_parsefile->next_to_pgetc = buf;
Denis Vlasenko38f63192007-01-22 09:03:07 +000010515#if ENABLE_FEATURE_EDITING
Denis Vlasenko85c24712008-03-17 09:04:04 +000010516 retry:
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010517 if (!iflag || g_parsefile->pf_fd != STDIN_FILENO)
Ron Yorston61d6ae22015-04-19 10:50:25 +010010518 nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1);
Eric Andersenc470f442003-07-28 09:56:35 +000010519 else {
Denys Vlasenko66c5b122011-02-08 05:07:02 +010010520# if ENABLE_ASH_IDLE_TIMEOUT
Denys Vlasenko84ea60e2017-08-02 17:27:28 +020010521 int timeout = -1;
Denys Vlasenko66c5b122011-02-08 05:07:02 +010010522 if (iflag) {
10523 const char *tmout_var = lookupvar("TMOUT");
10524 if (tmout_var) {
10525 timeout = atoi(tmout_var) * 1000;
10526 if (timeout <= 0)
10527 timeout = -1;
10528 }
10529 }
Denys Vlasenko84ea60e2017-08-02 17:27:28 +020010530 line_input_state->timeout = timeout;
Denys Vlasenko66c5b122011-02-08 05:07:02 +010010531# endif
Denys Vlasenko8c52f802011-02-04 17:36:21 +010010532# if ENABLE_FEATURE_TAB_COMPLETION
Denis Vlasenko8e1c7152007-01-22 07:21:38 +000010533 line_input_state->path_lookup = pathval();
Denys Vlasenko8c52f802011-02-04 17:36:21 +010010534# endif
Denys Vlasenkoe9ab07c2014-08-13 18:00:08 +020010535 reinit_unicode_for_ash();
Denys Vlasenko84ea60e2017-08-02 17:27:28 +020010536 nr = read_line_input(line_input_state, cmdedit_prompt, buf, IBUFSIZ);
Denis Vlasenko8e1c7152007-01-22 07:21:38 +000010537 if (nr == 0) {
Denys Vlasenko4b89d512016-11-25 03:41:03 +010010538 /* ^C pressed, "convert" to SIGINT */
10539 write(STDOUT_FILENO, "^C", 2);
Denis Vlasenko8e1c7152007-01-22 07:21:38 +000010540 if (trap[SIGINT]) {
Glenn L McGrath16e45d72004-02-04 08:24:39 +000010541 buf[0] = '\n';
Denis Vlasenko8e1c7152007-01-22 07:21:38 +000010542 buf[1] = '\0';
Glenn L McGrath16e45d72004-02-04 08:24:39 +000010543 raise(SIGINT);
10544 return 1;
10545 }
Denys Vlasenko8660aeb2016-11-24 17:44:02 +010010546 exitstatus = 128 + SIGINT;
Denys Vlasenko4b89d512016-11-25 03:41:03 +010010547 bb_putchar('\n');
Eric Andersenc470f442003-07-28 09:56:35 +000010548 goto retry;
10549 }
Denys Vlasenko66c5b122011-02-08 05:07:02 +010010550 if (nr < 0) {
10551 if (errno == 0) {
10552 /* Ctrl+D pressed */
10553 nr = 0;
10554 }
10555# if ENABLE_ASH_IDLE_TIMEOUT
10556 else if (errno == EAGAIN && timeout > 0) {
Denys Vlasenkod60752f2015-10-07 22:42:45 +020010557 puts("\007timed out waiting for input: auto-logout");
Denys Vlasenko66c5b122011-02-08 05:07:02 +010010558 exitshell();
10559 }
10560# endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010561 }
Eric Andersencb57d552001-06-28 07:25:16 +000010562 }
10563#else
Ron Yorston61d6ae22015-04-19 10:50:25 +010010564 nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1);
Eric Andersencb57d552001-06-28 07:25:16 +000010565#endif
10566
Denys Vlasenko80c5b682011-05-08 21:21:10 +020010567#if 0 /* disabled: nonblock_immune_read() handles this problem */
Eric Andersencb57d552001-06-28 07:25:16 +000010568 if (nr < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +000010569 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
Denis Vlasenkod37f2222007-08-19 13:42:08 +000010570 int flags = fcntl(0, F_GETFL);
Denis Vlasenko9cb220b2007-12-09 10:03:28 +000010571 if (flags >= 0 && (flags & O_NONBLOCK)) {
10572 flags &= ~O_NONBLOCK;
Eric Andersencb57d552001-06-28 07:25:16 +000010573 if (fcntl(0, F_SETFL, flags) >= 0) {
10574 out2str("sh: turning off NDELAY mode\n");
10575 goto retry;
10576 }
10577 }
10578 }
10579 }
Denis Vlasenkoe376d452008-02-20 22:23:24 +000010580#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010581 return nr;
10582}
10583
10584/*
10585 * Refill the input buffer and return the next input character:
10586 *
10587 * 1) If a string was pushed back on the input, pop it;
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010588 * 2) If an EOF was pushed back (g_parsefile->left_in_line < -BIGNUM)
10589 * or we are reading from a string so we can't refill the buffer,
10590 * return EOF.
Denys Vlasenko883cea42009-07-11 15:31:59 +020010591 * 3) If there is more stuff in this buffer, use it else call read to fill it.
Eric Andersencb57d552001-06-28 07:25:16 +000010592 * 4) Process input up to the next newline, deleting nul characters.
10593 */
Denis Vlasenko727752d2008-11-28 03:41:47 +000010594//#define pgetc_debug(...) bb_error_msg(__VA_ARGS__)
10595#define pgetc_debug(...) ((void)0)
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010596static int pgetc(void);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010597static int
Eric Andersenc470f442003-07-28 09:56:35 +000010598preadbuffer(void)
Eric Andersencb57d552001-06-28 07:25:16 +000010599{
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010600 char *q;
Eric Andersencb57d552001-06-28 07:25:16 +000010601 int more;
Eric Andersencb57d552001-06-28 07:25:16 +000010602
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010603 if (g_parsefile->strpush) {
Denis Vlasenko131ae172007-02-18 13:00:19 +000010604#if ENABLE_ASH_ALIAS
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010605 if (g_parsefile->left_in_line == -1
10606 && g_parsefile->strpush->ap
10607 && g_parsefile->next_to_pgetc[-1] != ' '
10608 && g_parsefile->next_to_pgetc[-1] != '\t'
Denis Vlasenko16898402008-11-25 01:34:52 +000010609 ) {
Denis Vlasenko727752d2008-11-28 03:41:47 +000010610 pgetc_debug("preadbuffer PEOA");
Eric Andersencb57d552001-06-28 07:25:16 +000010611 return PEOA;
10612 }
Eric Andersen2870d962001-07-02 17:27:21 +000010613#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010614 popstring();
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010615 return pgetc();
Eric Andersencb57d552001-06-28 07:25:16 +000010616 }
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010617 /* on both branches above g_parsefile->left_in_line < 0.
Denis Vlasenko727752d2008-11-28 03:41:47 +000010618 * "pgetc" needs refilling.
10619 */
10620
Denis Vlasenkoe27dafd2008-11-28 04:01:03 +000010621 /* -90 is our -BIGNUM. Below we use -99 to mark "EOF on read",
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010622 * pungetc() may increment it a few times.
Denis Vlasenkoe27dafd2008-11-28 04:01:03 +000010623 * Assuming it won't increment it to less than -90.
Denis Vlasenko727752d2008-11-28 03:41:47 +000010624 */
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010625 if (g_parsefile->left_in_line < -90 || g_parsefile->buf == NULL) {
Denis Vlasenko727752d2008-11-28 03:41:47 +000010626 pgetc_debug("preadbuffer PEOF1");
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010627 /* even in failure keep left_in_line and next_to_pgetc
10628 * in lock step, for correct multi-layer pungetc.
10629 * left_in_line was decremented before preadbuffer(),
10630 * must inc next_to_pgetc: */
10631 g_parsefile->next_to_pgetc++;
Eric Andersencb57d552001-06-28 07:25:16 +000010632 return PEOF;
Denis Vlasenko727752d2008-11-28 03:41:47 +000010633 }
Eric Andersencb57d552001-06-28 07:25:16 +000010634
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010635 more = g_parsefile->left_in_buffer;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010636 if (more <= 0) {
Denis Vlasenko727752d2008-11-28 03:41:47 +000010637 flush_stdout_stderr();
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010638 again:
10639 more = preadfd();
10640 if (more <= 0) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010641 /* don't try reading again */
10642 g_parsefile->left_in_line = -99;
Denis Vlasenko727752d2008-11-28 03:41:47 +000010643 pgetc_debug("preadbuffer PEOF2");
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010644 g_parsefile->next_to_pgetc++;
Eric Andersencb57d552001-06-28 07:25:16 +000010645 return PEOF;
10646 }
10647 }
10648
Denis Vlasenko727752d2008-11-28 03:41:47 +000010649 /* Find out where's the end of line.
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010650 * Set g_parsefile->left_in_line
10651 * and g_parsefile->left_in_buffer acordingly.
Denis Vlasenko727752d2008-11-28 03:41:47 +000010652 * NUL chars are deleted.
10653 */
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010654 q = g_parsefile->next_to_pgetc;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010655 for (;;) {
Denis Vlasenko727752d2008-11-28 03:41:47 +000010656 char c;
Eric Andersencb57d552001-06-28 07:25:16 +000010657
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010658 more--;
Eric Andersenc470f442003-07-28 09:56:35 +000010659
Denis Vlasenko727752d2008-11-28 03:41:47 +000010660 c = *q;
10661 if (c == '\0') {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010662 memmove(q, q + 1, more);
Denis Vlasenko727752d2008-11-28 03:41:47 +000010663 } else {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010664 q++;
10665 if (c == '\n') {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010666 g_parsefile->left_in_line = q - g_parsefile->next_to_pgetc - 1;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010667 break;
10668 }
Eric Andersencb57d552001-06-28 07:25:16 +000010669 }
10670
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010671 if (more <= 0) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010672 g_parsefile->left_in_line = q - g_parsefile->next_to_pgetc - 1;
10673 if (g_parsefile->left_in_line < 0)
Eric Andersencb57d552001-06-28 07:25:16 +000010674 goto again;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010675 break;
Eric Andersencb57d552001-06-28 07:25:16 +000010676 }
10677 }
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010678 g_parsefile->left_in_buffer = more;
Eric Andersencb57d552001-06-28 07:25:16 +000010679
Eric Andersencb57d552001-06-28 07:25:16 +000010680 if (vflag) {
Denis Vlasenko727752d2008-11-28 03:41:47 +000010681 char save = *q;
10682 *q = '\0';
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010683 out2str(g_parsefile->next_to_pgetc);
Denis Vlasenko727752d2008-11-28 03:41:47 +000010684 *q = save;
Eric Andersencb57d552001-06-28 07:25:16 +000010685 }
10686
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010687 pgetc_debug("preadbuffer at %d:%p'%s'",
10688 g_parsefile->left_in_line,
10689 g_parsefile->next_to_pgetc,
10690 g_parsefile->next_to_pgetc);
Denys Vlasenkocd716832009-11-28 22:14:02 +010010691 return (unsigned char)*g_parsefile->next_to_pgetc++;
Eric Andersencb57d552001-06-28 07:25:16 +000010692}
10693
Denys Vlasenkoce332a22016-10-02 23:47:34 +020010694static void
10695nlprompt(void)
10696{
10697 g_parsefile->linno++;
10698 setprompt_if(doprompt, 2);
10699}
10700static void
10701nlnoprompt(void)
10702{
10703 g_parsefile->linno++;
10704 needprompt = doprompt;
10705}
10706
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010707static int
10708pgetc(void)
10709{
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010710 int c;
10711
10712 pgetc_debug("pgetc at %d:%p'%s'",
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010713 g_parsefile->left_in_line,
10714 g_parsefile->next_to_pgetc,
10715 g_parsefile->next_to_pgetc);
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010716 if (g_parsefile->unget)
10717 return g_parsefile->lastc[--g_parsefile->unget];
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010718
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010719 if (--g_parsefile->left_in_line >= 0)
Denys Vlasenko2fe66b12016-12-12 17:39:12 +010010720 c = (unsigned char)*g_parsefile->next_to_pgetc++;
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010721 else
10722 c = preadbuffer();
10723
10724 g_parsefile->lastc[1] = g_parsefile->lastc[0];
10725 g_parsefile->lastc[0] = c;
10726
10727 return c;
10728}
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010729
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010730#if ENABLE_ASH_ALIAS
10731static int
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010010732pgetc_without_PEOA(void)
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010733{
10734 int c;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010735 do {
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010736 pgetc_debug("pgetc at %d:%p'%s'",
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010737 g_parsefile->left_in_line,
10738 g_parsefile->next_to_pgetc,
10739 g_parsefile->next_to_pgetc);
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010740 c = pgetc();
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010741 } while (c == PEOA);
10742 return c;
10743}
10744#else
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010010745# define pgetc_without_PEOA() pgetc()
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010746#endif
10747
10748/*
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010749 * Undo a call to pgetc. Only two characters may be pushed back.
Eric Andersenc470f442003-07-28 09:56:35 +000010750 * PEOF may be pushed back.
10751 */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010752static void
Eric Andersenc470f442003-07-28 09:56:35 +000010753pungetc(void)
10754{
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010755 g_parsefile->unget++;
Eric Andersencb57d552001-06-28 07:25:16 +000010756}
10757
Denys Vlasenko73c3e072016-09-29 17:17:04 +020010758/* This one eats backslash+newline */
10759static int
10760pgetc_eatbnl(void)
10761{
10762 int c;
10763
10764 while ((c = pgetc()) == '\\') {
10765 if (pgetc() != '\n') {
10766 pungetc();
10767 break;
10768 }
10769
Denys Vlasenkoce332a22016-10-02 23:47:34 +020010770 nlprompt();
Denys Vlasenko73c3e072016-09-29 17:17:04 +020010771 }
10772
10773 return c;
10774}
10775
Denys Vlasenko216913c2018-04-02 12:35:04 +020010776struct synstack {
10777 smalluint syntax;
10778 uint8_t innerdq :1;
10779 uint8_t varpushed :1;
10780 uint8_t dblquote :1;
10781 int varnest; /* levels of variables expansion */
10782 int dqvarnest; /* levels of variables expansion within double quotes */
10783 int parenlevel; /* levels of parens in arithmetic */
10784 struct synstack *prev;
10785 struct synstack *next;
10786};
10787
10788static void
10789synstack_push(struct synstack **stack, struct synstack *next, int syntax)
10790{
10791 memset(next, 0, sizeof(*next));
10792 next->syntax = syntax;
10793 next->next = *stack;
10794 (*stack)->prev = next;
10795 *stack = next;
10796}
10797
10798static ALWAYS_INLINE void
10799synstack_pop(struct synstack **stack)
10800{
10801 *stack = (*stack)->next;
10802}
10803
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010804/*
10805 * To handle the "." command, a stack of input files is used. Pushfile
10806 * adds a new entry to the stack and popfile restores the previous level.
10807 */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010808static void
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010809pushfile(void)
Eric Andersenc470f442003-07-28 09:56:35 +000010810{
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010811 struct parsefile *pf;
10812
Denis Vlasenko597906c2008-02-20 16:38:54 +000010813 pf = ckzalloc(sizeof(*pf));
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010814 pf->prev = g_parsefile;
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010815 pf->pf_fd = -1;
Denis Vlasenko597906c2008-02-20 16:38:54 +000010816 /*pf->strpush = NULL; - ckzalloc did it */
10817 /*pf->basestrpush.prev = NULL;*/
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010818 /*pf->unget = 0;*/
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010819 g_parsefile = pf;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010820}
10821
10822static void
10823popfile(void)
10824{
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010825 struct parsefile *pf = g_parsefile;
Eric Andersenc470f442003-07-28 09:56:35 +000010826
Denys Vlasenko493b9ca2016-10-30 18:27:14 +010010827 if (pf == &basepf)
10828 return;
10829
Denis Vlasenkob012b102007-02-19 22:43:01 +000010830 INT_OFF;
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010831 if (pf->pf_fd >= 0)
10832 close(pf->pf_fd);
Denis Vlasenko60818682007-09-28 22:07:23 +000010833 free(pf->buf);
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010834 while (pf->strpush)
10835 popstring();
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010836 g_parsefile = pf->prev;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010837 free(pf);
Denis Vlasenkob012b102007-02-19 22:43:01 +000010838 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +000010839}
10840
Denys Vlasenko1c5eb882018-08-05 17:07:26 +020010841static void
10842unwindfiles(struct parsefile *stop)
10843{
10844 while (g_parsefile != stop)
10845 popfile();
10846}
10847
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010848/*
10849 * Return to top level.
10850 */
10851static void
10852popallfiles(void)
10853{
Denys Vlasenko1c5eb882018-08-05 17:07:26 +020010854 unwindfiles(&basepf);
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010855}
10856
10857/*
10858 * Close the file(s) that the shell is reading commands from. Called
10859 * after a fork is done.
10860 */
10861static void
10862closescript(void)
10863{
10864 popallfiles();
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010865 if (g_parsefile->pf_fd > 0) {
10866 close(g_parsefile->pf_fd);
10867 g_parsefile->pf_fd = 0;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010868 }
10869}
10870
10871/*
10872 * Like setinputfile, but takes an open file descriptor. Call this with
10873 * interrupts off.
10874 */
10875static void
10876setinputfd(int fd, int push)
10877{
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010878 if (push) {
10879 pushfile();
Denis Vlasenko727752d2008-11-28 03:41:47 +000010880 g_parsefile->buf = NULL;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010881 }
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010882 g_parsefile->pf_fd = fd;
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010883 if (g_parsefile->buf == NULL)
10884 g_parsefile->buf = ckmalloc(IBUFSIZ);
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010885 g_parsefile->left_in_buffer = 0;
10886 g_parsefile->left_in_line = 0;
10887 g_parsefile->linno = 1;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010888}
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010889
Eric Andersenc470f442003-07-28 09:56:35 +000010890/*
10891 * Set the input to take input from a file. If push is set, push the
10892 * old input onto the stack first.
10893 */
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010894static int
10895setinputfile(const char *fname, int flags)
Eric Andersenc470f442003-07-28 09:56:35 +000010896{
10897 int fd;
Eric Andersenc470f442003-07-28 09:56:35 +000010898
Denis Vlasenkob012b102007-02-19 22:43:01 +000010899 INT_OFF;
Denys Vlasenko60fb98e2018-03-30 22:15:14 +020010900 fd = open(fname, O_RDONLY | O_CLOEXEC);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010901 if (fd < 0) {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010902 if (flags & INPUT_NOFILE_OK)
10903 goto out;
Denys Vlasenkob7adf7a2016-10-25 17:00:13 +020010904 exitstatus = 127;
Johannes Schindelin20a63b22017-08-22 22:03:17 +020010905 ash_msg_and_raise_perror("can't open '%s'", fname);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010906 }
Denys Vlasenko64774602016-10-26 15:24:30 +020010907 if (fd < 10)
10908 fd = savefd(fd);
Denys Vlasenko60fb98e2018-03-30 22:15:14 +020010909 else if (O_CLOEXEC == 0) /* old libc */
Denys Vlasenkoe19923f2016-10-26 15:38:44 +020010910 close_on_exec_on(fd);
Denys Vlasenko60fb98e2018-03-30 22:15:14 +020010911
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010912 setinputfd(fd, flags & INPUT_PUSH_FILE);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010913 out:
Denis Vlasenkob012b102007-02-19 22:43:01 +000010914 INT_ON;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010915 return fd;
Eric Andersenc470f442003-07-28 09:56:35 +000010916}
10917
Eric Andersencb57d552001-06-28 07:25:16 +000010918/*
10919 * Like setinputfile, but takes input from a string.
10920 */
Eric Andersenc470f442003-07-28 09:56:35 +000010921static void
10922setinputstring(char *string)
Eric Andersen62483552001-07-10 06:09:16 +000010923{
Denis Vlasenkob012b102007-02-19 22:43:01 +000010924 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +000010925 pushfile();
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010926 g_parsefile->next_to_pgetc = string;
10927 g_parsefile->left_in_line = strlen(string);
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010928 g_parsefile->buf = NULL;
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010929 g_parsefile->linno = 1;
Denis Vlasenkob012b102007-02-19 22:43:01 +000010930 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +000010931}
10932
10933
Denys Vlasenko70392332016-10-27 02:31:55 +020010934/*
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010935 * Routines to check for mail.
Eric Andersencb57d552001-06-28 07:25:16 +000010936 */
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010937
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010938#if ENABLE_ASH_MAIL
Eric Andersencb57d552001-06-28 07:25:16 +000010939
Denys Vlasenko23841622015-10-09 15:52:03 +020010940/* Hash of mtimes of mailboxes */
10941static unsigned mailtime_hash;
Eric Andersenc470f442003-07-28 09:56:35 +000010942/* Set if MAIL or MAILPATH is changed. */
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010943static smallint mail_var_path_changed;
Eric Andersencb57d552001-06-28 07:25:16 +000010944
Eric Andersencb57d552001-06-28 07:25:16 +000010945/*
Eric Andersenc470f442003-07-28 09:56:35 +000010946 * Print appropriate message(s) if mail has arrived.
10947 * If mail_var_path_changed is set,
10948 * then the value of MAIL has mail_var_path_changed,
10949 * so we just update the values.
Eric Andersencb57d552001-06-28 07:25:16 +000010950 */
Eric Andersenc470f442003-07-28 09:56:35 +000010951static void
10952chkmail(void)
Eric Andersencb57d552001-06-28 07:25:16 +000010953{
Eric Andersencb57d552001-06-28 07:25:16 +000010954 const char *mpath;
10955 char *p;
10956 char *q;
Denys Vlasenko23841622015-10-09 15:52:03 +020010957 unsigned new_hash;
Eric Andersencb57d552001-06-28 07:25:16 +000010958 struct stackmark smark;
10959 struct stat statb;
10960
Eric Andersencb57d552001-06-28 07:25:16 +000010961 setstackmark(&smark);
Eric Andersenc470f442003-07-28 09:56:35 +000010962 mpath = mpathset() ? mpathval() : mailval();
Denys Vlasenko23841622015-10-09 15:52:03 +020010963 new_hash = 0;
10964 for (;;) {
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020010965 p = path_advance(&mpath, nullstr);
Eric Andersencb57d552001-06-28 07:25:16 +000010966 if (p == NULL)
10967 break;
10968 if (*p == '\0')
10969 continue;
Denis Vlasenkof7d56652008-03-25 05:51:41 +000010970 for (q = p; *q; q++)
10971 continue;
Denis Vlasenkoa7189f02006-11-17 20:29:00 +000010972#if DEBUG
Eric Andersencb57d552001-06-28 07:25:16 +000010973 if (q[-1] != '/')
10974 abort();
10975#endif
Eric Andersenc470f442003-07-28 09:56:35 +000010976 q[-1] = '\0'; /* delete trailing '/' */
10977 if (stat(p, &statb) < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +000010978 continue;
Eric Andersencb57d552001-06-28 07:25:16 +000010979 }
Denys Vlasenko23841622015-10-09 15:52:03 +020010980 /* Very simplistic "hash": just a sum of all mtimes */
10981 new_hash += (unsigned)statb.st_mtime;
10982 }
10983 if (!mail_var_path_changed && mailtime_hash != new_hash) {
Denys Vlasenko4cd99e72015-10-09 16:02:53 +020010984 if (mailtime_hash != 0)
10985 out2str("you have mail\n");
Denys Vlasenko23841622015-10-09 15:52:03 +020010986 mailtime_hash = new_hash;
Eric Andersencb57d552001-06-28 07:25:16 +000010987 }
Eric Andersenc470f442003-07-28 09:56:35 +000010988 mail_var_path_changed = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010989 popstackmark(&smark);
10990}
Eric Andersencb57d552001-06-28 07:25:16 +000010991
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010992static void FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010993changemail(const char *val UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000010994{
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010995 mail_var_path_changed = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000010996}
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010997
Denis Vlasenko131ae172007-02-18 13:00:19 +000010998#endif /* ASH_MAIL */
Eric Andersenc470f442003-07-28 09:56:35 +000010999
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000011000
11001/* ============ ??? */
11002
Eric Andersencb57d552001-06-28 07:25:16 +000011003/*
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000011004 * Set the shell parameters.
Eric Andersencb57d552001-06-28 07:25:16 +000011005 */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000011006static void
11007setparam(char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000011008{
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000011009 char **newparam;
11010 char **ap;
11011 int nparam;
Eric Andersencb57d552001-06-28 07:25:16 +000011012
Denis Vlasenkof7d56652008-03-25 05:51:41 +000011013 for (nparam = 0; argv[nparam]; nparam++)
11014 continue;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000011015 ap = newparam = ckmalloc((nparam + 1) * sizeof(*ap));
11016 while (*argv) {
11017 *ap++ = ckstrdup(*argv++);
Eric Andersencb57d552001-06-28 07:25:16 +000011018 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000011019 *ap = NULL;
11020 freeparam(&shellparam);
Denis Vlasenko01631112007-12-16 17:20:38 +000011021 shellparam.malloced = 1;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000011022 shellparam.nparam = nparam;
11023 shellparam.p = newparam;
11024#if ENABLE_ASH_GETOPTS
11025 shellparam.optind = 1;
11026 shellparam.optoff = -1;
11027#endif
Eric Andersencb57d552001-06-28 07:25:16 +000011028}
11029
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000011030/*
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000011031 * Process shell options. The global variable argptr contains a pointer
11032 * to the argument list; we advance it past the options.
Denis Vlasenko94e87bc2008-02-14 16:51:58 +000011033 *
11034 * SUSv3 section 2.8.1 "Consequences of Shell Errors" says:
11035 * For a non-interactive shell, an error condition encountered
11036 * by a special built-in ... shall cause the shell to write a diagnostic message
11037 * to standard error and exit as shown in the following table:
Denis Vlasenko56244732008-02-17 15:14:04 +000011038 * Error Special Built-In
Denis Vlasenko94e87bc2008-02-14 16:51:58 +000011039 * ...
11040 * Utility syntax error (option or operand error) Shall exit
11041 * ...
11042 * However, in bug 1142 (http://busybox.net/bugs/view.php?id=1142)
11043 * we see that bash does not do that (set "finishes" with error code 1 instead,
11044 * and shell continues), and people rely on this behavior!
11045 * Testcase:
11046 * set -o barfoo 2>/dev/null
11047 * echo $?
11048 *
11049 * Oh well. Let's mimic that.
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000011050 */
Denis Vlasenko28bf6712008-02-14 15:01:47 +000011051static int
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000011052plus_minus_o(char *name, int val)
Eric Andersen62483552001-07-10 06:09:16 +000011053{
11054 int i;
11055
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011056 if (name) {
11057 for (i = 0; i < NOPTS; i++) {
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000011058 if (strcmp(name, optnames(i)) == 0) {
Eric Andersenc470f442003-07-28 09:56:35 +000011059 optlist[i] = val;
Denis Vlasenko28bf6712008-02-14 15:01:47 +000011060 return 0;
Eric Andersen62483552001-07-10 06:09:16 +000011061 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011062 }
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000011063 ash_msg("illegal option %co %s", val ? '-' : '+', name);
Denis Vlasenko28bf6712008-02-14 15:01:47 +000011064 return 1;
Eric Andersen62483552001-07-10 06:09:16 +000011065 }
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000011066 for (i = 0; i < NOPTS; i++) {
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000011067 if (val) {
11068 out1fmt("%-16s%s\n", optnames(i), optlist[i] ? "on" : "off");
11069 } else {
11070 out1fmt("set %co %s\n", optlist[i] ? '-' : '+', optnames(i));
11071 }
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000011072 }
Denis Vlasenko28bf6712008-02-14 15:01:47 +000011073 return 0;
Eric Andersen62483552001-07-10 06:09:16 +000011074}
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011075static void
11076setoption(int flag, int val)
11077{
11078 int i;
11079
11080 for (i = 0; i < NOPTS; i++) {
11081 if (optletters(i) == flag) {
11082 optlist[i] = val;
11083 return;
11084 }
11085 }
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000011086 ash_msg_and_raise_error("illegal option %c%c", val ? '-' : '+', flag);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011087 /* NOTREACHED */
11088}
Denis Vlasenko28bf6712008-02-14 15:01:47 +000011089static int
Denys Vlasenkoec05df12017-07-31 19:43:47 +020011090options(int cmdline, int *login_sh)
Eric Andersencb57d552001-06-28 07:25:16 +000011091{
11092 char *p;
11093 int val;
11094 int c;
11095
11096 if (cmdline)
11097 minusc = NULL;
11098 while ((p = *argptr) != NULL) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011099 c = *p++;
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000011100 if (c != '-' && c != '+')
11101 break;
11102 argptr++;
11103 val = 0; /* val = 0 if c == '+' */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011104 if (c == '-') {
Eric Andersencb57d552001-06-28 07:25:16 +000011105 val = 1;
Denis Vlasenko9f739442006-12-16 23:49:13 +000011106 if (p[0] == '\0' || LONE_DASH(p)) {
Eric Andersen2870d962001-07-02 17:27:21 +000011107 if (!cmdline) {
11108 /* "-" means turn off -x and -v */
11109 if (p[0] == '\0')
11110 xflag = vflag = 0;
11111 /* "--" means reset params */
11112 else if (*argptr == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +000011113 setparam(argptr);
Eric Andersen2870d962001-07-02 17:27:21 +000011114 }
Denys Vlasenkob0b83432011-03-07 12:34:59 +010011115 break; /* "-" or "--" terminates options */
Eric Andersencb57d552001-06-28 07:25:16 +000011116 }
Eric Andersencb57d552001-06-28 07:25:16 +000011117 }
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000011118 /* first char was + or - */
Eric Andersencb57d552001-06-28 07:25:16 +000011119 while ((c = *p++) != '\0') {
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000011120 /* bash 3.2 indeed handles -c CMD and +c CMD the same */
Eric Andersencb57d552001-06-28 07:25:16 +000011121 if (c == 'c' && cmdline) {
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000011122 minusc = p; /* command is after shell args */
Eric Andersencb57d552001-06-28 07:25:16 +000011123 } else if (c == 'o') {
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000011124 if (plus_minus_o(*argptr, val)) {
Denis Vlasenko28bf6712008-02-14 15:01:47 +000011125 /* it already printed err message */
11126 return 1; /* error */
11127 }
Eric Andersencb57d552001-06-28 07:25:16 +000011128 if (*argptr)
11129 argptr++;
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000011130 } else if (cmdline && (c == 'l')) { /* -l or +l == --login */
Denys Vlasenkoec05df12017-07-31 19:43:47 +020011131 if (login_sh)
11132 *login_sh = 1;
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000011133 /* bash does not accept +-login, we also won't */
11134 } else if (cmdline && val && (c == '-')) { /* long options */
Denys Vlasenkoec05df12017-07-31 19:43:47 +020011135 if (strcmp(p, "login") == 0) {
11136 if (login_sh)
11137 *login_sh = 1;
11138 }
Robert Griebl64f70cc2002-05-14 23:22:06 +000011139 break;
Eric Andersencb57d552001-06-28 07:25:16 +000011140 } else {
11141 setoption(c, val);
11142 }
11143 }
11144 }
Denis Vlasenko28bf6712008-02-14 15:01:47 +000011145 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +000011146}
11147
Eric Andersencb57d552001-06-28 07:25:16 +000011148/*
Eric Andersencb57d552001-06-28 07:25:16 +000011149 * The shift builtin command.
11150 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020011151static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000011152shiftcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000011153{
11154 int n;
11155 char **ap1, **ap2;
11156
11157 n = 1;
Denis Vlasenko68404f12008-03-17 09:00:54 +000011158 if (argv[1])
Eric Andersencb57d552001-06-28 07:25:16 +000011159 n = number(argv[1]);
11160 if (n > shellparam.nparam)
Ingo van Lil9c8e94b2018-01-05 15:04:23 +010011161 return 1;
Denis Vlasenkob012b102007-02-19 22:43:01 +000011162 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +000011163 shellparam.nparam -= n;
Denis Vlasenko2da584f2007-02-19 22:44:05 +000011164 for (ap1 = shellparam.p; --n >= 0; ap1++) {
Denis Vlasenko01631112007-12-16 17:20:38 +000011165 if (shellparam.malloced)
Denis Vlasenkob012b102007-02-19 22:43:01 +000011166 free(*ap1);
Eric Andersencb57d552001-06-28 07:25:16 +000011167 }
11168 ap2 = shellparam.p;
Denis Vlasenkof7d56652008-03-25 05:51:41 +000011169 while ((*ap2++ = *ap1++) != NULL)
11170 continue;
Denis Vlasenko131ae172007-02-18 13:00:19 +000011171#if ENABLE_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +000011172 shellparam.optind = 1;
11173 shellparam.optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +000011174#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +000011175 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +000011176 return 0;
11177}
11178
Eric Andersencb57d552001-06-28 07:25:16 +000011179/*
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011180 * POSIX requires that 'set' (but not export or readonly) output the
11181 * variables in lexicographic order - by the locale's collating order (sigh).
11182 * Maybe we could keep them in an ordered balanced binary tree
11183 * instead of hashed lists.
11184 * For now just roll 'em through qsort for printing...
11185 */
11186static int
11187showvars(const char *sep_prefix, int on, int off)
11188{
11189 const char *sep;
11190 char **ep, **epend;
11191
Denys Vlasenkoa5060b82017-11-03 14:16:25 +010011192 ep = listvars(on, off, /*strlist:*/ NULL, &epend);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011193 qsort(ep, epend - ep, sizeof(char *), vpcmp);
11194
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000011195 sep = *sep_prefix ? " " : sep_prefix;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011196
11197 for (; ep < epend; ep++) {
11198 const char *p;
11199 const char *q;
11200
Denys Vlasenko9c143ce2017-11-02 12:56:24 +010011201 p = endofname(*ep);
11202/* Used to have simple "p = strchrnul(*ep, '=')" here instead, but this
11203 * makes "export -p" to have output not suitable for "eval":
11204 * import os
11205 * os.environ["test-test"]="test"
11206 * if os.fork() == 0:
11207 * os.execv("ash", [ 'ash', '-c', 'eval $(export -p); echo OK' ]) # fixes this
11208 * os.execv("ash", [ 'ash', '-c', 'env | grep test-test' ])
11209 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011210 q = nullstr;
Denys Vlasenko9c143ce2017-11-02 12:56:24 +010011211 if (*p == '=')
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011212 q = single_quote(++p);
11213 out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
11214 }
11215 return 0;
11216}
11217
11218/*
Eric Andersencb57d552001-06-28 07:25:16 +000011219 * The set command builtin.
11220 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020011221static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000011222setcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +000011223{
Denis Vlasenko28bf6712008-02-14 15:01:47 +000011224 int retval;
11225
Denis Vlasenko68404f12008-03-17 09:00:54 +000011226 if (!argv[1])
Eric Andersenc470f442003-07-28 09:56:35 +000011227 return showvars(nullstr, 0, VUNSET);
Denys Vlasenkob0b83432011-03-07 12:34:59 +010011228
Denis Vlasenkob012b102007-02-19 22:43:01 +000011229 INT_OFF;
Denys Vlasenkoec05df12017-07-31 19:43:47 +020011230 retval = options(/*cmdline:*/ 0, NULL);
Denys Vlasenkob0b83432011-03-07 12:34:59 +010011231 if (retval == 0) { /* if no parse error... */
Denis Vlasenko28bf6712008-02-14 15:01:47 +000011232 optschanged();
11233 if (*argptr != NULL) {
11234 setparam(argptr);
11235 }
Eric Andersencb57d552001-06-28 07:25:16 +000011236 }
Denis Vlasenkob012b102007-02-19 22:43:01 +000011237 INT_ON;
Denis Vlasenko28bf6712008-02-14 15:01:47 +000011238 return retval;
Eric Andersencb57d552001-06-28 07:25:16 +000011239}
11240
Denis Vlasenko131ae172007-02-18 13:00:19 +000011241#if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020011242static void FAST_FUNC
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000011243change_random(const char *value)
Eric Andersenef02f822004-03-11 13:34:24 +000011244{
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020011245 uint32_t t;
11246
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011247 if (value == NULL) {
Eric Andersen16767e22004-03-16 05:14:10 +000011248 /* "get", generate */
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020011249 t = next_random(&random_gen);
Eric Andersen16767e22004-03-16 05:14:10 +000011250 /* set without recursion */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +020011251 setvar(vrandom.var_text, utoa(t), VNOFUNC);
Eric Andersen16767e22004-03-16 05:14:10 +000011252 vrandom.flags &= ~VNOFUNC;
11253 } else {
11254 /* set/reset */
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020011255 t = strtoul(value, NULL, 10);
11256 INIT_RANDOM_T(&random_gen, (t ? t : 1), t);
Eric Andersen16767e22004-03-16 05:14:10 +000011257 }
Eric Andersenef02f822004-03-11 13:34:24 +000011258}
Eric Andersen16767e22004-03-16 05:14:10 +000011259#endif
11260
Ron Yorston1d371862019-04-15 10:52:05 +010011261#if BASH_EPOCH_VARS
11262static void FAST_FUNC
11263change_epoch(struct var *vepoch, const char *fmt)
11264{
11265 struct timeval tv;
11266 char buffer[sizeof("%lu.nnnnnn") + sizeof(long)*3];
11267
11268 gettimeofday(&tv, NULL);
11269 sprintf(buffer, fmt, (unsigned long)tv.tv_sec, (unsigned)tv.tv_usec);
11270 setvar(vepoch->var_text, buffer, VNOFUNC);
11271 vepoch->flags &= ~VNOFUNC;
11272}
11273
11274static void FAST_FUNC
11275change_seconds(const char *value UNUSED_PARAM)
11276{
11277 change_epoch(&vepochs, "%lu");
11278}
11279
11280static void FAST_FUNC
11281change_realtime(const char *value UNUSED_PARAM)
11282{
11283 change_epoch(&vepochr, "%lu.%06u");
11284}
11285#endif
11286
Denis Vlasenko131ae172007-02-18 13:00:19 +000011287#if ENABLE_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +000011288static int
Denys Vlasenko35c2a132016-10-26 17:34:26 +020011289getopts(char *optstr, char *optvar, char **optfirst)
Eric Andersencb57d552001-06-28 07:25:16 +000011290{
11291 char *p, *q;
11292 char c = '?';
11293 int done = 0;
Denys Vlasenko9c541002015-10-07 15:44:36 +020011294 char sbuf[2];
Eric Andersena48b0a32003-10-22 10:56:47 +000011295 char **optnext;
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020011296 int ind = shellparam.optind;
11297 int off = shellparam.optoff;
Eric Andersencb57d552001-06-28 07:25:16 +000011298
Denys Vlasenko9c541002015-10-07 15:44:36 +020011299 sbuf[1] = '\0';
11300
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020011301 shellparam.optind = -1;
11302 optnext = optfirst + ind - 1;
Eric Andersena48b0a32003-10-22 10:56:47 +000011303
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020011304 if (ind <= 1 || off < 0 || (int)strlen(optnext[-1]) < off)
Eric Andersencb57d552001-06-28 07:25:16 +000011305 p = NULL;
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020011306 else
11307 p = optnext[-1] + off;
Eric Andersencb57d552001-06-28 07:25:16 +000011308 if (p == NULL || *p == '\0') {
11309 /* Current word is done, advance */
Eric Andersencb57d552001-06-28 07:25:16 +000011310 p = *optnext;
11311 if (p == NULL || *p != '-' || *++p == '\0') {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011312 atend:
Denys Vlasenko9832bba2017-08-15 15:44:41 +020011313 unsetvar("OPTARG");
Eric Andersencb57d552001-06-28 07:25:16 +000011314 p = NULL;
11315 done = 1;
11316 goto out;
11317 }
11318 optnext++;
Denis Vlasenko9f739442006-12-16 23:49:13 +000011319 if (LONE_DASH(p)) /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +000011320 goto atend;
11321 }
11322
11323 c = *p++;
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +000011324 for (q = optstr; *q != c;) {
Eric Andersencb57d552001-06-28 07:25:16 +000011325 if (*q == '\0') {
Denys Vlasenko9832bba2017-08-15 15:44:41 +020011326 /* OPTERR is a bashism */
11327 const char *cp = lookupvar("OPTERR");
11328 if ((cp && LONE_CHAR(cp, '0'))
11329 || (optstr[0] == ':')
11330 ) {
Denys Vlasenko9c541002015-10-07 15:44:36 +020011331 sbuf[0] = c;
11332 /*sbuf[1] = '\0'; - already is */
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020011333 setvar0("OPTARG", sbuf);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011334 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000011335 fprintf(stderr, "Illegal option -%c\n", c);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011336 unsetvar("OPTARG");
Eric Andersencb57d552001-06-28 07:25:16 +000011337 }
11338 c = '?';
Eric Andersenc470f442003-07-28 09:56:35 +000011339 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +000011340 }
11341 if (*++q == ':')
11342 q++;
11343 }
11344
11345 if (*++q == ':') {
11346 if (*p == '\0' && (p = *optnext) == NULL) {
Denys Vlasenko9832bba2017-08-15 15:44:41 +020011347 /* OPTERR is a bashism */
11348 const char *cp = lookupvar("OPTERR");
11349 if ((cp && LONE_CHAR(cp, '0'))
11350 || (optstr[0] == ':')
11351 ) {
Denys Vlasenko9c541002015-10-07 15:44:36 +020011352 sbuf[0] = c;
11353 /*sbuf[1] = '\0'; - already is */
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020011354 setvar0("OPTARG", sbuf);
Eric Andersencb57d552001-06-28 07:25:16 +000011355 c = ':';
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011356 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000011357 fprintf(stderr, "No arg for -%c option\n", c);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011358 unsetvar("OPTARG");
Eric Andersencb57d552001-06-28 07:25:16 +000011359 c = '?';
11360 }
Eric Andersenc470f442003-07-28 09:56:35 +000011361 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +000011362 }
11363
11364 if (p == *optnext)
11365 optnext++;
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020011366 setvar0("OPTARG", p);
Eric Andersencb57d552001-06-28 07:25:16 +000011367 p = NULL;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011368 } else
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020011369 setvar0("OPTARG", nullstr);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011370 out:
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020011371 ind = optnext - optfirst + 1;
11372 setvar("OPTIND", itoa(ind), VNOFUNC);
Denys Vlasenko9c541002015-10-07 15:44:36 +020011373 sbuf[0] = c;
11374 /*sbuf[1] = '\0'; - already is */
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020011375 setvar0(optvar, sbuf);
11376
11377 shellparam.optoff = p ? p - *(optnext - 1) : -1;
11378 shellparam.optind = ind;
11379
Eric Andersencb57d552001-06-28 07:25:16 +000011380 return done;
11381}
Eric Andersenc470f442003-07-28 09:56:35 +000011382
11383/*
11384 * The getopts builtin. Shellparam.optnext points to the next argument
11385 * to be processed. Shellparam.optptr points to the next character to
11386 * be processed in the current argument. If shellparam.optnext is NULL,
11387 * then it's the first time getopts has been called.
11388 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020011389static int FAST_FUNC
Eric Andersenc470f442003-07-28 09:56:35 +000011390getoptscmd(int argc, char **argv)
11391{
11392 char **optbase;
11393
11394 if (argc < 3)
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +000011395 ash_msg_and_raise_error("usage: getopts optstring var [arg]");
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011396 if (argc == 3) {
Eric Andersenc470f442003-07-28 09:56:35 +000011397 optbase = shellparam.p;
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020011398 if ((unsigned)shellparam.optind > shellparam.nparam + 1) {
Eric Andersenc470f442003-07-28 09:56:35 +000011399 shellparam.optind = 1;
11400 shellparam.optoff = -1;
11401 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011402 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000011403 optbase = &argv[3];
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020011404 if ((unsigned)shellparam.optind > argc - 2) {
Eric Andersenc470f442003-07-28 09:56:35 +000011405 shellparam.optind = 1;
11406 shellparam.optoff = -1;
11407 }
11408 }
11409
Denys Vlasenko35c2a132016-10-26 17:34:26 +020011410 return getopts(argv[1], argv[2], optbase);
Eric Andersenc470f442003-07-28 09:56:35 +000011411}
Denis Vlasenko131ae172007-02-18 13:00:19 +000011412#endif /* ASH_GETOPTS */
Eric Andersencb57d552001-06-28 07:25:16 +000011413
Eric Andersencb57d552001-06-28 07:25:16 +000011414
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011415/* ============ Shell parser */
Eric Andersencb57d552001-06-28 07:25:16 +000011416
Denis Vlasenkob07a4962008-06-22 13:16:23 +000011417struct heredoc {
11418 struct heredoc *next; /* next here document in list */
11419 union node *here; /* redirection node */
11420 char *eofmark; /* string indicating end of input */
11421 smallint striptabs; /* if set, strip leading tabs */
11422};
11423
11424static smallint tokpushback; /* last token pushed back */
Denis Vlasenkob07a4962008-06-22 13:16:23 +000011425static smallint quoteflag; /* set if (part of) last token was quoted */
11426static token_id_t lasttoken; /* last token read (integer id Txxx) */
11427static struct heredoc *heredoclist; /* list of here documents to read */
11428static char *wordtext; /* text of last word returned by readtoken */
11429static struct nodelist *backquotelist;
11430static union node *redirnode;
11431static struct heredoc *heredoc;
Denis Vlasenko99eb8502007-02-23 21:09:49 +000011432
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020011433static const char *
11434tokname(char *buf, int tok)
11435{
11436 if (tok < TSEMI)
Denys Vlasenko888527c2016-10-02 16:54:17 +020011437 return tokname_array[tok];
11438 sprintf(buf, "\"%s\"", tokname_array[tok]);
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020011439 return buf;
11440}
11441
11442/* raise_error_unexpected_syntax:
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011443 * Called when an unexpected token is read during the parse. The argument
11444 * is the token that is expected, or -1 if more than one type of token can
11445 * occur at this point.
11446 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000011447static void raise_error_unexpected_syntax(int) NORETURN;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011448static void
11449raise_error_unexpected_syntax(int token)
11450{
11451 char msg[64];
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020011452 char buf[16];
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011453 int l;
11454
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020011455 l = sprintf(msg, "unexpected %s", tokname(buf, lasttoken));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011456 if (token >= 0)
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020011457 sprintf(msg + l, " (expecting %s)", tokname(buf, token));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011458 raise_error_syntax(msg);
11459 /* NOTREACHED */
11460}
Eric Andersencb57d552001-06-28 07:25:16 +000011461
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011462/* parsing is heavily cross-recursive, need these forward decls */
11463static union node *andor(void);
11464static union node *pipeline(void);
11465static union node *parse_command(void);
11466static void parseheredoc(void);
Ron Yorstonc0e00762015-10-29 11:30:55 +000011467static int peektoken(void);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011468static int readtoken(void);
Eric Andersencb57d552001-06-28 07:25:16 +000011469
Eric Andersenc470f442003-07-28 09:56:35 +000011470static union node *
11471list(int nlflag)
Eric Andersencb57d552001-06-28 07:25:16 +000011472{
11473 union node *n1, *n2, *n3;
11474 int tok;
11475
Eric Andersencb57d552001-06-28 07:25:16 +000011476 n1 = NULL;
11477 for (;;) {
Ron Yorstonc0e00762015-10-29 11:30:55 +000011478 switch (peektoken()) {
11479 case TNL:
11480 if (!(nlflag & 1))
11481 break;
11482 parseheredoc();
11483 return n1;
11484
11485 case TEOF:
11486 if (!n1 && (nlflag & 1))
11487 n1 = NODE_EOF;
11488 parseheredoc();
11489 return n1;
11490 }
11491
11492 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Denys Vlasenko888527c2016-10-02 16:54:17 +020011493 if (nlflag == 2 && ((1 << peektoken()) & tokendlist))
Ron Yorstonc0e00762015-10-29 11:30:55 +000011494 return n1;
11495 nlflag |= 2;
11496
Eric Andersencb57d552001-06-28 07:25:16 +000011497 n2 = andor();
11498 tok = readtoken();
11499 if (tok == TBACKGND) {
Eric Andersenc470f442003-07-28 09:56:35 +000011500 if (n2->type == NPIPE) {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +000011501 n2->npipe.pipe_backgnd = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011502 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000011503 if (n2->type != NREDIR) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011504 n3 = stzalloc(sizeof(struct nredir));
Eric Andersenc470f442003-07-28 09:56:35 +000011505 n3->nredir.n = n2;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011506 /*n3->nredir.redirect = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011507 n2 = n3;
11508 }
11509 n2->type = NBACKGND;
Eric Andersencb57d552001-06-28 07:25:16 +000011510 }
11511 }
11512 if (n1 == NULL) {
11513 n1 = n2;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011514 } else {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011515 n3 = stzalloc(sizeof(struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +000011516 n3->type = NSEMI;
11517 n3->nbinary.ch1 = n1;
11518 n3->nbinary.ch2 = n2;
11519 n1 = n3;
11520 }
11521 switch (tok) {
Ron Yorstonc0e00762015-10-29 11:30:55 +000011522 case TNL:
11523 case TEOF:
11524 tokpushback = 1;
11525 /* fall through */
Eric Andersencb57d552001-06-28 07:25:16 +000011526 case TBACKGND:
11527 case TSEMI:
Eric Andersencb57d552001-06-28 07:25:16 +000011528 break;
Eric Andersencb57d552001-06-28 07:25:16 +000011529 default:
Ron Yorstonc0e00762015-10-29 11:30:55 +000011530 if ((nlflag & 1))
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011531 raise_error_unexpected_syntax(-1);
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011532 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011533 return n1;
11534 }
11535 }
11536}
11537
Eric Andersenc470f442003-07-28 09:56:35 +000011538static union node *
11539andor(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011540{
Eric Andersencb57d552001-06-28 07:25:16 +000011541 union node *n1, *n2, *n3;
11542 int t;
11543
Eric Andersencb57d552001-06-28 07:25:16 +000011544 n1 = pipeline();
11545 for (;;) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011546 t = readtoken();
11547 if (t == TAND) {
Eric Andersencb57d552001-06-28 07:25:16 +000011548 t = NAND;
11549 } else if (t == TOR) {
11550 t = NOR;
11551 } else {
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011552 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011553 return n1;
11554 }
Eric Andersenc470f442003-07-28 09:56:35 +000011555 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000011556 n2 = pipeline();
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011557 n3 = stzalloc(sizeof(struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +000011558 n3->type = t;
11559 n3->nbinary.ch1 = n1;
11560 n3->nbinary.ch2 = n2;
11561 n1 = n3;
11562 }
11563}
11564
Eric Andersenc470f442003-07-28 09:56:35 +000011565static union node *
11566pipeline(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011567{
Eric Andersencb57d552001-06-28 07:25:16 +000011568 union node *n1, *n2, *pipenode;
11569 struct nodelist *lp, *prev;
11570 int negate;
11571
11572 negate = 0;
11573 TRACE(("pipeline: entered\n"));
11574 if (readtoken() == TNOT) {
11575 negate = !negate;
Eric Andersenc470f442003-07-28 09:56:35 +000011576 checkkwd = CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000011577 } else
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011578 tokpushback = 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011579 n1 = parse_command();
Eric Andersencb57d552001-06-28 07:25:16 +000011580 if (readtoken() == TPIPE) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011581 pipenode = stzalloc(sizeof(struct npipe));
Eric Andersencb57d552001-06-28 07:25:16 +000011582 pipenode->type = NPIPE;
Denis Vlasenko2dc240c2008-07-24 06:07:50 +000011583 /*pipenode->npipe.pipe_backgnd = 0; - stzalloc did it */
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011584 lp = stzalloc(sizeof(struct nodelist));
Eric Andersencb57d552001-06-28 07:25:16 +000011585 pipenode->npipe.cmdlist = lp;
11586 lp->n = n1;
11587 do {
11588 prev = lp;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011589 lp = stzalloc(sizeof(struct nodelist));
Eric Andersenc470f442003-07-28 09:56:35 +000011590 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011591 lp->n = parse_command();
Eric Andersencb57d552001-06-28 07:25:16 +000011592 prev->next = lp;
11593 } while (readtoken() == TPIPE);
11594 lp->next = NULL;
11595 n1 = pipenode;
11596 }
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011597 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011598 if (negate) {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011599 n2 = stzalloc(sizeof(struct nnot));
Eric Andersencb57d552001-06-28 07:25:16 +000011600 n2->type = NNOT;
11601 n2->nnot.com = n1;
11602 return n2;
Denis Vlasenko2da584f2007-02-19 22:44:05 +000011603 }
11604 return n1;
Eric Andersencb57d552001-06-28 07:25:16 +000011605}
11606
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011607static union node *
11608makename(void)
11609{
11610 union node *n;
11611
Denis Vlasenko597906c2008-02-20 16:38:54 +000011612 n = stzalloc(sizeof(struct narg));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011613 n->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011614 /*n->narg.next = NULL; - stzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011615 n->narg.text = wordtext;
11616 n->narg.backquote = backquotelist;
11617 return n;
11618}
11619
11620static void
11621fixredir(union node *n, const char *text, int err)
11622{
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000011623 int fd;
11624
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011625 TRACE(("Fix redir %s %d\n", text, err));
11626 if (!err)
11627 n->ndup.vname = NULL;
11628
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000011629 fd = bb_strtou(text, NULL, 10);
11630 if (!errno && fd >= 0)
11631 n->ndup.dupfd = fd;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011632 else if (LONE_DASH(text))
11633 n->ndup.dupfd = -1;
11634 else {
11635 if (err)
Denis Vlasenko559691a2008-10-05 18:39:31 +000011636 raise_error_syntax("bad fd number");
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011637 n->ndup.vname = makename();
11638 }
11639}
11640
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011641static void
11642parsefname(void)
11643{
11644 union node *n = redirnode;
11645
Denys Vlasenkoa7328982017-07-29 19:57:28 +020011646 if (n->type == NHERE)
11647 checkkwd = CHKEOFMARK;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011648 if (readtoken() != TWORD)
11649 raise_error_unexpected_syntax(-1);
11650 if (n->type == NHERE) {
11651 struct heredoc *here = heredoc;
11652 struct heredoc *p;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011653
11654 if (quoteflag == 0)
11655 n->type = NXHERE;
11656 TRACE(("Here document %d\n", n->type));
Denys Vlasenko740058b2018-01-09 17:01:00 +010011657 rmescapes(wordtext, 0, NULL);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011658 here->eofmark = wordtext;
11659 here->next = NULL;
11660 if (heredoclist == NULL)
11661 heredoclist = here;
11662 else {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011663 for (p = heredoclist; p->next; p = p->next)
11664 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011665 p->next = here;
11666 }
11667 } else if (n->type == NTOFD || n->type == NFROMFD) {
11668 fixredir(n, wordtext, 0);
11669 } else {
11670 n->nfile.fname = makename();
11671 }
11672}
Eric Andersencb57d552001-06-28 07:25:16 +000011673
Eric Andersenc470f442003-07-28 09:56:35 +000011674static union node *
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011675simplecmd(void)
11676{
11677 union node *args, **app;
11678 union node *n = NULL;
11679 union node *vars, **vpp;
11680 union node **rpp, *redir;
11681 int savecheckkwd;
Denys Vlasenko675d24a2018-01-27 22:02:05 +010011682 int savelinno;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011683#if BASH_TEST2
Denis Vlasenko80591b02008-03-25 07:49:43 +000011684 smallint double_brackets_flag = 0;
11685#endif
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011686 IF_BASH_FUNCTION(smallint function_flag = 0;)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011687
11688 args = NULL;
11689 app = &args;
11690 vars = NULL;
11691 vpp = &vars;
11692 redir = NULL;
11693 rpp = &redir;
11694
11695 savecheckkwd = CHKALIAS;
Denys Vlasenko675d24a2018-01-27 22:02:05 +010011696 savelinno = g_parsefile->linno;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011697 for (;;) {
Denis Vlasenko80591b02008-03-25 07:49:43 +000011698 int t;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011699 checkkwd = savecheckkwd;
Denis Vlasenko80591b02008-03-25 07:49:43 +000011700 t = readtoken();
11701 switch (t) {
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011702#if BASH_FUNCTION
Ron Yorston95ebcf72015-11-03 09:42:23 +000011703 case TFUNCTION:
11704 if (peektoken() != TWORD)
11705 raise_error_unexpected_syntax(TWORD);
11706 function_flag = 1;
11707 break;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011708#endif
11709#if BASH_TEST2
Denis Vlasenko80591b02008-03-25 07:49:43 +000011710 case TAND: /* "&&" */
11711 case TOR: /* "||" */
11712 if (!double_brackets_flag) {
11713 tokpushback = 1;
11714 goto out;
11715 }
11716 wordtext = (char *) (t == TAND ? "-a" : "-o");
11717#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011718 case TWORD:
Denis Vlasenko597906c2008-02-20 16:38:54 +000011719 n = stzalloc(sizeof(struct narg));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011720 n->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011721 /*n->narg.next = NULL; - stzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011722 n->narg.text = wordtext;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011723#if BASH_TEST2
Denis Vlasenko80591b02008-03-25 07:49:43 +000011724 if (strcmp("[[", wordtext) == 0)
11725 double_brackets_flag = 1;
11726 else if (strcmp("]]", wordtext) == 0)
11727 double_brackets_flag = 0;
11728#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011729 n->narg.backquote = backquotelist;
11730 if (savecheckkwd && isassignment(wordtext)) {
11731 *vpp = n;
11732 vpp = &n->narg.next;
11733 } else {
11734 *app = n;
11735 app = &n->narg.next;
11736 savecheckkwd = 0;
11737 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011738#if BASH_FUNCTION
Ron Yorston95ebcf72015-11-03 09:42:23 +000011739 if (function_flag) {
11740 checkkwd = CHKNL | CHKKWD;
11741 switch (peektoken()) {
11742 case TBEGIN:
11743 case TIF:
11744 case TCASE:
11745 case TUNTIL:
11746 case TWHILE:
11747 case TFOR:
11748 goto do_func;
11749 case TLP:
11750 function_flag = 0;
11751 break;
Denys Vlasenkoe93031e2018-04-10 01:23:19 +020011752# if BASH_TEST2
Ron Yorston95ebcf72015-11-03 09:42:23 +000011753 case TWORD:
11754 if (strcmp("[[", wordtext) == 0)
11755 goto do_func;
11756 /* fall through */
Denys Vlasenkoe93031e2018-04-10 01:23:19 +020011757# endif
Ron Yorston95ebcf72015-11-03 09:42:23 +000011758 default:
11759 raise_error_unexpected_syntax(-1);
11760 }
11761 }
11762#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011763 break;
11764 case TREDIR:
11765 *rpp = n = redirnode;
11766 rpp = &n->nfile.next;
11767 parsefname(); /* read name of redirection file */
11768 break;
11769 case TLP:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011770 IF_BASH_FUNCTION(do_func:)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011771 if (args && app == &args->narg.next
11772 && !vars && !redir
11773 ) {
11774 struct builtincmd *bcmd;
11775 const char *name;
11776
11777 /* We have a function */
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011778 if (IF_BASH_FUNCTION(!function_flag &&) readtoken() != TRP)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011779 raise_error_unexpected_syntax(TRP);
11780 name = n->narg.text;
11781 if (!goodname(name)
11782 || ((bcmd = find_builtin(name)) && IS_BUILTIN_SPECIAL(bcmd))
11783 ) {
Denis Vlasenko559691a2008-10-05 18:39:31 +000011784 raise_error_syntax("bad function name");
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011785 }
11786 n->type = NDEFUN;
11787 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Denys Vlasenko675d24a2018-01-27 22:02:05 +010011788 n->ndefun.text = n->narg.text;
11789 n->ndefun.linno = g_parsefile->linno;
11790 n->ndefun.body = parse_command();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011791 return n;
11792 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011793 IF_BASH_FUNCTION(function_flag = 0;)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011794 /* fall through */
11795 default:
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011796 tokpushback = 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011797 goto out;
11798 }
11799 }
11800 out:
11801 *app = NULL;
11802 *vpp = NULL;
11803 *rpp = NULL;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011804 n = stzalloc(sizeof(struct ncmd));
Denys Vlasenko57b7efb2018-04-10 01:20:26 +020011805 if (NCMD != 0)
11806 n->type = NCMD;
Denys Vlasenko675d24a2018-01-27 22:02:05 +010011807 n->ncmd.linno = savelinno;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011808 n->ncmd.args = args;
11809 n->ncmd.assign = vars;
11810 n->ncmd.redirect = redir;
11811 return n;
11812}
11813
11814static union node *
11815parse_command(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011816{
Eric Andersencb57d552001-06-28 07:25:16 +000011817 union node *n1, *n2;
11818 union node *ap, **app;
11819 union node *cp, **cpp;
11820 union node *redir, **rpp;
Eric Andersenc470f442003-07-28 09:56:35 +000011821 union node **rpp2;
Eric Andersencb57d552001-06-28 07:25:16 +000011822 int t;
Denys Vlasenko675d24a2018-01-27 22:02:05 +010011823 int savelinno;
Eric Andersencb57d552001-06-28 07:25:16 +000011824
11825 redir = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +000011826 rpp2 = &redir;
Eric Andersen88cec252001-09-06 17:35:20 +000011827
Denys Vlasenko675d24a2018-01-27 22:02:05 +010011828 savelinno = g_parsefile->linno;
11829
Eric Andersencb57d552001-06-28 07:25:16 +000011830 switch (readtoken()) {
Eric Andersenc470f442003-07-28 09:56:35 +000011831 default:
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011832 raise_error_unexpected_syntax(-1);
Eric Andersenc470f442003-07-28 09:56:35 +000011833 /* NOTREACHED */
Eric Andersencb57d552001-06-28 07:25:16 +000011834 case TIF:
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011835 n1 = stzalloc(sizeof(struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +000011836 n1->type = NIF;
11837 n1->nif.test = list(0);
11838 if (readtoken() != TTHEN)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011839 raise_error_unexpected_syntax(TTHEN);
Eric Andersencb57d552001-06-28 07:25:16 +000011840 n1->nif.ifpart = list(0);
11841 n2 = n1;
11842 while (readtoken() == TELIF) {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011843 n2->nif.elsepart = stzalloc(sizeof(struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +000011844 n2 = n2->nif.elsepart;
11845 n2->type = NIF;
11846 n2->nif.test = list(0);
11847 if (readtoken() != TTHEN)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011848 raise_error_unexpected_syntax(TTHEN);
Eric Andersencb57d552001-06-28 07:25:16 +000011849 n2->nif.ifpart = list(0);
11850 }
11851 if (lasttoken == TELSE)
11852 n2->nif.elsepart = list(0);
11853 else {
11854 n2->nif.elsepart = NULL;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011855 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011856 }
Eric Andersenc470f442003-07-28 09:56:35 +000011857 t = TFI;
Eric Andersencb57d552001-06-28 07:25:16 +000011858 break;
11859 case TWHILE:
Eric Andersenc470f442003-07-28 09:56:35 +000011860 case TUNTIL: {
Eric Andersencb57d552001-06-28 07:25:16 +000011861 int got;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011862 n1 = stzalloc(sizeof(struct nbinary));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011863 n1->type = (lasttoken == TWHILE) ? NWHILE : NUNTIL;
Eric Andersencb57d552001-06-28 07:25:16 +000011864 n1->nbinary.ch1 = list(0);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011865 got = readtoken();
11866 if (got != TDO) {
Denys Vlasenko888527c2016-10-02 16:54:17 +020011867 TRACE(("expecting DO got '%s' %s\n", tokname_array[got],
Denis Vlasenko131ae172007-02-18 13:00:19 +000011868 got == TWORD ? wordtext : ""));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011869 raise_error_unexpected_syntax(TDO);
Eric Andersencb57d552001-06-28 07:25:16 +000011870 }
11871 n1->nbinary.ch2 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +000011872 t = TDONE;
Eric Andersencb57d552001-06-28 07:25:16 +000011873 break;
11874 }
11875 case TFOR:
Denis Vlasenko2dc240c2008-07-24 06:07:50 +000011876 if (readtoken() != TWORD || quoteflag || !goodname(wordtext))
Denis Vlasenko559691a2008-10-05 18:39:31 +000011877 raise_error_syntax("bad for loop variable");
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011878 n1 = stzalloc(sizeof(struct nfor));
Eric Andersencb57d552001-06-28 07:25:16 +000011879 n1->type = NFOR;
Denys Vlasenko675d24a2018-01-27 22:02:05 +010011880 n1->nfor.linno = savelinno;
Eric Andersencb57d552001-06-28 07:25:16 +000011881 n1->nfor.var = wordtext;
Ron Yorstonab80e012015-08-03 13:46:00 +010011882 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000011883 if (readtoken() == TIN) {
11884 app = &ap;
11885 while (readtoken() == TWORD) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011886 n2 = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000011887 n2->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011888 /*n2->narg.next = NULL; - stzalloc did it */
Eric Andersencb57d552001-06-28 07:25:16 +000011889 n2->narg.text = wordtext;
11890 n2->narg.backquote = backquotelist;
11891 *app = n2;
11892 app = &n2->narg.next;
11893 }
11894 *app = NULL;
11895 n1->nfor.args = ap;
11896 if (lasttoken != TNL && lasttoken != TSEMI)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011897 raise_error_unexpected_syntax(-1);
Eric Andersencb57d552001-06-28 07:25:16 +000011898 } else {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011899 n2 = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000011900 n2->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011901 /*n2->narg.next = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011902 n2->narg.text = (char *)dolatstr;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011903 /*n2->narg.backquote = NULL;*/
Eric Andersencb57d552001-06-28 07:25:16 +000011904 n1->nfor.args = n2;
11905 /*
11906 * Newline or semicolon here is optional (but note
11907 * that the original Bourne shell only allowed NL).
11908 */
Ron Yorstonab80e012015-08-03 13:46:00 +010011909 if (lasttoken != TSEMI)
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011910 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011911 }
Eric Andersenc470f442003-07-28 09:56:35 +000011912 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000011913 if (readtoken() != TDO)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011914 raise_error_unexpected_syntax(TDO);
Eric Andersencb57d552001-06-28 07:25:16 +000011915 n1->nfor.body = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +000011916 t = TDONE;
Eric Andersencb57d552001-06-28 07:25:16 +000011917 break;
11918 case TCASE:
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011919 n1 = stzalloc(sizeof(struct ncase));
Eric Andersencb57d552001-06-28 07:25:16 +000011920 n1->type = NCASE;
Denys Vlasenko675d24a2018-01-27 22:02:05 +010011921 n1->ncase.linno = savelinno;
Eric Andersencb57d552001-06-28 07:25:16 +000011922 if (readtoken() != TWORD)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011923 raise_error_unexpected_syntax(TWORD);
Denis Vlasenko597906c2008-02-20 16:38:54 +000011924 n1->ncase.expr = n2 = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000011925 n2->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011926 /*n2->narg.next = NULL; - stzalloc did it */
Eric Andersencb57d552001-06-28 07:25:16 +000011927 n2->narg.text = wordtext;
11928 n2->narg.backquote = backquotelist;
Ron Yorston383b8852015-08-03 13:46:25 +010011929 checkkwd = CHKNL | CHKKWD | CHKALIAS;
11930 if (readtoken() != TIN)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011931 raise_error_unexpected_syntax(TIN);
Eric Andersencb57d552001-06-28 07:25:16 +000011932 cpp = &n1->ncase.cases;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011933 next_case:
Eric Andersenc470f442003-07-28 09:56:35 +000011934 checkkwd = CHKNL | CHKKWD;
11935 t = readtoken();
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011936 while (t != TESAC) {
Eric Andersencb57d552001-06-28 07:25:16 +000011937 if (lasttoken == TLP)
11938 readtoken();
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011939 *cpp = cp = stzalloc(sizeof(struct nclist));
Eric Andersencb57d552001-06-28 07:25:16 +000011940 cp->type = NCLIST;
11941 app = &cp->nclist.pattern;
11942 for (;;) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011943 *app = ap = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000011944 ap->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011945 /*ap->narg.next = NULL; - stzalloc did it */
Eric Andersencb57d552001-06-28 07:25:16 +000011946 ap->narg.text = wordtext;
11947 ap->narg.backquote = backquotelist;
Eric Andersenc470f442003-07-28 09:56:35 +000011948 if (readtoken() != TPIPE)
Eric Andersencb57d552001-06-28 07:25:16 +000011949 break;
11950 app = &ap->narg.next;
11951 readtoken();
11952 }
Denis Vlasenko597906c2008-02-20 16:38:54 +000011953 //ap->narg.next = NULL;
Eric Andersencb57d552001-06-28 07:25:16 +000011954 if (lasttoken != TRP)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011955 raise_error_unexpected_syntax(TRP);
Eric Andersenc470f442003-07-28 09:56:35 +000011956 cp->nclist.body = list(2);
Eric Andersencb57d552001-06-28 07:25:16 +000011957
Eric Andersenc470f442003-07-28 09:56:35 +000011958 cpp = &cp->nclist.next;
11959
11960 checkkwd = CHKNL | CHKKWD;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011961 t = readtoken();
11962 if (t != TESAC) {
Eric Andersencb57d552001-06-28 07:25:16 +000011963 if (t != TENDCASE)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011964 raise_error_unexpected_syntax(TENDCASE);
11965 goto next_case;
Eric Andersencb57d552001-06-28 07:25:16 +000011966 }
Eric Andersenc470f442003-07-28 09:56:35 +000011967 }
Eric Andersencb57d552001-06-28 07:25:16 +000011968 *cpp = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +000011969 goto redir;
Eric Andersencb57d552001-06-28 07:25:16 +000011970 case TLP:
Denis Vlasenko597906c2008-02-20 16:38:54 +000011971 n1 = stzalloc(sizeof(struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +000011972 n1->type = NSUBSHELL;
Denys Vlasenko675d24a2018-01-27 22:02:05 +010011973 n1->nredir.linno = savelinno;
Eric Andersencb57d552001-06-28 07:25:16 +000011974 n1->nredir.n = list(0);
Denis Vlasenko597906c2008-02-20 16:38:54 +000011975 /*n1->nredir.redirect = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011976 t = TRP;
Eric Andersencb57d552001-06-28 07:25:16 +000011977 break;
11978 case TBEGIN:
11979 n1 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +000011980 t = TEND;
Eric Andersencb57d552001-06-28 07:25:16 +000011981 break;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011982 IF_BASH_FUNCTION(case TFUNCTION:)
Eric Andersencb57d552001-06-28 07:25:16 +000011983 case TWORD:
Eric Andersenc470f442003-07-28 09:56:35 +000011984 case TREDIR:
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011985 tokpushback = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000011986 return simplecmd();
Eric Andersencb57d552001-06-28 07:25:16 +000011987 }
11988
Eric Andersenc470f442003-07-28 09:56:35 +000011989 if (readtoken() != t)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011990 raise_error_unexpected_syntax(t);
Eric Andersenc470f442003-07-28 09:56:35 +000011991
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011992 redir:
Eric Andersencb57d552001-06-28 07:25:16 +000011993 /* Now check for redirection which may follow command */
Eric Andersenc470f442003-07-28 09:56:35 +000011994 checkkwd = CHKKWD | CHKALIAS;
11995 rpp = rpp2;
Eric Andersencb57d552001-06-28 07:25:16 +000011996 while (readtoken() == TREDIR) {
11997 *rpp = n2 = redirnode;
11998 rpp = &n2->nfile.next;
11999 parsefname();
12000 }
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000012001 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000012002 *rpp = NULL;
12003 if (redir) {
12004 if (n1->type != NSUBSHELL) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000012005 n2 = stzalloc(sizeof(struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +000012006 n2->type = NREDIR;
Denys Vlasenko675d24a2018-01-27 22:02:05 +010012007 n2->nredir.linno = savelinno;
Eric Andersencb57d552001-06-28 07:25:16 +000012008 n2->nredir.n = n1;
12009 n1 = n2;
12010 }
12011 n1->nredir.redirect = redir;
12012 }
Eric Andersencb57d552001-06-28 07:25:16 +000012013 return n1;
12014}
12015
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010012016#if BASH_DOLLAR_SQUOTE
Denys Vlasenko37dc08b2016-10-02 04:38:07 +020012017static int
12018decode_dollar_squote(void)
Denis Vlasenkoef527f52008-06-23 01:52:30 +000012019{
12020 static const char C_escapes[] ALIGN1 = "nrbtfav""x\\01234567";
12021 int c, cnt;
12022 char *p;
12023 char buf[4];
12024
12025 c = pgetc();
12026 p = strchr(C_escapes, c);
12027 if (p) {
12028 buf[0] = c;
12029 p = buf;
12030 cnt = 3;
12031 if ((unsigned char)(c - '0') <= 7) { /* \ooo */
12032 do {
12033 c = pgetc();
12034 *++p = c;
12035 } while ((unsigned char)(c - '0') <= 7 && --cnt);
12036 pungetc();
12037 } else if (c == 'x') { /* \xHH */
12038 do {
12039 c = pgetc();
12040 *++p = c;
12041 } while (isxdigit(c) && --cnt);
12042 pungetc();
12043 if (cnt == 3) { /* \x but next char is "bad" */
12044 c = 'x';
12045 goto unrecognized;
12046 }
12047 } else { /* simple seq like \\ or \t */
12048 p++;
12049 }
12050 *p = '\0';
12051 p = buf;
12052 c = bb_process_escape_sequence((void*)&p);
12053 } else { /* unrecognized "\z": print both chars unless ' or " */
12054 if (c != '\'' && c != '"') {
12055 unrecognized:
12056 c |= 0x100; /* "please encode \, then me" */
12057 }
12058 }
12059 return c;
12060}
12061#endif
12062
Denys Vlasenko46999802017-07-29 21:12:29 +020012063/* Used by expandstr to get here-doc like behaviour. */
12064#define FAKEEOFMARK ((char*)(uintptr_t)1)
12065
12066static ALWAYS_INLINE int
12067realeofmark(const char *eofmark)
12068{
12069 return eofmark && eofmark != FAKEEOFMARK;
12070}
12071
Eric Andersencb57d552001-06-28 07:25:16 +000012072/*
12073 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
12074 * is not NULL, read a here document. In the latter case, eofmark is the
12075 * word which marks the end of the document and striptabs is true if
Denys Vlasenkocd716832009-11-28 22:14:02 +010012076 * leading tabs should be stripped from the document. The argument c
Eric Andersencb57d552001-06-28 07:25:16 +000012077 * is the first character of the input token or document.
12078 *
12079 * Because C does not have internal subroutines, I have simulated them
12080 * using goto's to implement the subroutine linkage. The following macros
12081 * will run code that appears at the end of readtoken1.
12082 */
Eric Andersen2870d962001-07-02 17:27:21 +000012083#define CHECKEND() {goto checkend; checkend_return:;}
12084#define PARSEREDIR() {goto parseredir; parseredir_return:;}
12085#define PARSESUB() {goto parsesub; parsesub_return:;}
12086#define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
12087#define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
12088#define PARSEARITH() {goto parsearith; parsearith_return:;}
Eric Andersencb57d552001-06-28 07:25:16 +000012089static int
Denys Vlasenkocd716832009-11-28 22:14:02 +010012090readtoken1(int c, int syntax, char *eofmark, int striptabs)
Manuel Novoa III 16815d42001-08-10 19:36:07 +000012091{
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000012092 /* NB: syntax parameter fits into smallint */
Denys Vlasenkocd716832009-11-28 22:14:02 +010012093 /* c parameter is an unsigned char or PEOF or PEOA */
Eric Andersencb57d552001-06-28 07:25:16 +000012094 char *out;
Denys Vlasenko50e6d422016-09-30 11:35:54 +020012095 size_t len;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000012096 struct nodelist *bqlist;
12097 smallint quotef;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000012098 smallint oldstyle;
Denis Vlasenko46a53062007-09-24 18:30:02 +000012099 smallint pssyntax; /* we are expanding a prompt string */
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010012100 IF_BASH_DOLLAR_SQUOTE(smallint bash_dollar_squote = 0;)
Denys Vlasenko216913c2018-04-02 12:35:04 +020012101 /* syntax stack */
Denys Vlasenkoee1fd122018-04-04 13:59:53 +020012102 struct synstack synbase = { };
Denys Vlasenko216913c2018-04-02 12:35:04 +020012103 struct synstack *synstack = &synbase;
Denis Vlasenkoef527f52008-06-23 01:52:30 +000012104
Denys Vlasenko5f0a75f2017-07-29 22:58:44 +020012105#if ENABLE_ASH_EXPAND_PRMT
Denis Vlasenko46a53062007-09-24 18:30:02 +000012106 pssyntax = (syntax == PSSYNTAX);
12107 if (pssyntax)
12108 syntax = DQSYNTAX;
Denys Vlasenko5f0a75f2017-07-29 22:58:44 +020012109#else
12110 pssyntax = 0; /* constant */
12111#endif
Denys Vlasenkoee1fd122018-04-04 13:59:53 +020012112 synstack->syntax = syntax;
12113
Denys Vlasenko216913c2018-04-02 12:35:04 +020012114 if (syntax == DQSYNTAX)
12115 synstack->dblquote = 1;
12116 quotef = 0;
12117 bqlist = NULL;
Eric Andersencb57d552001-06-28 07:25:16 +000012118
12119 STARTSTACKSTR(out);
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012120 loop:
12121 /* For each line, until end of word */
Denys Vlasenko958581a2010-09-12 15:04:27 +020012122 CHECKEND(); /* set c to PEOF if at end of here document */
12123 for (;;) { /* until end of line or end of word */
12124 CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */
Denys Vlasenko216913c2018-04-02 12:35:04 +020012125 switch (SIT(c, synstack->syntax)) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020012126 case CNL: /* '\n' */
Denys Vlasenko680c3012018-04-11 12:39:18 +020012127 if (synstack->syntax == BASESYNTAX
12128 && !synstack->varnest
12129 ) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020012130 goto endword; /* exit outer loop */
Denys Vlasenko680c3012018-04-11 12:39:18 +020012131 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020012132 USTPUTC(c, out);
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012133 nlprompt();
Denys Vlasenko958581a2010-09-12 15:04:27 +020012134 c = pgetc();
12135 goto loop; /* continue outer loop */
12136 case CWORD:
12137 USTPUTC(c, out);
12138 break;
12139 case CCTL:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010012140#if BASH_DOLLAR_SQUOTE
Denys Vlasenko958581a2010-09-12 15:04:27 +020012141 if (c == '\\' && bash_dollar_squote) {
12142 c = decode_dollar_squote();
Denys Vlasenko13f20912016-09-25 20:54:25 +020012143 if (c == '\0') {
12144 /* skip $'\000', $'\x00' (like bash) */
12145 break;
12146 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020012147 if (c & 0x100) {
Denys Vlasenko13f20912016-09-25 20:54:25 +020012148 /* Unknown escape. Encode as '\z' */
Denys Vlasenko958581a2010-09-12 15:04:27 +020012149 c = (unsigned char)c;
Denys Vlasenko216913c2018-04-02 12:35:04 +020012150 if (eofmark == NULL || synstack->dblquote)
Denys Vlasenko13f20912016-09-25 20:54:25 +020012151 USTPUTC(CTLESC, out);
12152 USTPUTC('\\', out);
Denis Vlasenkoef527f52008-06-23 01:52:30 +000012153 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020012154 }
Denis Vlasenkoef527f52008-06-23 01:52:30 +000012155#endif
Denys Vlasenkoc4c20122018-04-02 13:29:20 +020012156 if (!eofmark || synstack->dblquote || synstack->varnest)
Denys Vlasenko13f20912016-09-25 20:54:25 +020012157 USTPUTC(CTLESC, out);
Denys Vlasenko958581a2010-09-12 15:04:27 +020012158 USTPUTC(c, out);
12159 break;
12160 case CBACK: /* backslash */
12161 c = pgetc_without_PEOA();
12162 if (c == PEOF) {
12163 USTPUTC(CTLESC, out);
12164 USTPUTC('\\', out);
12165 pungetc();
12166 } else if (c == '\n') {
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012167 nlprompt();
Denys Vlasenko958581a2010-09-12 15:04:27 +020012168 } else {
Denys Vlasenko5f0a75f2017-07-29 22:58:44 +020012169 if (pssyntax && c == '$') {
Eric Andersenc470f442003-07-28 09:56:35 +000012170 USTPUTC(CTLESC, out);
Eric Andersencb57d552001-06-28 07:25:16 +000012171 USTPUTC('\\', out);
Denys Vlasenko958581a2010-09-12 15:04:27 +020012172 }
Denys Vlasenko8de5b9f2018-02-13 14:43:29 +010012173 /* Backslash is retained if we are in "str"
12174 * and next char isn't dquote-special.
12175 */
Denys Vlasenko216913c2018-04-02 12:35:04 +020012176 if (synstack->dblquote
Denys Vlasenko958581a2010-09-12 15:04:27 +020012177 && c != '\\'
12178 && c != '`'
12179 && c != '$'
Denys Vlasenko216913c2018-04-02 12:35:04 +020012180 && (c != '"' || (eofmark != NULL && !synstack->varnest))
12181 && (c != '}' || !synstack->varnest)
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000012182 ) {
Denys Vlasenko8de5b9f2018-02-13 14:43:29 +010012183 USTPUTC(CTLESC, out); /* protect '\' from glob */
Denys Vlasenko958581a2010-09-12 15:04:27 +020012184 USTPUTC('\\', out);
Eric Andersencb57d552001-06-28 07:25:16 +000012185 }
Ron Yorston549deab2015-05-18 09:57:51 +020012186 USTPUTC(CTLESC, out);
Denys Vlasenko0ff78a02010-08-30 15:20:07 +020012187 USTPUTC(c, out);
Denys Vlasenko958581a2010-09-12 15:04:27 +020012188 quotef = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000012189 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020012190 break;
12191 case CSQUOTE:
Denys Vlasenko216913c2018-04-02 12:35:04 +020012192 synstack->syntax = SQSYNTAX;
Denys Vlasenko958581a2010-09-12 15:04:27 +020012193 quotemark:
12194 if (eofmark == NULL) {
12195 USTPUTC(CTLQUOTEMARK, out);
12196 }
12197 break;
12198 case CDQUOTE:
Denys Vlasenko216913c2018-04-02 12:35:04 +020012199 synstack->syntax = DQSYNTAX;
12200 synstack->dblquote = 1;
12201 toggledq:
12202 if (synstack->varnest)
12203 synstack->innerdq ^= 1;
Denys Vlasenko958581a2010-09-12 15:04:27 +020012204 goto quotemark;
12205 case CENDQUOTE:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010012206 IF_BASH_DOLLAR_SQUOTE(bash_dollar_squote = 0;)
Denys Vlasenko216913c2018-04-02 12:35:04 +020012207 if (eofmark != NULL && synstack->varnest == 0) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020012208 USTPUTC(c, out);
Denys Vlasenko216913c2018-04-02 12:35:04 +020012209 break;
Denys Vlasenko958581a2010-09-12 15:04:27 +020012210 }
Denys Vlasenko216913c2018-04-02 12:35:04 +020012211
12212 if (synstack->dqvarnest == 0) {
12213 synstack->syntax = BASESYNTAX;
12214 synstack->dblquote = 0;
12215 }
12216
12217 quotef = 1;
12218
12219 if (c == '"')
12220 goto toggledq;
12221
12222 goto quotemark;
Denys Vlasenko958581a2010-09-12 15:04:27 +020012223 case CVAR: /* '$' */
12224 PARSESUB(); /* parse substitution */
12225 break;
12226 case CENDVAR: /* '}' */
Denys Vlasenko216913c2018-04-02 12:35:04 +020012227 if (!synstack->innerdq && synstack->varnest > 0) {
12228 if (!--synstack->varnest && synstack->varpushed)
12229 synstack_pop(&synstack);
12230 else if (synstack->dqvarnest > 0)
12231 synstack->dqvarnest--;
Denys Vlasenko958581a2010-09-12 15:04:27 +020012232 c = CTLENDVAR;
12233 }
12234 USTPUTC(c, out);
12235 break;
Denys Vlasenko0b883582016-12-23 16:49:07 +010012236#if ENABLE_FEATURE_SH_MATH
Denys Vlasenko958581a2010-09-12 15:04:27 +020012237 case CLP: /* '(' in arithmetic */
Denys Vlasenko216913c2018-04-02 12:35:04 +020012238 synstack->parenlevel++;
Denys Vlasenko958581a2010-09-12 15:04:27 +020012239 USTPUTC(c, out);
12240 break;
12241 case CRP: /* ')' in arithmetic */
Denys Vlasenko216913c2018-04-02 12:35:04 +020012242 if (synstack->parenlevel > 0) {
12243 synstack->parenlevel--;
Denys Vlasenko958581a2010-09-12 15:04:27 +020012244 } else {
Denys Vlasenko459293b2016-09-29 17:58:58 +020012245 if (pgetc_eatbnl() == ')') {
Ron Yorstonad88bde2015-05-18 09:56:16 +020012246 c = CTLENDARI;
Denys Vlasenko216913c2018-04-02 12:35:04 +020012247 synstack_pop(&synstack);
Denys Vlasenko958581a2010-09-12 15:04:27 +020012248 } else {
12249 /*
12250 * unbalanced parens
12251 * (don't 2nd guess - no error)
12252 */
12253 pungetc();
12254 }
12255 }
12256 USTPUTC(c, out);
12257 break;
12258#endif
12259 case CBQUOTE: /* '`' */
Denys Vlasenko41fddb42018-04-01 16:38:32 +020012260 if (checkkwd & CHKEOFMARK) {
12261 quotef = 1;
12262 USTPUTC('`', out);
12263 break;
12264 }
12265
Denys Vlasenko958581a2010-09-12 15:04:27 +020012266 PARSEBACKQOLD();
12267 break;
12268 case CENDFILE:
12269 goto endword; /* exit outer loop */
12270 case CIGN:
12271 break;
12272 default:
Denys Vlasenko216913c2018-04-02 12:35:04 +020012273 if (synstack->varnest == 0) {
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010012274#if BASH_REDIR_OUTPUT
Denys Vlasenko958581a2010-09-12 15:04:27 +020012275 if (c == '&') {
Denys Vlasenko459293b2016-09-29 17:58:58 +020012276//Can't call pgetc_eatbnl() here, this requires three-deep pungetc()
Denys Vlasenko958581a2010-09-12 15:04:27 +020012277 if (pgetc() == '>')
12278 c = 0x100 + '>'; /* flag &> */
12279 pungetc();
12280 }
12281#endif
12282 goto endword; /* exit outer loop */
12283 }
12284 IF_ASH_ALIAS(if (c != PEOA))
12285 USTPUTC(c, out);
12286 }
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020012287 c = pgetc();
Denys Vlasenko958581a2010-09-12 15:04:27 +020012288 } /* for (;;) */
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000012289 endword:
Denys Vlasenko958581a2010-09-12 15:04:27 +020012290
Denys Vlasenko0b883582016-12-23 16:49:07 +010012291#if ENABLE_FEATURE_SH_MATH
Denys Vlasenko216913c2018-04-02 12:35:04 +020012292 if (synstack->syntax == ARISYNTAX)
Denis Vlasenko559691a2008-10-05 18:39:31 +000012293 raise_error_syntax("missing '))'");
Eric Andersenc470f442003-07-28 09:56:35 +000012294#endif
Denys Vlasenko216913c2018-04-02 12:35:04 +020012295 if (synstack->syntax != BASESYNTAX && eofmark == NULL)
Denis Vlasenko559691a2008-10-05 18:39:31 +000012296 raise_error_syntax("unterminated quoted string");
Denys Vlasenko216913c2018-04-02 12:35:04 +020012297 if (synstack->varnest != 0) {
Eric Andersenc470f442003-07-28 09:56:35 +000012298 /* { */
Denis Vlasenko559691a2008-10-05 18:39:31 +000012299 raise_error_syntax("missing '}'");
Eric Andersencb57d552001-06-28 07:25:16 +000012300 }
12301 USTPUTC('\0', out);
Eric Andersenc470f442003-07-28 09:56:35 +000012302 len = out - (char *)stackblock();
Eric Andersencb57d552001-06-28 07:25:16 +000012303 out = stackblock();
12304 if (eofmark == NULL) {
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010012305 if ((c == '>' || c == '<' IF_BASH_REDIR_OUTPUT( || c == 0x100 + '>'))
Denis Vlasenko834dee72008-10-07 09:18:30 +000012306 && quotef == 0
12307 ) {
Denis Vlasenko559691a2008-10-05 18:39:31 +000012308 if (isdigit_str9(out)) {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000012309 PARSEREDIR(); /* passed as params: out, c */
12310 lasttoken = TREDIR;
12311 return lasttoken;
12312 }
12313 /* else: non-number X seen, interpret it
12314 * as "NNNX>file" = "NNNX >file" */
Eric Andersencb57d552001-06-28 07:25:16 +000012315 }
Denis Vlasenkoef527f52008-06-23 01:52:30 +000012316 pungetc();
Eric Andersencb57d552001-06-28 07:25:16 +000012317 }
12318 quoteflag = quotef;
12319 backquotelist = bqlist;
12320 grabstackblock(len);
12321 wordtext = out;
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000012322 lasttoken = TWORD;
12323 return lasttoken;
Eric Andersencb57d552001-06-28 07:25:16 +000012324/* end of readtoken routine */
12325
Eric Andersencb57d552001-06-28 07:25:16 +000012326/*
12327 * Check to see whether we are at the end of the here document. When this
12328 * is called, c is set to the first character of the next input line. If
12329 * we are at the end of the here document, this routine sets the c to PEOF.
12330 */
Eric Andersenc470f442003-07-28 09:56:35 +000012331checkend: {
Denys Vlasenko46999802017-07-29 21:12:29 +020012332 if (realeofmark(eofmark)) {
Denys Vlasenkoa7328982017-07-29 19:57:28 +020012333 int markloc;
12334 char *p;
12335
Denis Vlasenko131ae172007-02-18 13:00:19 +000012336#if ENABLE_ASH_ALIAS
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010012337 if (c == PEOA)
12338 c = pgetc_without_PEOA();
Eric Andersenc470f442003-07-28 09:56:35 +000012339#endif
12340 if (striptabs) {
12341 while (c == '\t') {
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010012342 c = pgetc_without_PEOA();
Eric Andersencb57d552001-06-28 07:25:16 +000012343 }
Eric Andersenc470f442003-07-28 09:56:35 +000012344 }
Eric Andersencb57d552001-06-28 07:25:16 +000012345
Denys Vlasenkoa7328982017-07-29 19:57:28 +020012346 markloc = out - (char *)stackblock();
12347 for (p = eofmark; STPUTC(c, out), *p; p++) {
12348 if (c != *p)
12349 goto more_heredoc;
12350
12351 c = pgetc_without_PEOA();
12352 }
12353
12354 if (c == '\n' || c == PEOF) {
12355 c = PEOF;
12356 g_parsefile->linno++;
12357 needprompt = doprompt;
12358 } else {
12359 int len_here;
12360
12361 more_heredoc:
12362 p = (char *)stackblock() + markloc + 1;
12363 len_here = out - p;
12364
12365 if (len_here) {
12366 len_here -= (c >= PEOF);
12367 c = p[-1];
12368
12369 if (len_here) {
12370 char *str;
12371
12372 str = alloca(len_here + 1);
12373 *(char *)mempcpy(str, p, len_here) = '\0';
12374
12375 pushstring(str, NULL);
Eric Andersencb57d552001-06-28 07:25:16 +000012376 }
12377 }
12378 }
Denys Vlasenkoa7328982017-07-29 19:57:28 +020012379
12380 STADJUST((char *)stackblock() + markloc - out, out);
Eric Andersencb57d552001-06-28 07:25:16 +000012381 }
Eric Andersenc470f442003-07-28 09:56:35 +000012382 goto checkend_return;
12383}
Eric Andersencb57d552001-06-28 07:25:16 +000012384
Eric Andersencb57d552001-06-28 07:25:16 +000012385/*
12386 * Parse a redirection operator. The variable "out" points to a string
12387 * specifying the fd to be redirected. The variable "c" contains the
12388 * first character of the redirection operator.
12389 */
Eric Andersenc470f442003-07-28 09:56:35 +000012390parseredir: {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000012391 /* out is already checked to be a valid number or "" */
12392 int fd = (*out == '\0' ? -1 : atoi(out));
Eric Andersenc470f442003-07-28 09:56:35 +000012393 union node *np;
Eric Andersencb57d552001-06-28 07:25:16 +000012394
Denis Vlasenko597906c2008-02-20 16:38:54 +000012395 np = stzalloc(sizeof(struct nfile));
Eric Andersenc470f442003-07-28 09:56:35 +000012396 if (c == '>') {
12397 np->nfile.fd = 1;
Denys Vlasenko220be532018-03-31 19:21:31 +020012398 c = pgetc_eatbnl();
Eric Andersenc470f442003-07-28 09:56:35 +000012399 if (c == '>')
12400 np->type = NAPPEND;
12401 else if (c == '|')
12402 np->type = NCLOBBER;
12403 else if (c == '&')
12404 np->type = NTOFD;
Denis Vlasenko559691a2008-10-05 18:39:31 +000012405 /* it also can be NTO2 (>&file), but we can't figure it out yet */
Eric Andersenc470f442003-07-28 09:56:35 +000012406 else {
12407 np->type = NTO;
12408 pungetc();
Eric Andersencb57d552001-06-28 07:25:16 +000012409 }
Denis Vlasenko834dee72008-10-07 09:18:30 +000012410 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010012411#if BASH_REDIR_OUTPUT
Denis Vlasenko834dee72008-10-07 09:18:30 +000012412 else if (c == 0x100 + '>') { /* this flags &> redirection */
12413 np->nfile.fd = 1;
12414 pgetc(); /* this is '>', no need to check */
12415 np->type = NTO2;
12416 }
12417#endif
12418 else { /* c == '<' */
Denis Vlasenko597906c2008-02-20 16:38:54 +000012419 /*np->nfile.fd = 0; - stzalloc did it */
Denys Vlasenko220be532018-03-31 19:21:31 +020012420 c = pgetc_eatbnl();
Denis Vlasenko5cedb752007-02-18 19:56:41 +000012421 switch (c) {
Eric Andersenc470f442003-07-28 09:56:35 +000012422 case '<':
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000012423 if (sizeof(struct nfile) != sizeof(struct nhere)) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000012424 np = stzalloc(sizeof(struct nhere));
12425 /*np->nfile.fd = 0; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000012426 }
12427 np->type = NHERE;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000012428 heredoc = stzalloc(sizeof(struct heredoc));
Eric Andersenc470f442003-07-28 09:56:35 +000012429 heredoc->here = np;
Denys Vlasenko220be532018-03-31 19:21:31 +020012430 c = pgetc_eatbnl();
Denis Vlasenko5cedb752007-02-18 19:56:41 +000012431 if (c == '-') {
Eric Andersenc470f442003-07-28 09:56:35 +000012432 heredoc->striptabs = 1;
12433 } else {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000012434 /*heredoc->striptabs = 0; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000012435 pungetc();
12436 }
12437 break;
12438
12439 case '&':
12440 np->type = NFROMFD;
12441 break;
12442
12443 case '>':
12444 np->type = NFROMTO;
12445 break;
12446
12447 default:
12448 np->type = NFROM;
12449 pungetc();
12450 break;
12451 }
Eric Andersencb57d552001-06-28 07:25:16 +000012452 }
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000012453 if (fd >= 0)
12454 np->nfile.fd = fd;
Eric Andersenc470f442003-07-28 09:56:35 +000012455 redirnode = np;
12456 goto parseredir_return;
12457}
Eric Andersencb57d552001-06-28 07:25:16 +000012458
Eric Andersencb57d552001-06-28 07:25:16 +000012459/*
12460 * Parse a substitution. At this point, we have read the dollar sign
12461 * and nothing else.
12462 */
Denis Vlasenkocc571512007-02-23 21:10:35 +000012463
12464/* is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise
12465 * (assuming ascii char codes, as the original implementation did) */
12466#define is_special(c) \
Denis Vlasenkoef527f52008-06-23 01:52:30 +000012467 (((unsigned)(c) - 33 < 32) \
12468 && ((0xc1ff920dU >> ((unsigned)(c) - 33)) & 1))
Eric Andersenc470f442003-07-28 09:56:35 +000012469parsesub: {
Denys Vlasenkocd716832009-11-28 22:14:02 +010012470 unsigned char subtype;
Eric Andersenc470f442003-07-28 09:56:35 +000012471 int typeloc;
Eric Andersencb57d552001-06-28 07:25:16 +000012472
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012473 c = pgetc_eatbnl();
Denys Vlasenkoa7328982017-07-29 19:57:28 +020012474 if ((checkkwd & CHKEOFMARK)
12475 || c > 255 /* PEOA or PEOF */
Denis Vlasenkoef527f52008-06-23 01:52:30 +000012476 || (c != '(' && c != '{' && !is_name(c) && !is_special(c))
Eric Andersenc470f442003-07-28 09:56:35 +000012477 ) {
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010012478#if BASH_DOLLAR_SQUOTE
Denys Vlasenko216913c2018-04-02 12:35:04 +020012479 if (synstack->syntax != DQSYNTAX && c == '\'')
Denis Vlasenkoef527f52008-06-23 01:52:30 +000012480 bash_dollar_squote = 1;
12481 else
12482#endif
12483 USTPUTC('$', out);
Eric Andersenc470f442003-07-28 09:56:35 +000012484 pungetc();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012485 } else if (c == '(') {
12486 /* $(command) or $((arith)) */
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012487 if (pgetc_eatbnl() == '(') {
Denys Vlasenko0b883582016-12-23 16:49:07 +010012488#if ENABLE_FEATURE_SH_MATH
Eric Andersenc470f442003-07-28 09:56:35 +000012489 PARSEARITH();
12490#else
Denys Vlasenko4f8079d2017-07-17 17:11:48 +020012491 raise_error_syntax("support for $((arith)) is disabled");
Eric Andersenc470f442003-07-28 09:56:35 +000012492#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012493 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000012494 pungetc();
12495 PARSEBACKQNEW();
12496 }
12497 } else {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012498 /* $VAR, $<specialchar>, ${...}, or PEOA/PEOF */
Denys Vlasenko216913c2018-04-02 12:35:04 +020012499 smalluint newsyn = synstack->syntax;
12500
Eric Andersenc470f442003-07-28 09:56:35 +000012501 USTPUTC(CTLVAR, out);
12502 typeloc = out - (char *)stackblock();
Denys Vlasenko3df14102016-10-26 16:41:13 +020012503 STADJUST(1, out);
Eric Andersenc470f442003-07-28 09:56:35 +000012504 subtype = VSNORMAL;
12505 if (c == '{') {
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012506 c = pgetc_eatbnl();
Denys Vlasenkof15aa572016-10-26 15:56:53 +020012507 subtype = 0;
Eric Andersenc470f442003-07-28 09:56:35 +000012508 }
Denys Vlasenkof15aa572016-10-26 15:56:53 +020012509 varname:
Denys Vlasenko3df14102016-10-26 16:41:13 +020012510 if (is_name(c)) {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012511 /* $[{[#]]NAME[}] */
Eric Andersenc470f442003-07-28 09:56:35 +000012512 do {
12513 STPUTC(c, out);
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012514 c = pgetc_eatbnl();
Denys Vlasenko3df14102016-10-26 16:41:13 +020012515 } while (is_in_name(c));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012516 } else if (isdigit(c)) {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012517 /* $[{[#]]NUM[}] */
Eric Andersenc470f442003-07-28 09:56:35 +000012518 do {
12519 STPUTC(c, out);
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012520 c = pgetc_eatbnl();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012521 } while (isdigit(c));
Denys Vlasenko58eb8052018-08-05 15:58:13 +020012522 } else if (c != '}') {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012523 /* $[{[#]]<specialchar>[}] */
Denys Vlasenkof15aa572016-10-26 15:56:53 +020012524 int cc = c;
12525
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012526 c = pgetc_eatbnl();
Denys Vlasenkof15aa572016-10-26 15:56:53 +020012527 if (!subtype && cc == '#') {
12528 subtype = VSLENGTH;
12529 if (c == '_' || isalnum(c))
12530 goto varname;
12531 cc = c;
12532 c = pgetc_eatbnl();
12533 if (cc == '}' || c != '}') {
12534 pungetc();
12535 subtype = 0;
12536 c = cc;
12537 cc = '#';
12538 }
12539 }
Denys Vlasenko452cc1d2017-08-14 14:23:45 +020012540
12541 if (!is_special(cc)) {
12542 if (subtype == VSLENGTH)
12543 subtype = 0;
12544 goto badsub;
12545 }
12546
Denys Vlasenkof15aa572016-10-26 15:56:53 +020012547 USTPUTC(cc, out);
Denys Vlasenko58eb8052018-08-05 15:58:13 +020012548 } else
12549 goto badsub;
Denys Vlasenko452cc1d2017-08-14 14:23:45 +020012550
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012551 if (c != '}' && subtype == VSLENGTH) {
12552 /* ${#VAR didn't end with } */
Cristian Ionescu-Idbohrn301f5ec2009-10-05 02:07:23 +020012553 goto badsub;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012554 }
Eric Andersencb57d552001-06-28 07:25:16 +000012555
Eric Andersenc470f442003-07-28 09:56:35 +000012556 if (subtype == 0) {
Denys Vlasenkof8ddbe12016-07-25 03:56:00 +020012557 static const char types[] ALIGN1 = "}-+?=";
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012558 /* ${VAR...} but not $VAR or ${#VAR} */
12559 /* c == first char after VAR */
Denys Vlasenko216913c2018-04-02 12:35:04 +020012560 int cc = c;
12561
Eric Andersenc470f442003-07-28 09:56:35 +000012562 switch (c) {
12563 case ':':
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012564 c = pgetc_eatbnl();
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010012565#if BASH_SUBSTR
Denys Vlasenkof8ddbe12016-07-25 03:56:00 +020012566 /* This check is only needed to not misinterpret
12567 * ${VAR:-WORD}, ${VAR:+WORD}, ${VAR:=WORD}, ${VAR:?WORD}
12568 * constructs.
12569 */
12570 if (!strchr(types, c)) {
Denis Vlasenko92e13c22008-03-25 01:17:40 +000012571 subtype = VSSUBSTR;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012572 pungetc();
Denys Vlasenko88e15702016-10-26 01:55:56 +020012573 break; /* "goto badsub" is bigger (!) */
Denis Vlasenko92e13c22008-03-25 01:17:40 +000012574 }
12575#endif
Denys Vlasenko3df14102016-10-26 16:41:13 +020012576 subtype = VSNUL;
Eric Andersenc470f442003-07-28 09:56:35 +000012577 /*FALLTHROUGH*/
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012578 default: {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012579 const char *p = strchr(types, c);
Eric Andersenc470f442003-07-28 09:56:35 +000012580 if (p == NULL)
Denys Vlasenko88e15702016-10-26 01:55:56 +020012581 break;
Denys Vlasenko3df14102016-10-26 16:41:13 +020012582 subtype |= p - types + VSNORMAL;
Eric Andersenc470f442003-07-28 09:56:35 +000012583 break;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012584 }
Eric Andersenc470f442003-07-28 09:56:35 +000012585 case '%':
Denys Vlasenko216913c2018-04-02 12:35:04 +020012586 case '#':
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012587 subtype = (c == '#' ? VSTRIMLEFT : VSTRIMRIGHT);
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012588 c = pgetc_eatbnl();
Denys Vlasenko216913c2018-04-02 12:35:04 +020012589 if (c == cc)
12590 subtype++;
12591 else
12592 pungetc();
12593
12594 newsyn = BASESYNTAX;
Denis Vlasenko92e13c22008-03-25 01:17:40 +000012595 break;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010012596#if BASH_PATTERN_SUBST
Denis Vlasenko92e13c22008-03-25 01:17:40 +000012597 case '/':
Denys Vlasenko6040fe82010-09-12 15:03:16 +020012598 /* ${v/[/]pattern/repl} */
12599//TODO: encode pattern and repl separately.
Denys Vlasenko216913c2018-04-02 12:35:04 +020012600// Currently cases like: v=1;echo ${v/$((1/1))/ONE}
12601// are broken (should print "ONE")
Denis Vlasenko92e13c22008-03-25 01:17:40 +000012602 subtype = VSREPLACE;
Denys Vlasenko216913c2018-04-02 12:35:04 +020012603 newsyn = BASESYNTAX;
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012604 c = pgetc_eatbnl();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012605 if (c != '/')
Denys Vlasenko88e15702016-10-26 01:55:56 +020012606 goto badsub;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012607 subtype++; /* VSREPLACEALL */
Denis Vlasenko92e13c22008-03-25 01:17:40 +000012608 break;
12609#endif
Eric Andersencb57d552001-06-28 07:25:16 +000012610 }
Eric Andersenc470f442003-07-28 09:56:35 +000012611 } else {
Denys Vlasenko88e15702016-10-26 01:55:56 +020012612 badsub:
Eric Andersenc470f442003-07-28 09:56:35 +000012613 pungetc();
12614 }
Denys Vlasenko216913c2018-04-02 12:35:04 +020012615
Denys Vlasenkof50e1462018-04-02 21:00:59 +020012616 if (newsyn == ARISYNTAX)
Denys Vlasenko216913c2018-04-02 12:35:04 +020012617 newsyn = DQSYNTAX;
12618
Denys Vlasenkof50e1462018-04-02 21:00:59 +020012619 if ((newsyn != synstack->syntax || synstack->innerdq)
12620 && subtype != VSNORMAL
12621 ) {
Denys Vlasenko216913c2018-04-02 12:35:04 +020012622 synstack_push(&synstack,
12623 synstack->prev ?: alloca(sizeof(*synstack)),
12624 newsyn);
12625
12626 synstack->varpushed = 1;
12627 synstack->dblquote = newsyn != BASESYNTAX;
12628 }
12629
Denys Vlasenko3df14102016-10-26 16:41:13 +020012630 ((unsigned char *)stackblock())[typeloc] = subtype;
Eric Andersenc470f442003-07-28 09:56:35 +000012631 if (subtype != VSNORMAL) {
Denys Vlasenko216913c2018-04-02 12:35:04 +020012632 synstack->varnest++;
12633 if (synstack->dblquote)
12634 synstack->dqvarnest++;
Eric Andersencb57d552001-06-28 07:25:16 +000012635 }
Denys Vlasenko88e15702016-10-26 01:55:56 +020012636 STPUTC('=', out);
Eric Andersencb57d552001-06-28 07:25:16 +000012637 }
Eric Andersenc470f442003-07-28 09:56:35 +000012638 goto parsesub_return;
12639}
Eric Andersencb57d552001-06-28 07:25:16 +000012640
Eric Andersencb57d552001-06-28 07:25:16 +000012641/*
12642 * Called to parse command substitutions. Newstyle is set if the command
12643 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
12644 * list of commands (passed by reference), and savelen is the number of
12645 * characters on the top of the stack which must be preserved.
12646 */
Eric Andersenc470f442003-07-28 09:56:35 +000012647parsebackq: {
12648 struct nodelist **nlpp;
Eric Andersenc470f442003-07-28 09:56:35 +000012649 union node *n;
Ron Yorston072fc602015-07-01 16:46:18 +010012650 char *str;
Eric Andersenc470f442003-07-28 09:56:35 +000012651 size_t savelen;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000012652 smallint saveprompt = 0;
12653
Eric Andersenc470f442003-07-28 09:56:35 +000012654 str = NULL;
12655 savelen = out - (char *)stackblock();
12656 if (savelen > 0) {
Denys Vlasenko7bc3d392016-09-17 20:53:47 +020012657 /*
12658 * FIXME: this can allocate very large block on stack and SEGV.
12659 * Example:
12660 * echo "..<100kbytes>..`true` $(true) `true` ..."
Denys Vlasenko73737592016-09-17 20:58:22 +020012661 * allocates 100kb for every command subst. With about
Denys Vlasenko7bc3d392016-09-17 20:53:47 +020012662 * a hundred command substitutions stack overflows.
12663 * With larger prepended string, SEGV happens sooner.
12664 */
Ron Yorston072fc602015-07-01 16:46:18 +010012665 str = alloca(savelen);
Eric Andersenc470f442003-07-28 09:56:35 +000012666 memcpy(str, stackblock(), savelen);
12667 }
Denys Vlasenko7bc3d392016-09-17 20:53:47 +020012668
Eric Andersenc470f442003-07-28 09:56:35 +000012669 if (oldstyle) {
12670 /* We must read until the closing backquote, giving special
Denys Vlasenko60cb48c2013-01-14 15:57:44 +010012671 * treatment to some slashes, and then push the string and
12672 * reread it as input, interpreting it normally.
12673 */
Eric Andersenc470f442003-07-28 09:56:35 +000012674 char *pout;
Eric Andersenc470f442003-07-28 09:56:35 +000012675 size_t psavelen;
12676 char *pstr;
12677
Eric Andersenc470f442003-07-28 09:56:35 +000012678 STARTSTACKSTR(pout);
12679 for (;;) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020012680 int pc;
12681
12682 setprompt_if(needprompt, 2);
Denys Vlasenko220be532018-03-31 19:21:31 +020012683 pc = pgetc_eatbnl();
Denis Vlasenko5cedb752007-02-18 19:56:41 +000012684 switch (pc) {
Eric Andersenc470f442003-07-28 09:56:35 +000012685 case '`':
12686 goto done;
12687
12688 case '\\':
Denys Vlasenko220be532018-03-31 19:21:31 +020012689 pc = pgetc(); /* or pgetc_eatbnl()? why (example)? */
Eric Andersenc470f442003-07-28 09:56:35 +000012690 if (pc != '\\' && pc != '`' && pc != '$'
Denys Vlasenko216913c2018-04-02 12:35:04 +020012691 && (!synstack->dblquote || pc != '"')
Denys Vlasenko76bc2d62009-11-29 01:37:46 +010012692 ) {
Eric Andersenc470f442003-07-28 09:56:35 +000012693 STPUTC('\\', pout);
Denys Vlasenko76bc2d62009-11-29 01:37:46 +010012694 }
Denys Vlasenkocd716832009-11-28 22:14:02 +010012695 if (pc <= 255 /* not PEOA or PEOF */) {
Eric Andersenc470f442003-07-28 09:56:35 +000012696 break;
12697 }
12698 /* fall through */
12699
12700 case PEOF:
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010012701 IF_ASH_ALIAS(case PEOA:)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000012702 raise_error_syntax("EOF in backquote substitution");
Eric Andersenc470f442003-07-28 09:56:35 +000012703
12704 case '\n':
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012705 nlnoprompt();
Eric Andersenc470f442003-07-28 09:56:35 +000012706 break;
12707
12708 default:
12709 break;
12710 }
12711 STPUTC(pc, pout);
12712 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +000012713 done:
Eric Andersenc470f442003-07-28 09:56:35 +000012714 STPUTC('\0', pout);
12715 psavelen = pout - (char *)stackblock();
12716 if (psavelen > 0) {
12717 pstr = grabstackstr(pout);
12718 setinputstring(pstr);
12719 }
12720 }
12721 nlpp = &bqlist;
12722 while (*nlpp)
12723 nlpp = &(*nlpp)->next;
Denis Vlasenko597906c2008-02-20 16:38:54 +000012724 *nlpp = stzalloc(sizeof(**nlpp));
12725 /* (*nlpp)->next = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000012726
12727 if (oldstyle) {
12728 saveprompt = doprompt;
12729 doprompt = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000012730 }
12731
Eric Andersenc470f442003-07-28 09:56:35 +000012732 n = list(2);
12733
12734 if (oldstyle)
12735 doprompt = saveprompt;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012736 else if (readtoken() != TRP)
12737 raise_error_unexpected_syntax(TRP);
Eric Andersenc470f442003-07-28 09:56:35 +000012738
12739 (*nlpp)->n = n;
12740 if (oldstyle) {
12741 /*
12742 * Start reading from old file again, ignoring any pushed back
12743 * tokens left from the backquote parsing
12744 */
12745 popfile();
12746 tokpushback = 0;
12747 }
12748 while (stackblocksize() <= savelen)
12749 growstackblock();
12750 STARTSTACKSTR(out);
12751 if (str) {
12752 memcpy(out, str, savelen);
12753 STADJUST(savelen, out);
Eric Andersenc470f442003-07-28 09:56:35 +000012754 }
Ron Yorston549deab2015-05-18 09:57:51 +020012755 USTPUTC(CTLBACKQ, out);
Eric Andersenc470f442003-07-28 09:56:35 +000012756 if (oldstyle)
12757 goto parsebackq_oldreturn;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000012758 goto parsebackq_newreturn;
Eric Andersenc470f442003-07-28 09:56:35 +000012759}
12760
Denys Vlasenko0b883582016-12-23 16:49:07 +010012761#if ENABLE_FEATURE_SH_MATH
Eric Andersencb57d552001-06-28 07:25:16 +000012762/*
12763 * Parse an arithmetic expansion (indicate start of one and set state)
12764 */
Eric Andersenc470f442003-07-28 09:56:35 +000012765parsearith: {
Denys Vlasenko216913c2018-04-02 12:35:04 +020012766
12767 synstack_push(&synstack,
12768 synstack->prev ?: alloca(sizeof(*synstack)),
12769 ARISYNTAX);
12770 synstack->dblquote = 1;
Ron Yorstonad88bde2015-05-18 09:56:16 +020012771 USTPUTC(CTLARI, out);
Eric Andersenc470f442003-07-28 09:56:35 +000012772 goto parsearith_return;
12773}
12774#endif
Eric Andersenc470f442003-07-28 09:56:35 +000012775} /* end of readtoken */
12776
Eric Andersencb57d552001-06-28 07:25:16 +000012777/*
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012778 * Read the next input token.
12779 * If the token is a word, we set backquotelist to the list of cmds in
12780 * backquotes. We set quoteflag to true if any part of the word was
12781 * quoted.
12782 * If the token is TREDIR, then we set redirnode to a structure containing
12783 * the redirection.
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012784 *
12785 * [Change comment: here documents and internal procedures]
12786 * [Readtoken shouldn't have any arguments. Perhaps we should make the
12787 * word parsing code into a separate routine. In this case, readtoken
12788 * doesn't need to have any internal procedures, but parseword does.
12789 * We could also make parseoperator in essence the main routine, and
12790 * have parseword (readtoken1?) handle both words and redirection.]
Eric Andersencb57d552001-06-28 07:25:16 +000012791 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012792#define NEW_xxreadtoken
12793#ifdef NEW_xxreadtoken
12794/* singles must be first! */
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000012795static const char xxreadtoken_chars[7] ALIGN1 = {
Denis Vlasenko834dee72008-10-07 09:18:30 +000012796 '\n', '(', ')', /* singles */
12797 '&', '|', ';', /* doubles */
12798 0
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000012799};
Eric Andersencb57d552001-06-28 07:25:16 +000012800
Denis Vlasenko834dee72008-10-07 09:18:30 +000012801#define xxreadtoken_singles 3
12802#define xxreadtoken_doubles 3
12803
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000012804static const char xxreadtoken_tokens[] ALIGN1 = {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012805 TNL, TLP, TRP, /* only single occurrence allowed */
12806 TBACKGND, TPIPE, TSEMI, /* if single occurrence */
12807 TEOF, /* corresponds to trailing nul */
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000012808 TAND, TOR, TENDCASE /* if double occurrence */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012809};
12810
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012811static int
12812xxreadtoken(void)
12813{
12814 int c;
12815
12816 if (tokpushback) {
12817 tokpushback = 0;
12818 return lasttoken;
Eric Andersencb57d552001-06-28 07:25:16 +000012819 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020012820 setprompt_if(needprompt, 2);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012821 for (;;) { /* until token or start of word found */
Denys Vlasenko220be532018-03-31 19:21:31 +020012822 c = pgetc_eatbnl();
Denis Vlasenko5e34ff22009-04-21 11:09:40 +000012823 if (c == ' ' || c == '\t' IF_ASH_ALIAS( || c == PEOA))
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012824 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012825
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012826 if (c == '#') {
12827 while ((c = pgetc()) != '\n' && c != PEOF)
12828 continue;
12829 pungetc();
12830 } else if (c == '\\') {
Denys Vlasenko220be532018-03-31 19:21:31 +020012831 break; /* return readtoken1(...) */
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012832 } else {
12833 const char *p;
12834
12835 p = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
12836 if (c != PEOF) {
12837 if (c == '\n') {
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012838 nlnoprompt();
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012839 }
12840
12841 p = strchr(xxreadtoken_chars, c);
Denis Vlasenko834dee72008-10-07 09:18:30 +000012842 if (p == NULL)
12843 break; /* return readtoken1(...) */
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012844
Denis Vlasenko834dee72008-10-07 09:18:30 +000012845 if ((int)(p - xxreadtoken_chars) >= xxreadtoken_singles) {
Denys Vlasenko1e5111b2018-04-01 03:04:55 +020012846 int cc = pgetc_eatbnl();
Denis Vlasenko834dee72008-10-07 09:18:30 +000012847 if (cc == c) { /* double occurrence? */
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012848 p += xxreadtoken_doubles + 1;
12849 } else {
12850 pungetc();
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010012851#if BASH_REDIR_OUTPUT
Denis Vlasenko834dee72008-10-07 09:18:30 +000012852 if (c == '&' && cc == '>') /* &> */
12853 break; /* return readtoken1(...) */
12854#endif
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012855 }
12856 }
12857 }
12858 lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
12859 return lasttoken;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012860 }
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012861 } /* for (;;) */
Denis Vlasenko834dee72008-10-07 09:18:30 +000012862
12863 return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012864}
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012865#else /* old xxreadtoken */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012866#define RETURN(token) return lasttoken = token
12867static int
12868xxreadtoken(void)
12869{
12870 int c;
12871
12872 if (tokpushback) {
12873 tokpushback = 0;
12874 return lasttoken;
12875 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020012876 setprompt_if(needprompt, 2);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012877 for (;;) { /* until token or start of word found */
Denys Vlasenko220be532018-03-31 19:21:31 +020012878 c = pgetc_eatbnl();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012879 switch (c) {
12880 case ' ': case '\t':
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010012881 IF_ASH_ALIAS(case PEOA:)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012882 continue;
12883 case '#':
Denis Vlasenkof7d56652008-03-25 05:51:41 +000012884 while ((c = pgetc()) != '\n' && c != PEOF)
12885 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012886 pungetc();
12887 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012888 case '\n':
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012889 nlnoprompt();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012890 RETURN(TNL);
12891 case PEOF:
12892 RETURN(TEOF);
12893 case '&':
Denys Vlasenko220be532018-03-31 19:21:31 +020012894 if (pgetc_eatbnl() == '&')
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012895 RETURN(TAND);
12896 pungetc();
12897 RETURN(TBACKGND);
12898 case '|':
Denys Vlasenko220be532018-03-31 19:21:31 +020012899 if (pgetc_eatbnl() == '|')
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012900 RETURN(TOR);
12901 pungetc();
12902 RETURN(TPIPE);
12903 case ';':
Denys Vlasenko220be532018-03-31 19:21:31 +020012904 if (pgetc_eatbnl() == ';')
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012905 RETURN(TENDCASE);
12906 pungetc();
12907 RETURN(TSEMI);
12908 case '(':
12909 RETURN(TLP);
12910 case ')':
12911 RETURN(TRP);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012912 }
Denys Vlasenko220be532018-03-31 19:21:31 +020012913 break;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012914 }
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012915 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
12916#undef RETURN
12917}
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012918#endif /* old xxreadtoken */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012919
12920static int
12921readtoken(void)
12922{
12923 int t;
Ron Yorston713f07d2015-10-29 16:44:56 +000012924 int kwd = checkkwd;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012925#if DEBUG
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000012926 smallint alreadyseen = tokpushback;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012927#endif
12928
12929#if ENABLE_ASH_ALIAS
12930 top:
12931#endif
12932
12933 t = xxreadtoken();
12934
12935 /*
12936 * eat newlines
12937 */
Ron Yorston713f07d2015-10-29 16:44:56 +000012938 if (kwd & CHKNL) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012939 while (t == TNL) {
12940 parseheredoc();
12941 t = xxreadtoken();
12942 }
12943 }
12944
12945 if (t != TWORD || quoteflag) {
12946 goto out;
12947 }
12948
12949 /*
12950 * check for keywords
12951 */
Ron Yorston713f07d2015-10-29 16:44:56 +000012952 if (kwd & CHKKWD) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012953 const char *const *pp;
12954
12955 pp = findkwd(wordtext);
12956 if (pp) {
12957 lasttoken = t = pp - tokname_array;
Denys Vlasenko888527c2016-10-02 16:54:17 +020012958 TRACE(("keyword '%s' recognized\n", tokname_array[t]));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012959 goto out;
12960 }
12961 }
12962
12963 if (checkkwd & CHKALIAS) {
12964#if ENABLE_ASH_ALIAS
12965 struct alias *ap;
12966 ap = lookupalias(wordtext, 1);
12967 if (ap != NULL) {
12968 if (*ap->val) {
12969 pushstring(ap->val, ap);
12970 }
12971 goto top;
12972 }
12973#endif
12974 }
12975 out:
12976 checkkwd = 0;
12977#if DEBUG
12978 if (!alreadyseen)
Denys Vlasenko888527c2016-10-02 16:54:17 +020012979 TRACE(("token '%s' %s\n", tokname_array[t], t == TWORD ? wordtext : ""));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012980 else
Denys Vlasenko888527c2016-10-02 16:54:17 +020012981 TRACE(("reread token '%s' %s\n", tokname_array[t], t == TWORD ? wordtext : ""));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012982#endif
12983 return t;
Eric Andersencb57d552001-06-28 07:25:16 +000012984}
12985
Ron Yorstonc0e00762015-10-29 11:30:55 +000012986static int
Ron Yorston6bd2fab2015-10-29 11:30:22 +000012987peektoken(void)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012988{
12989 int t;
12990
12991 t = readtoken();
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000012992 tokpushback = 1;
Ron Yorstonc0e00762015-10-29 11:30:55 +000012993 return t;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012994}
Eric Andersencb57d552001-06-28 07:25:16 +000012995
12996/*
Denys Vlasenko86e83ec2009-07-23 22:07:07 +020012997 * Read and parse a command. Returns NODE_EOF on end of file.
12998 * (NULL is a valid parse tree indicating a blank line.)
Eric Andersencb57d552001-06-28 07:25:16 +000012999 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000013000static union node *
13001parsecmd(int interact)
Eric Andersen90898442003-08-06 11:20:52 +000013002{
Denis Vlasenkoaa744452007-02-23 01:04:22 +000013003 tokpushback = 0;
Ron Yorstonc0e00762015-10-29 11:30:55 +000013004 checkkwd = 0;
13005 heredoclist = 0;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000013006 doprompt = interact;
Denys Vlasenko958581a2010-09-12 15:04:27 +020013007 setprompt_if(doprompt, doprompt);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000013008 needprompt = 0;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000013009 return list(1);
13010}
13011
13012/*
13013 * Input any here documents.
13014 */
13015static void
13016parseheredoc(void)
13017{
13018 struct heredoc *here;
13019 union node *n;
13020
13021 here = heredoclist;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000013022 heredoclist = NULL;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000013023
13024 while (here) {
Christoph Schulz03ad7ae2018-11-20 17:45:52 +010013025 tokpushback = 0;
Denys Vlasenko958581a2010-09-12 15:04:27 +020013026 setprompt_if(needprompt, 2);
13027 readtoken1(pgetc(), here->here->type == NHERE ? SQSYNTAX : DQSYNTAX,
Denis Vlasenkoaa744452007-02-23 01:04:22 +000013028 here->eofmark, here->striptabs);
Denis Vlasenko597906c2008-02-20 16:38:54 +000013029 n = stzalloc(sizeof(struct narg));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000013030 n->narg.type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000013031 /*n->narg.next = NULL; - stzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000013032 n->narg.text = wordtext;
13033 n->narg.backquote = backquotelist;
13034 here->here->nhere.doc = n;
13035 here = here->next;
Eric Andersencb57d552001-06-28 07:25:16 +000013036 }
Eric Andersencb57d552001-06-28 07:25:16 +000013037}
13038
13039
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000013040static const char *
Denys Vlasenko46999802017-07-29 21:12:29 +020013041expandstr(const char *ps, int syntax_type)
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000013042{
13043 union node n;
Denys Vlasenko2a6d29a2016-10-25 21:17:52 +020013044 int saveprompt;
Ron Yorston48645b82019-04-18 09:48:13 +010013045 struct parsefile *file_stop = g_parsefile;
Ron Yorstond1a2fa22019-04-18 09:49:13 +010013046 volatile int saveint;
13047 struct jmploc *volatile savehandler = exception_handler;
13048 struct jmploc jmploc;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000013049
Denys Vlasenko46999802017-07-29 21:12:29 +020013050 /* XXX Fix (char *) cast. */
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000013051 setinputstring((char *)ps);
Denys Vlasenko2a6d29a2016-10-25 21:17:52 +020013052
13053 saveprompt = doprompt;
13054 doprompt = 0;
Denys Vlasenkoa2e32b32017-10-12 19:20:13 +020013055
13056 /* readtoken1() might die horribly.
Denys Vlasenko3c183a82017-10-12 19:35:42 +020013057 * Try a prompt with syntactically wrong command:
Denys Vlasenkoa2e32b32017-10-12 19:20:13 +020013058 * PS1='$(date "+%H:%M:%S) > '
13059 */
Ron Yorstond1a2fa22019-04-18 09:49:13 +010013060 SAVE_INT(saveint);
13061 if (setjmp(jmploc.loc) == 0) {
13062 exception_handler = &jmploc;
13063 readtoken1(pgetc(), syntax_type, FAKEEOFMARK, 0);
Denys Vlasenkoa2e32b32017-10-12 19:20:13 +020013064 }
Ron Yorstond1a2fa22019-04-18 09:49:13 +010013065 exception_handler = savehandler;
13066 RESTORE_INT(saveint);
Denys Vlasenkoa2e32b32017-10-12 19:20:13 +020013067
Denys Vlasenko2a6d29a2016-10-25 21:17:52 +020013068 doprompt = saveprompt;
13069
Ron Yorston48645b82019-04-18 09:48:13 +010013070 /* Try: PS1='`xxx(`' */
13071 unwindfiles(file_stop);
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000013072
13073 n.narg.type = NARG;
13074 n.narg.next = NULL;
13075 n.narg.text = wordtext;
13076 n.narg.backquote = backquotelist;
13077
Ron Yorstond1a2fa22019-04-18 09:49:13 +010013078 /* expandarg() might fail too:
13079 * PS1='$((123+))'
13080 */
13081 SAVE_INT(saveint);
13082 if (setjmp(jmploc.loc) == 0) {
13083 exception_handler = &jmploc;
13084 expandarg(&n, NULL, EXP_QUOTED);
13085 }
13086 exception_handler = savehandler;
13087 RESTORE_INT(saveint);
13088
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000013089 return stackblock();
13090}
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000013091
Denys Vlasenko1e3e2cc2017-07-25 20:31:14 +020013092static inline int
13093parser_eof(void)
13094{
13095 return tokpushback && lasttoken == TEOF;
13096}
13097
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013098/*
13099 * Execute a command or commands contained in a string.
13100 */
13101static int
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020013102evalstring(char *s, int flags)
Eric Andersenc470f442003-07-28 09:56:35 +000013103{
Denys Vlasenko493b9ca2016-10-30 18:27:14 +010013104 struct jmploc *volatile savehandler;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020013105 struct jmploc jmploc;
13106 int ex;
13107
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013108 union node *n;
13109 struct stackmark smark;
Denys Vlasenko928e2a72016-09-29 00:30:31 +020013110 int status;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013111
Denys Vlasenko8e2bc472016-09-28 23:02:57 +020013112 s = sstrdup(s);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013113 setinputstring(s);
13114 setstackmark(&smark);
13115
Denys Vlasenko928e2a72016-09-29 00:30:31 +020013116 status = 0;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020013117 /* On exception inside execution loop, we must popfile().
13118 * Try interactively:
13119 * readonly a=a
13120 * command eval "a=b" # throws "is read only" error
13121 * "command BLTIN" is not supposed to abort (even in non-interactive use).
13122 * But if we skip popfile(), we hit EOF in eval's string, and exit.
13123 */
13124 savehandler = exception_handler;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020013125 ex = setjmp(jmploc.loc);
13126 if (ex)
13127 goto out;
Denys Vlasenko493b9ca2016-10-30 18:27:14 +010013128 exception_handler = &jmploc;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020013129
Denys Vlasenko86e83ec2009-07-23 22:07:07 +020013130 while ((n = parsecmd(0)) != NODE_EOF) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020013131 int i;
13132
Denys Vlasenko1e3e2cc2017-07-25 20:31:14 +020013133 i = evaltree(n, flags & ~(parser_eof() ? 0 : EV_EXIT));
Denys Vlasenko928e2a72016-09-29 00:30:31 +020013134 if (n)
13135 status = i;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013136 popstackmark(&smark);
Denys Vlasenko928e2a72016-09-29 00:30:31 +020013137 if (evalskip)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013138 break;
13139 }
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020013140 out:
Denys Vlasenko8e2bc472016-09-28 23:02:57 +020013141 popstackmark(&smark);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013142 popfile();
Denys Vlasenko8e2bc472016-09-28 23:02:57 +020013143 stunalloc(s);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013144
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020013145 exception_handler = savehandler;
13146 if (ex)
Denys Vlasenko14c85eb2017-10-12 19:40:47 +020013147 longjmp(exception_handler->loc, ex);
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020013148
Denys Vlasenko928e2a72016-09-29 00:30:31 +020013149 return status;
Eric Andersenc470f442003-07-28 09:56:35 +000013150}
13151
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013152/*
13153 * The eval command.
13154 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013155static int FAST_FUNC
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020013156evalcmd(int argc UNUSED_PARAM, char **argv, int flags)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013157{
13158 char *p;
13159 char *concat;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013160
Denis Vlasenko68404f12008-03-17 09:00:54 +000013161 if (argv[1]) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013162 p = argv[1];
Denis Vlasenko68404f12008-03-17 09:00:54 +000013163 argv += 2;
13164 if (argv[0]) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013165 STARTSTACKSTR(concat);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013166 for (;;) {
13167 concat = stack_putstr(p, concat);
Denis Vlasenko68404f12008-03-17 09:00:54 +000013168 p = *argv++;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013169 if (p == NULL)
13170 break;
13171 STPUTC(' ', concat);
13172 }
13173 STPUTC('\0', concat);
13174 p = grabstackstr(concat);
13175 }
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020013176 return evalstring(p, flags & EV_TESTED);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013177 }
Denys Vlasenko928e2a72016-09-29 00:30:31 +020013178 return 0;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013179}
13180
13181/*
Denys Vlasenko285ad152009-12-04 23:02:27 +010013182 * Read and execute commands.
13183 * "Top" is nonzero for the top level command loop;
13184 * it turns on prompting if the shell is interactive.
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013185 */
13186static int
13187cmdloop(int top)
13188{
13189 union node *n;
13190 struct stackmark smark;
13191 int inter;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020013192 int status = 0;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013193 int numeof = 0;
13194
13195 TRACE(("cmdloop(%d) called\n", top));
13196 for (;;) {
13197 int skip;
13198
13199 setstackmark(&smark);
13200#if JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +000013201 if (doing_jobctl)
Denys Vlasenko9c541002015-10-07 15:44:36 +020013202 showjobs(SHOW_CHANGED|SHOW_STDERR);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013203#endif
13204 inter = 0;
13205 if (iflag && top) {
13206 inter++;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013207 chkmail();
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013208 }
13209 n = parsecmd(inter);
Denys Vlasenko7cee00e2009-07-24 01:08:03 +020013210#if DEBUG
13211 if (DEBUG > 2 && debug && (n != NODE_EOF))
Denys Vlasenko883cea42009-07-11 15:31:59 +020013212 showtree(n);
Denis Vlasenko135cecb2009-04-12 00:00:57 +000013213#endif
Denys Vlasenko86e83ec2009-07-23 22:07:07 +020013214 if (n == NODE_EOF) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013215 if (!top || numeof >= 50)
13216 break;
13217 if (!stoppedjobs()) {
13218 if (!Iflag)
13219 break;
13220 out2str("\nUse \"exit\" to leave shell.\n");
13221 }
13222 numeof++;
13223 } else if (nflag == 0) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020013224 int i;
13225
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +000013226 /* job_warning can only be 2,1,0. Here 2->1, 1/0->0 */
13227 job_warning >>= 1;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013228 numeof = 0;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020013229 i = evaltree(n, 0);
13230 if (n)
13231 status = i;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013232 }
13233 popstackmark(&smark);
13234 skip = evalskip;
13235
13236 if (skip) {
Denys Vlasenko6a0710e2016-09-30 14:18:34 +020013237 evalskip &= ~SKIPFUNC;
Denys Vlasenko0840c912016-10-01 15:27:44 +020013238 break;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013239 }
13240 }
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020013241 return status;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013242}
13243
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000013244/*
13245 * Take commands from a file. To be compatible we should do a path
13246 * search for the file, which is necessary to find sub-commands.
13247 */
13248static char *
13249find_dot_file(char *name)
13250{
13251 char *fullname;
13252 const char *path = pathval();
13253 struct stat statb;
13254
13255 /* don't try this for absolute or relative paths */
13256 if (strchr(name, '/'))
13257 return name;
13258
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020013259 while ((fullname = path_advance(&path, name)) != NULL) {
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000013260 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
13261 /*
13262 * Don't bother freeing here, since it will
13263 * be freed by the caller.
13264 */
13265 return fullname;
13266 }
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020013267 if (fullname != name)
13268 stunalloc(fullname);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000013269 }
Denys Vlasenko01f7b9e2018-01-26 15:15:43 +010013270 /* not found in PATH */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000013271
Denys Vlasenko01f7b9e2018-01-26 15:15:43 +010013272#if ENABLE_ASH_BASH_SOURCE_CURDIR
13273 return name;
13274#else
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000013275 ash_msg_and_raise_error("%s: not found", name);
13276 /* NOTREACHED */
Denys Vlasenko01f7b9e2018-01-26 15:15:43 +010013277#endif
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000013278}
13279
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013280static int FAST_FUNC
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020013281dotcmd(int argc_ UNUSED_PARAM, char **argv_ UNUSED_PARAM)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013282{
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020013283 /* "false; . empty_file; echo $?" should print 0, not 1: */
13284 int status = 0;
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020013285 char *fullname;
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020013286 char **argv;
Denys Vlasenkofb87d932017-01-09 08:22:06 +010013287 char *args_need_save;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013288 volatile struct shparam saveparam;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013289
Denys Vlasenko981a0562017-07-26 19:53:11 +020013290//???
13291// struct strlist *sp;
13292// for (sp = cmdenviron; sp; sp = sp->next)
13293// setvareq(ckstrdup(sp->text), VSTRFIXED | VTEXTFIXED);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013294
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020013295 nextopt(nullstr); /* handle possible "--" */
13296 argv = argptr;
13297
13298 if (!argv[0]) {
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020013299 /* bash says: "bash: .: filename argument required" */
13300 return 2; /* bash compat */
13301 }
13302
Denys Vlasenko091f8312013-03-17 14:25:22 +010013303 /* This aborts if file isn't found, which is POSIXly correct.
13304 * bash returns exitcode 1 instead.
13305 */
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020013306 fullname = find_dot_file(argv[0]);
13307 argv++;
Denys Vlasenkofb87d932017-01-09 08:22:06 +010013308 args_need_save = argv[0];
Denys Vlasenko5f7c82b2017-02-03 13:00:06 +010013309 if (args_need_save) { /* ". FILE ARGS", and ARGS are not empty */
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020013310 int argc;
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020013311 saveparam = shellparam;
13312 shellparam.malloced = 0;
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020013313 argc = 1;
13314 while (argv[argc])
13315 argc++;
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020013316 shellparam.nparam = argc;
13317 shellparam.p = argv;
13318 };
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013319
Denys Vlasenko091f8312013-03-17 14:25:22 +010013320 /* This aborts if file can't be opened, which is POSIXly correct.
13321 * bash returns exitcode 1 instead.
13322 */
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020013323 setinputfile(fullname, INPUT_PUSH_FILE);
13324 commandname = fullname;
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020013325 status = cmdloop(0);
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020013326 popfile();
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013327
Denys Vlasenkofb87d932017-01-09 08:22:06 +010013328 if (args_need_save) {
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020013329 freeparam(&shellparam);
13330 shellparam = saveparam;
13331 };
13332
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020013333 return status;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013334}
13335
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013336static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013337exitcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013338{
13339 if (stoppedjobs())
13340 return 0;
Denis Vlasenko68404f12008-03-17 09:00:54 +000013341 if (argv[1])
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013342 exitstatus = number(argv[1]);
13343 raise_exception(EXEXIT);
13344 /* NOTREACHED */
13345}
13346
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013347/*
13348 * Read a file containing shell functions.
13349 */
13350static void
13351readcmdfile(char *name)
13352{
13353 setinputfile(name, INPUT_PUSH_FILE);
13354 cmdloop(0);
13355 popfile();
13356}
13357
13358
Denis Vlasenkocc571512007-02-23 21:10:35 +000013359/* ============ find_command inplementation */
13360
13361/*
13362 * Resolve a command name. If you change this routine, you may have to
13363 * change the shellexec routine as well.
13364 */
13365static void
13366find_command(char *name, struct cmdentry *entry, int act, const char *path)
13367{
13368 struct tblentry *cmdp;
13369 int idx;
13370 int prev;
13371 char *fullname;
13372 struct stat statb;
13373 int e;
13374 int updatetbl;
13375 struct builtincmd *bcmd;
13376
13377 /* If name contains a slash, don't use PATH or hash table */
13378 if (strchr(name, '/') != NULL) {
13379 entry->u.index = -1;
13380 if (act & DO_ABS) {
13381 while (stat(name, &statb) < 0) {
13382#ifdef SYSV
13383 if (errno == EINTR)
13384 continue;
13385#endif
13386 entry->cmdtype = CMDUNKNOWN;
13387 return;
13388 }
13389 }
13390 entry->cmdtype = CMDNORMAL;
13391 return;
13392 }
13393
Denis Vlasenkof20de5b2007-04-29 23:42:54 +000013394/* #if ENABLE_FEATURE_SH_STANDALONE... moved after builtin check */
Denis Vlasenkocc571512007-02-23 21:10:35 +000013395
13396 updatetbl = (path == pathval());
13397 if (!updatetbl) {
13398 act |= DO_ALTPATH;
13399 if (strstr(path, "%builtin") != NULL)
13400 act |= DO_ALTBLTIN;
13401 }
13402
13403 /* If name is in the table, check answer will be ok */
13404 cmdp = cmdlookup(name, 0);
13405 if (cmdp != NULL) {
13406 int bit;
13407
13408 switch (cmdp->cmdtype) {
13409 default:
13410#if DEBUG
13411 abort();
13412#endif
13413 case CMDNORMAL:
13414 bit = DO_ALTPATH;
13415 break;
13416 case CMDFUNCTION:
13417 bit = DO_NOFUNC;
13418 break;
13419 case CMDBUILTIN:
13420 bit = DO_ALTBLTIN;
13421 break;
13422 }
13423 if (act & bit) {
13424 updatetbl = 0;
13425 cmdp = NULL;
13426 } else if (cmdp->rehash == 0)
13427 /* if not invalidated by cd, we're done */
13428 goto success;
13429 }
13430
13431 /* If %builtin not in path, check for builtin next */
13432 bcmd = find_builtin(name);
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000013433 if (bcmd) {
13434 if (IS_BUILTIN_REGULAR(bcmd))
13435 goto builtin_success;
13436 if (act & DO_ALTPATH) {
13437 if (!(act & DO_ALTBLTIN))
13438 goto builtin_success;
13439 } else if (builtinloc <= 0) {
13440 goto builtin_success;
Denis Vlasenko8e858e22007-03-07 09:35:43 +000013441 }
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000013442 }
Denis Vlasenkocc571512007-02-23 21:10:35 +000013443
Denis Vlasenkof20de5b2007-04-29 23:42:54 +000013444#if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko7465dbc2008-04-13 02:25:53 +000013445 {
13446 int applet_no = find_applet_by_name(name);
13447 if (applet_no >= 0) {
13448 entry->cmdtype = CMDNORMAL;
13449 entry->u.index = -2 - applet_no;
13450 return;
13451 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +000013452 }
13453#endif
13454
Denis Vlasenkocc571512007-02-23 21:10:35 +000013455 /* We have to search path. */
13456 prev = -1; /* where to start */
13457 if (cmdp && cmdp->rehash) { /* doing a rehash */
13458 if (cmdp->cmdtype == CMDBUILTIN)
13459 prev = builtinloc;
13460 else
13461 prev = cmdp->param.index;
13462 }
13463
13464 e = ENOENT;
13465 idx = -1;
13466 loop:
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020013467 while ((fullname = path_advance(&path, name)) != NULL) {
Denis Vlasenkocc571512007-02-23 21:10:35 +000013468 stunalloc(fullname);
Denis Vlasenkodee82b62007-07-29 14:05:27 +000013469 /* NB: code below will still use fullname
13470 * despite it being "unallocated" */
Denis Vlasenkocc571512007-02-23 21:10:35 +000013471 idx++;
13472 if (pathopt) {
13473 if (prefix(pathopt, "builtin")) {
13474 if (bcmd)
13475 goto builtin_success;
13476 continue;
Denis Vlasenko4a9ca132008-04-12 20:07:08 +000013477 }
13478 if ((act & DO_NOFUNC)
13479 || !prefix(pathopt, "func")
Denys Vlasenkoe4dcba12010-10-28 18:57:19 +020013480 ) { /* ignore unimplemented options */
Denis Vlasenkocc571512007-02-23 21:10:35 +000013481 continue;
13482 }
13483 }
13484 /* if rehash, don't redo absolute path names */
13485 if (fullname[0] == '/' && idx <= prev) {
13486 if (idx < prev)
13487 continue;
13488 TRACE(("searchexec \"%s\": no change\n", name));
13489 goto success;
13490 }
13491 while (stat(fullname, &statb) < 0) {
13492#ifdef SYSV
13493 if (errno == EINTR)
13494 continue;
13495#endif
13496 if (errno != ENOENT && errno != ENOTDIR)
13497 e = errno;
13498 goto loop;
13499 }
13500 e = EACCES; /* if we fail, this will be the error */
13501 if (!S_ISREG(statb.st_mode))
13502 continue;
13503 if (pathopt) { /* this is a %func directory */
13504 stalloc(strlen(fullname) + 1);
Denis Vlasenkodee82b62007-07-29 14:05:27 +000013505 /* NB: stalloc will return space pointed by fullname
13506 * (because we don't have any intervening allocations
13507 * between stunalloc above and this stalloc) */
Denis Vlasenkocc571512007-02-23 21:10:35 +000013508 readcmdfile(fullname);
13509 cmdp = cmdlookup(name, 0);
13510 if (cmdp == NULL || cmdp->cmdtype != CMDFUNCTION)
13511 ash_msg_and_raise_error("%s not defined in %s", name, fullname);
13512 stunalloc(fullname);
13513 goto success;
13514 }
13515 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
13516 if (!updatetbl) {
13517 entry->cmdtype = CMDNORMAL;
13518 entry->u.index = idx;
13519 return;
13520 }
13521 INT_OFF;
13522 cmdp = cmdlookup(name, 1);
13523 cmdp->cmdtype = CMDNORMAL;
13524 cmdp->param.index = idx;
13525 INT_ON;
13526 goto success;
13527 }
13528
13529 /* We failed. If there was an entry for this command, delete it */
13530 if (cmdp && updatetbl)
13531 delete_cmd_entry();
William Pitcockd8fd88a2018-01-24 18:33:18 +010013532 if (act & DO_ERR) {
13533#if ENABLE_ASH_BASH_NOT_FOUND_HOOK
13534 struct tblentry *hookp = cmdlookup("command_not_found_handle", 0);
13535 if (hookp && hookp->cmdtype == CMDFUNCTION) {
13536 char *argv[3];
13537 argv[0] = (char*) "command_not_found_handle";
13538 argv[1] = name;
13539 argv[2] = NULL;
13540 evalfun(hookp->param.func, 2, argv, 0);
13541 entry->cmdtype = CMDUNKNOWN;
13542 return;
13543 }
13544#endif
Denis Vlasenkocc571512007-02-23 21:10:35 +000013545 ash_msg("%s: %s", name, errmsg(e, "not found"));
William Pitcockd8fd88a2018-01-24 18:33:18 +010013546 }
Denis Vlasenkocc571512007-02-23 21:10:35 +000013547 entry->cmdtype = CMDUNKNOWN;
13548 return;
13549
13550 builtin_success:
13551 if (!updatetbl) {
13552 entry->cmdtype = CMDBUILTIN;
13553 entry->u.cmd = bcmd;
13554 return;
13555 }
13556 INT_OFF;
13557 cmdp = cmdlookup(name, 1);
13558 cmdp->cmdtype = CMDBUILTIN;
13559 cmdp->param.cmd = bcmd;
13560 INT_ON;
13561 success:
13562 cmdp->rehash = 0;
13563 entry->cmdtype = cmdp->cmdtype;
13564 entry->u = cmdp->param;
13565}
13566
13567
Eric Andersencb57d552001-06-28 07:25:16 +000013568/*
Eric Andersencb57d552001-06-28 07:25:16 +000013569 * The trap builtin.
13570 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013571static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013572trapcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +000013573{
13574 char *action;
13575 char **ap;
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010013576 int signo, exitcode;
Eric Andersencb57d552001-06-28 07:25:16 +000013577
Eric Andersenc470f442003-07-28 09:56:35 +000013578 nextopt(nullstr);
13579 ap = argptr;
13580 if (!*ap) {
Denis Vlasenko2da584f2007-02-19 22:44:05 +000013581 for (signo = 0; signo < NSIG; signo++) {
Denys Vlasenko21d87d42009-09-25 00:06:51 +020013582 char *tr = trap_ptr[signo];
13583 if (tr) {
Denys Vlasenkoe74aaf92009-09-27 02:05:45 +020013584 /* note: bash adds "SIG", but only if invoked
13585 * as "bash". If called as "sh", or if set -o posix,
13586 * then it prints short signal names.
13587 * We are printing short names: */
13588 out1fmt("trap -- %s %s\n",
Denys Vlasenko21d87d42009-09-25 00:06:51 +020013589 single_quote(tr),
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +000013590 get_signame(signo));
Denys Vlasenko726e1a02009-09-25 02:58:20 +020013591 /* trap_ptr != trap only if we are in special-cased `trap` code.
13592 * In this case, we will exit very soon, no need to free(). */
Denys Vlasenkoe74aaf92009-09-27 02:05:45 +020013593 /* if (trap_ptr != trap && tp[0]) */
Denys Vlasenko726e1a02009-09-25 02:58:20 +020013594 /* free(tr); */
Eric Andersencb57d552001-06-28 07:25:16 +000013595 }
13596 }
Denys Vlasenko726e1a02009-09-25 02:58:20 +020013597 /*
Denys Vlasenko21d87d42009-09-25 00:06:51 +020013598 if (trap_ptr != trap) {
13599 free(trap_ptr);
13600 trap_ptr = trap;
13601 }
Denys Vlasenko726e1a02009-09-25 02:58:20 +020013602 */
Eric Andersencb57d552001-06-28 07:25:16 +000013603 return 0;
13604 }
Denys Vlasenko21d87d42009-09-25 00:06:51 +020013605
Denys Vlasenko86981e32017-07-25 20:06:17 +020013606 /* Why the second check?
13607 * "trap NUM [sig2]..." is the same as "trap - NUM [sig2]..."
13608 * In this case, NUM is signal no, not an action.
13609 */
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +000013610 action = NULL;
Denys Vlasenko86981e32017-07-25 20:06:17 +020013611 if (ap[1] && !is_number(ap[0]))
Eric Andersencb57d552001-06-28 07:25:16 +000013612 action = *ap++;
Denys Vlasenko86981e32017-07-25 20:06:17 +020013613
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010013614 exitcode = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000013615 while (*ap) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000013616 signo = get_signum(*ap);
Denys Vlasenko86981e32017-07-25 20:06:17 +020013617 if (signo < 0) {
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010013618 /* Mimic bash message exactly */
13619 ash_msg("%s: invalid signal specification", *ap);
13620 exitcode = 1;
13621 goto next;
13622 }
Denis Vlasenkob012b102007-02-19 22:43:01 +000013623 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +000013624 if (action) {
Denis Vlasenko9f739442006-12-16 23:49:13 +000013625 if (LONE_DASH(action))
Eric Andersencb57d552001-06-28 07:25:16 +000013626 action = NULL;
Denys Vlasenkob4f51d32016-10-27 12:55:09 +020013627 else {
13628 if (action[0]) /* not NULL and not "" and not "-" */
13629 may_have_traps = 1;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013630 action = ckstrdup(action);
Denys Vlasenkob4f51d32016-10-27 12:55:09 +020013631 }
Eric Andersencb57d552001-06-28 07:25:16 +000013632 }
Denis Vlasenko60818682007-09-28 22:07:23 +000013633 free(trap[signo]);
Eric Andersencb57d552001-06-28 07:25:16 +000013634 trap[signo] = action;
13635 if (signo != 0)
13636 setsignal(signo);
Denis Vlasenkob012b102007-02-19 22:43:01 +000013637 INT_ON;
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010013638 next:
Eric Andersencb57d552001-06-28 07:25:16 +000013639 ap++;
13640 }
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010013641 return exitcode;
Eric Andersencb57d552001-06-28 07:25:16 +000013642}
13643
Eric Andersenc470f442003-07-28 09:56:35 +000013644
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013645/* ============ Builtins */
Eric Andersenc470f442003-07-28 09:56:35 +000013646
Denys Vlasenko2ec34962014-09-08 16:52:39 +020013647#if ENABLE_ASH_HELP
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013648static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013649helpcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000013650{
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000013651 unsigned col;
13652 unsigned i;
Eric Andersenc470f442003-07-28 09:56:35 +000013653
Denys Vlasenkod6b05eb2009-06-06 20:59:55 +020013654 out1fmt(
Denis Vlasenko34d4d892009-04-04 20:24:37 +000013655 "Built-in commands:\n"
13656 "------------------\n");
Denis Vlasenkob71c6682007-07-21 15:08:09 +000013657 for (col = 0, i = 0; i < ARRAY_SIZE(builtintab); i++) {
Eric Andersenc470f442003-07-28 09:56:35 +000013658 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
Denis Vlasenko52764022007-02-24 13:42:56 +000013659 builtintab[i].name + 1);
Eric Andersenc470f442003-07-28 09:56:35 +000013660 if (col > 60) {
13661 out1fmt("\n");
13662 col = 0;
13663 }
13664 }
Denys Vlasenko2ec34962014-09-08 16:52:39 +020013665# if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko1aa7e472007-11-28 06:49:03 +000013666 {
13667 const char *a = applet_names;
13668 while (*a) {
13669 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), a);
13670 if (col > 60) {
13671 out1fmt("\n");
13672 col = 0;
13673 }
Ron Yorston2b919582016-04-08 11:57:20 +010013674 while (*a++ != '\0')
13675 continue;
Eric Andersenc470f442003-07-28 09:56:35 +000013676 }
13677 }
Denys Vlasenko2ec34962014-09-08 16:52:39 +020013678# endif
Denys Vlasenkoebedb942016-10-02 18:45:09 +020013679 newline_and_flush(stdout);
Eric Andersenc470f442003-07-28 09:56:35 +000013680 return EXIT_SUCCESS;
13681}
Denys Vlasenko2ec34962014-09-08 16:52:39 +020013682#endif
Eric Andersenc470f442003-07-28 09:56:35 +000013683
Flemming Madsend96ffda2013-04-07 18:47:24 +020013684#if MAX_HISTORY
13685static int FAST_FUNC
13686historycmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
13687{
13688 show_history(line_input_state);
13689 return EXIT_SUCCESS;
13690}
13691#endif
13692
Eric Andersencb57d552001-06-28 07:25:16 +000013693/*
Eric Andersencb57d552001-06-28 07:25:16 +000013694 * The export and readonly commands.
13695 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013696static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013697exportcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000013698{
13699 struct var *vp;
13700 char *name;
13701 const char *p;
Eric Andersenc470f442003-07-28 09:56:35 +000013702 char **aptr;
Denys Vlasenkod5275882012-10-01 13:41:17 +020013703 char opt;
13704 int flag;
13705 int flag_off;
Eric Andersencb57d552001-06-28 07:25:16 +000013706
Denys Vlasenkod5275882012-10-01 13:41:17 +020013707 /* "readonly" in bash accepts, but ignores -n.
13708 * We do the same: it saves a conditional in nextopt's param.
13709 */
13710 flag_off = 0;
13711 while ((opt = nextopt("np")) != '\0') {
13712 if (opt == 'n')
13713 flag_off = VEXPORT;
13714 }
13715 flag = VEXPORT;
13716 if (argv[0][0] == 'r') {
13717 flag = VREADONLY;
13718 flag_off = 0; /* readonly ignores -n */
13719 }
13720 flag_off = ~flag_off;
13721
Denys Vlasenko10ad6222017-04-17 16:13:32 +020013722 /*if (opt_p_not_specified) - bash doesn't check this. Try "export -p NAME" */
Denys Vlasenkod5275882012-10-01 13:41:17 +020013723 {
Denis Vlasenko2da584f2007-02-19 22:44:05 +000013724 aptr = argptr;
13725 name = *aptr;
13726 if (name) {
13727 do {
13728 p = strchr(name, '=');
13729 if (p != NULL) {
13730 p++;
13731 } else {
13732 vp = *findvar(hashvar(name), name);
13733 if (vp) {
Denys Vlasenkod5275882012-10-01 13:41:17 +020013734 vp->flags = ((vp->flags | flag) & flag_off);
Denis Vlasenko2da584f2007-02-19 22:44:05 +000013735 continue;
13736 }
Eric Andersencb57d552001-06-28 07:25:16 +000013737 }
Denys Vlasenkod5275882012-10-01 13:41:17 +020013738 setvar(name, p, (flag & flag_off));
Denis Vlasenko2da584f2007-02-19 22:44:05 +000013739 } while ((name = *++aptr) != NULL);
13740 return 0;
13741 }
Eric Andersencb57d552001-06-28 07:25:16 +000013742 }
Denys Vlasenkod5275882012-10-01 13:41:17 +020013743
13744 /* No arguments. Show the list of exported or readonly vars.
13745 * -n is ignored.
13746 */
Denis Vlasenko2da584f2007-02-19 22:44:05 +000013747 showvars(argv[0], flag, 0);
Eric Andersencb57d552001-06-28 07:25:16 +000013748 return 0;
13749}
13750
Eric Andersencb57d552001-06-28 07:25:16 +000013751/*
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000013752 * Delete a function if it exists.
Eric Andersencb57d552001-06-28 07:25:16 +000013753 */
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +000013754static void
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000013755unsetfunc(const char *name)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000013756{
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000013757 struct tblentry *cmdp;
Eric Andersencb57d552001-06-28 07:25:16 +000013758
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000013759 cmdp = cmdlookup(name, 0);
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020013760 if (cmdp != NULL && cmdp->cmdtype == CMDFUNCTION)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000013761 delete_cmd_entry();
Eric Andersenc470f442003-07-28 09:56:35 +000013762}
13763
Eric Andersencb57d552001-06-28 07:25:16 +000013764/*
Eric Andersencb57d552001-06-28 07:25:16 +000013765 * The unset builtin command. We unset the function before we unset the
13766 * variable to allow a function to be unset when there is a readonly variable
13767 * with the same name.
13768 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013769static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013770unsetcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +000013771{
13772 char **ap;
13773 int i;
Eric Andersenc470f442003-07-28 09:56:35 +000013774 int flag = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000013775
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020013776 while ((i = nextopt("vf")) != 0) {
Eric Andersenc470f442003-07-28 09:56:35 +000013777 flag = i;
Eric Andersencb57d552001-06-28 07:25:16 +000013778 }
Eric Andersencb57d552001-06-28 07:25:16 +000013779
Denis Vlasenko2da584f2007-02-19 22:44:05 +000013780 for (ap = argptr; *ap; ap++) {
Eric Andersenc470f442003-07-28 09:56:35 +000013781 if (flag != 'f') {
Denys Vlasenkob28d4c32017-07-25 16:29:36 +020013782 unsetvar(*ap);
13783 continue;
Eric Andersenc470f442003-07-28 09:56:35 +000013784 }
13785 if (flag != 'v')
Eric Andersencb57d552001-06-28 07:25:16 +000013786 unsetfunc(*ap);
Eric Andersencb57d552001-06-28 07:25:16 +000013787 }
Denys Vlasenkob28d4c32017-07-25 16:29:36 +020013788 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +000013789}
13790
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000013791static const unsigned char timescmd_str[] ALIGN1 = {
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013792 ' ', offsetof(struct tms, tms_utime),
13793 '\n', offsetof(struct tms, tms_stime),
13794 ' ', offsetof(struct tms, tms_cutime),
13795 '\n', offsetof(struct tms, tms_cstime),
13796 0
13797};
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013798static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013799timescmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013800{
Denys Vlasenko11f2e992017-08-10 16:34:03 +020013801 unsigned clk_tck;
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013802 const unsigned char *p;
13803 struct tms buf;
13804
Bartosz Golaszewski5d2e4092014-06-22 14:01:13 +020013805 clk_tck = bb_clk_tck();
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013806
Denys Vlasenko11f2e992017-08-10 16:34:03 +020013807 times(&buf);
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013808 p = timescmd_str;
13809 do {
Denys Vlasenko11f2e992017-08-10 16:34:03 +020013810 unsigned sec, frac;
13811 unsigned long t;
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013812 t = *(clock_t *)(((char *) &buf) + p[1]);
Denys Vlasenko11f2e992017-08-10 16:34:03 +020013813 sec = t / clk_tck;
13814 frac = t % clk_tck;
13815 out1fmt("%um%u.%03us%c",
13816 sec / 60, sec % 60,
13817 (frac * 1000) / clk_tck,
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013818 p[0]);
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020013819 p += 2;
13820 } while (*p);
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013821
Eric Andersencb57d552001-06-28 07:25:16 +000013822 return 0;
13823}
13824
Denys Vlasenko0b883582016-12-23 16:49:07 +010013825#if ENABLE_FEATURE_SH_MATH
Eric Andersenc470f442003-07-28 09:56:35 +000013826/*
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020013827 * The let builtin. Partially stolen from GNU Bash, the Bourne Again SHell.
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +000013828 * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
Eric Andersen90898442003-08-06 11:20:52 +000013829 *
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +000013830 * Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
Eric Andersenc470f442003-07-28 09:56:35 +000013831 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013832static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013833letcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersenc470f442003-07-28 09:56:35 +000013834{
Denis Vlasenko68404f12008-03-17 09:00:54 +000013835 arith_t i;
Eric Andersenc470f442003-07-28 09:56:35 +000013836
Denis Vlasenko68404f12008-03-17 09:00:54 +000013837 argv++;
13838 if (!*argv)
Denis Vlasenkob012b102007-02-19 22:43:01 +000013839 ash_msg_and_raise_error("expression expected");
Denis Vlasenko68404f12008-03-17 09:00:54 +000013840 do {
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +000013841 i = ash_arith(*argv);
Denis Vlasenko68404f12008-03-17 09:00:54 +000013842 } while (*++argv);
Eric Andersenc470f442003-07-28 09:56:35 +000013843
Denis Vlasenkod9e15f22006-11-27 16:49:55 +000013844 return !i;
Eric Andersenc470f442003-07-28 09:56:35 +000013845}
Eric Andersenc470f442003-07-28 09:56:35 +000013846#endif
Eric Andersen74bcd162001-07-30 21:41:37 +000013847
Eric Andersenc470f442003-07-28 09:56:35 +000013848/*
Denis Vlasenko59f351c2008-03-25 00:07:12 +000013849 * The read builtin. Options:
13850 * -r Do not interpret '\' specially
13851 * -s Turn off echo (tty only)
13852 * -n NCHARS Read NCHARS max
13853 * -p PROMPT Display PROMPT on stderr (if input is from tty)
13854 * -t SECONDS Timeout after SECONDS (tty or pipe only)
13855 * -u FD Read from given FD instead of fd 0
Johannes Schindelin3bef5d82017-08-08 16:46:39 +020013856 * -d DELIM End on DELIM char, not newline
Eric Andersenc470f442003-07-28 09:56:35 +000013857 * This uses unbuffered input, which may be avoidable in some cases.
Denis Vlasenko59f351c2008-03-25 00:07:12 +000013858 * TODO: bash also has:
13859 * -a ARRAY Read into array[0],[1],etc
Denis Vlasenko59f351c2008-03-25 00:07:12 +000013860 * -e Use line editing (tty only)
Eric Andersenc470f442003-07-28 09:56:35 +000013861 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013862static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013863readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000013864{
Denys Vlasenko19358cc2018-08-05 15:42:29 +020013865 struct builtin_read_params params;
Denys Vlasenko73067272010-01-12 22:11:24 +010013866 const char *r;
Eric Andersenc470f442003-07-28 09:56:35 +000013867 int i;
13868
Denys Vlasenko19358cc2018-08-05 15:42:29 +020013869 memset(&params, 0, sizeof(params));
13870
Johannes Schindelin3bef5d82017-08-08 16:46:39 +020013871 while ((i = nextopt("p:u:rt:n:sd:")) != '\0') {
Denis Vlasenkobf0a2012006-12-26 10:42:51 +000013872 switch (i) {
Paul Fox02eb9342005-09-07 16:56:02 +000013873 case 'p':
Denys Vlasenko19358cc2018-08-05 15:42:29 +020013874 params.opt_p = optionarg;
Paul Fox02eb9342005-09-07 16:56:02 +000013875 break;
Paul Fox02eb9342005-09-07 16:56:02 +000013876 case 'n':
Denys Vlasenko19358cc2018-08-05 15:42:29 +020013877 params.opt_n = optionarg;
Paul Fox02eb9342005-09-07 16:56:02 +000013878 break;
13879 case 's':
Denys Vlasenko19358cc2018-08-05 15:42:29 +020013880 params.read_flags |= BUILTIN_READ_SILENT;
Paul Fox02eb9342005-09-07 16:56:02 +000013881 break;
Paul Fox02eb9342005-09-07 16:56:02 +000013882 case 't':
Denys Vlasenko19358cc2018-08-05 15:42:29 +020013883 params.opt_t = optionarg;
Paul Fox02eb9342005-09-07 16:56:02 +000013884 break;
Paul Fox02eb9342005-09-07 16:56:02 +000013885 case 'r':
Denys Vlasenko19358cc2018-08-05 15:42:29 +020013886 params.read_flags |= BUILTIN_READ_RAW;
Paul Fox02eb9342005-09-07 16:56:02 +000013887 break;
Denis Vlasenko59f351c2008-03-25 00:07:12 +000013888 case 'u':
Denys Vlasenko19358cc2018-08-05 15:42:29 +020013889 params.opt_u = optionarg;
Denis Vlasenko59f351c2008-03-25 00:07:12 +000013890 break;
Johannes Schindelin3bef5d82017-08-08 16:46:39 +020013891#if BASH_READ_D
13892 case 'd':
Denys Vlasenko19358cc2018-08-05 15:42:29 +020013893 params.opt_d = optionarg;
Johannes Schindelin3bef5d82017-08-08 16:46:39 +020013894 break;
13895#endif
Paul Fox02eb9342005-09-07 16:56:02 +000013896 default:
13897 break;
13898 }
Eric Andersenc470f442003-07-28 09:56:35 +000013899 }
Paul Fox02eb9342005-09-07 16:56:02 +000013900
Denys Vlasenko19358cc2018-08-05 15:42:29 +020013901 params.argv = argptr;
13902 params.setvar = setvar0;
13903 params.ifs = bltinlookup("IFS"); /* can be NULL */
13904
Denys Vlasenko9e71e3c2012-09-06 13:28:10 +020013905 /* "read -s" needs to save/restore termios, can't allow ^C
13906 * to jump out of it.
13907 */
Denys Vlasenkof5470412017-05-22 19:34:45 +020013908 again:
Denys Vlasenko9e71e3c2012-09-06 13:28:10 +020013909 INT_OFF;
Denys Vlasenko19358cc2018-08-05 15:42:29 +020013910 r = shell_builtin_read(&params);
Denys Vlasenko9e71e3c2012-09-06 13:28:10 +020013911 INT_ON;
Denis Vlasenko46aeab92009-03-31 19:18:17 +000013912
Denys Vlasenkof5470412017-05-22 19:34:45 +020013913 if ((uintptr_t)r == 1 && errno == EINTR) {
Denys Vlasenko49e6bf22017-08-04 14:28:16 +020013914 /* To get SIGCHLD: sleep 1 & read x; echo $x
13915 * Correct behavior is to not exit "read"
13916 */
Denys Vlasenkof5470412017-05-22 19:34:45 +020013917 if (pending_sig == 0)
13918 goto again;
13919 }
13920
Denys Vlasenko73067272010-01-12 22:11:24 +010013921 if ((uintptr_t)r > 1)
13922 ash_msg_and_raise_error(r);
Denis Vlasenko037576d2007-10-20 18:30:38 +000013923
Denys Vlasenko73067272010-01-12 22:11:24 +010013924 return (uintptr_t)r;
Eric Andersenc470f442003-07-28 09:56:35 +000013925}
13926
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013927static int FAST_FUNC
Denys Vlasenko6283f982015-10-07 16:56:20 +020013928umaskcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000013929{
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013930 static const char permuser[3] ALIGN1 = "ogu";
Eric Andersenc470f442003-07-28 09:56:35 +000013931
Eric Andersenc470f442003-07-28 09:56:35 +000013932 mode_t mask;
Eric Andersenc470f442003-07-28 09:56:35 +000013933 int symbolic_mode = 0;
13934
13935 while (nextopt("S") != '\0') {
13936 symbolic_mode = 1;
13937 }
13938
Denis Vlasenkob012b102007-02-19 22:43:01 +000013939 INT_OFF;
Eric Andersenc470f442003-07-28 09:56:35 +000013940 mask = umask(0);
13941 umask(mask);
Denis Vlasenkob012b102007-02-19 22:43:01 +000013942 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +000013943
Denys Vlasenko6283f982015-10-07 16:56:20 +020013944 if (*argptr == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +000013945 if (symbolic_mode) {
Denys Vlasenko005c4922015-10-10 20:17:12 +020013946 char buf[sizeof(",u=rwx,g=rwx,o=rwx")];
Eric Andersenc470f442003-07-28 09:56:35 +000013947 char *p = buf;
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013948 int i;
Eric Andersenc470f442003-07-28 09:56:35 +000013949
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013950 i = 2;
13951 for (;;) {
Denys Vlasenko005c4922015-10-10 20:17:12 +020013952 *p++ = ',';
Eric Andersenc470f442003-07-28 09:56:35 +000013953 *p++ = permuser[i];
13954 *p++ = '=';
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013955 /* mask is 0..0uuugggooo. i=2 selects uuu bits */
Denys Vlasenko005c4922015-10-10 20:17:12 +020013956 if (!(mask & 0400)) *p++ = 'r';
13957 if (!(mask & 0200)) *p++ = 'w';
13958 if (!(mask & 0100)) *p++ = 'x';
13959 mask <<= 3;
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013960 if (--i < 0)
13961 break;
Eric Andersenc470f442003-07-28 09:56:35 +000013962 }
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013963 *p = '\0';
Denys Vlasenko005c4922015-10-10 20:17:12 +020013964 puts(buf + 1);
Eric Andersenc470f442003-07-28 09:56:35 +000013965 } else {
Denys Vlasenkoec046f72015-10-07 17:57:53 +020013966 out1fmt("%04o\n", mask);
Eric Andersenc470f442003-07-28 09:56:35 +000013967 }
13968 } else {
Denys Vlasenko6283f982015-10-07 16:56:20 +020013969 char *modestr = *argptr;
Denys Vlasenko14c85eb2017-10-12 19:40:47 +020013970 /* numeric umasks are taken as-is */
13971 /* symbolic umasks are inverted: "umask a=rx" calls umask(222) */
Denys Vlasenko6283f982015-10-07 16:56:20 +020013972 if (!isdigit(modestr[0]))
13973 mask ^= 0777;
Denys Vlasenko5711a2a2015-10-07 17:55:33 +020013974 mask = bb_parse_mode(modestr, mask);
13975 if ((unsigned)mask > 0777) {
Denys Vlasenko6283f982015-10-07 16:56:20 +020013976 ash_msg_and_raise_error("illegal mode: %s", modestr);
Eric Andersenc470f442003-07-28 09:56:35 +000013977 }
Denys Vlasenko6283f982015-10-07 16:56:20 +020013978 if (!isdigit(modestr[0]))
13979 mask ^= 0777;
13980 umask(mask);
Eric Andersenc470f442003-07-28 09:56:35 +000013981 }
13982 return 0;
13983}
13984
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013985static int FAST_FUNC
Denys Vlasenkof3c742f2010-03-06 20:12:00 +010013986ulimitcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersenc470f442003-07-28 09:56:35 +000013987{
Denys Vlasenkof3c742f2010-03-06 20:12:00 +010013988 return shell_builtin_ulimit(argv);
Eric Andersenc470f442003-07-28 09:56:35 +000013989}
13990
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013991/* ============ main() and helpers */
13992
13993/*
13994 * Called to exit the shell.
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013995 */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013996static void
13997exitshell(void)
13998{
13999 struct jmploc loc;
14000 char *p;
14001 int status;
14002
Denys Vlasenkobede2152011-09-04 16:12:33 +020014003#if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT
14004 save_history(line_input_state);
14005#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000014006 status = exitstatus;
14007 TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
14008 if (setjmp(loc.loc)) {
Denis Vlasenko7f88e342009-03-19 03:36:18 +000014009 if (exception_type == EXEXIT)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000014010 status = exitstatus;
14011 goto out;
14012 }
14013 exception_handler = &loc;
14014 p = trap[0];
14015 if (p) {
14016 trap[0] = NULL;
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020014017 evalskip = 0;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000014018 evalstring(p, 0);
Denys Vlasenkof37e1152016-10-07 03:17:28 +020014019 /*free(p); - we'll exit soon */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000014020 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000014021 out:
Denys Vlasenkof37e1152016-10-07 03:17:28 +020014022 /* dash wraps setjobctl(0) in "if (setjmp(loc.loc) == 0) {...}".
14023 * our setjobctl(0) does not panic if tcsetpgrp fails inside it.
14024 */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000014025 setjobctl(0);
Denys Vlasenkocaee80c2016-10-25 20:49:53 +020014026 flush_stdout_stderr();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000014027 _exit(status);
14028 /* NOTREACHED */
14029}
14030
Denys Vlasenko49e6bf22017-08-04 14:28:16 +020014031/* Don't inline: conserve stack of caller from having our locals too */
14032static NOINLINE void
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +000014033init(void)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014034{
Denys Vlasenko82dd14a2010-05-17 10:10:01 +020014035 /* we will never free this */
14036 basepf.next_to_pgetc = basepf.buf = ckmalloc(IBUFSIZ);
Denys Vlasenko0485b672017-08-14 19:46:56 +020014037 basepf.linno = 1;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014038
Denys Vlasenko49e6bf22017-08-04 14:28:16 +020014039 sigmode[SIGCHLD - 1] = S_DFL; /* ensure we install handler even if it is SIG_IGNed */
Denys Vlasenko458c1f22016-10-27 23:51:19 +020014040 setsignal(SIGCHLD);
14041
Denys Vlasenko7a7b0342009-12-04 04:18:31 +010014042 /* bash re-enables SIGHUP which is SIG_IGNed on entry.
14043 * Try: "trap '' HUP; bash; echo RET" and type "kill -HUP $$"
14044 */
Denys Vlasenkocacb2cd2010-10-05 00:13:02 +020014045 signal(SIGHUP, SIG_DFL);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014046
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014047 {
14048 char **envp;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014049 const char *p;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014050
14051 initvar();
14052 for (envp = environ; envp && *envp; envp++) {
Denys Vlasenko9c143ce2017-11-02 12:56:24 +010014053/* Used to have
14054 * p = endofname(*envp);
14055 * if (p != *envp && *p == '=') {
14056 * here to weed out badly-named variables, but this breaks
14057 * scenarios where people do want them passed to children:
14058 * import os
14059 * os.environ["test-test"]="test"
14060 * if os.fork() == 0:
14061 * os.execv("ash", [ 'ash', '-c', 'eval $(export -p); echo OK' ]) # fixes this
14062 * os.execv("ash", [ 'ash', '-c', 'env | grep test-test' ]) # breaks this
14063 */
14064 if (strchr(*envp, '=')) {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014065 setvareq(*envp, VEXPORT|VTEXTFIXED);
14066 }
14067 }
14068
Denys Vlasenko67dae152018-08-05 13:59:35 +020014069 setvareq((char*)defifsvar, VTEXTFIXED);
Denys Vlasenkoe627ac92016-09-30 14:36:59 +020014070 setvareq((char*)defoptindvar, VTEXTFIXED);
14071
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020014072 setvar0("PPID", utoa(getppid()));
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010014073#if BASH_SHLVL_VAR
Bernhard Reutner-Fischer80f8cdf2013-11-08 14:25:24 +010014074 p = lookupvar("SHLVL");
Denys Vlasenko5680e982014-01-07 16:12:48 +010014075 setvar("SHLVL", utoa((p ? atoi(p) : 0) + 1), VEXPORT);
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010014076#endif
14077#if BASH_HOSTNAME_VAR
Denys Vlasenko3fa97af2014-04-15 11:43:29 +020014078 if (!lookupvar("HOSTNAME")) {
14079 struct utsname uts;
14080 uname(&uts);
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020014081 setvar0("HOSTNAME", uts.nodename);
Denys Vlasenko3fa97af2014-04-15 11:43:29 +020014082 }
Bernhard Reutner-Fischer80f8cdf2013-11-08 14:25:24 +010014083#endif
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014084 p = lookupvar("PWD");
Denys Vlasenkob0b83432011-03-07 12:34:59 +010014085 if (p) {
Denys Vlasenko49e6bf22017-08-04 14:28:16 +020014086 struct stat st1, st2;
Denys Vlasenkoef159702016-09-01 11:16:22 +020014087 if (p[0] != '/' || stat(p, &st1) || stat(".", &st2)
Denys Vlasenkob0b83432011-03-07 12:34:59 +010014088 || st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino
14089 ) {
Denys Vlasenkoef159702016-09-01 11:16:22 +020014090 p = NULL;
Denys Vlasenkob0b83432011-03-07 12:34:59 +010014091 }
14092 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014093 setpwd(p, 0);
14094 }
14095}
14096
Denys Vlasenkob0b83432011-03-07 12:34:59 +010014097
14098//usage:#define ash_trivial_usage
Denys Vlasenkof2ed39b2018-04-05 16:46:49 +020014099//usage: "[-/+OPTIONS] [-/+o OPT]... [-c 'SCRIPT' [ARG0 [ARGS]] / FILE [ARGS] / -s [ARGS]]"
Denys Vlasenkob0b83432011-03-07 12:34:59 +010014100//usage:#define ash_full_usage "\n\n"
14101//usage: "Unix shell interpreter"
14102
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014103/*
14104 * Process the shell command line arguments.
14105 */
Denys Vlasenkoec05df12017-07-31 19:43:47 +020014106static int
Denis Vlasenko68404f12008-03-17 09:00:54 +000014107procargs(char **argv)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014108{
14109 int i;
14110 const char *xminusc;
14111 char **xargv;
Denys Vlasenkoec05df12017-07-31 19:43:47 +020014112 int login_sh;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014113
14114 xargv = argv;
Ron Yorston8767c122018-11-05 13:13:08 +000014115 login_sh = xargv[0] && xargv[0][0] == '-';
Denys Vlasenko4f2ef4a2018-11-01 09:53:25 +010014116#if NUM_SCRIPTS > 0
14117 if (minusc)
14118 goto setarg0;
14119#endif
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014120 arg0 = xargv[0];
Denis Vlasenko68404f12008-03-17 09:00:54 +000014121 /* if (xargv[0]) - mmm, this is always true! */
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014122 xargv++;
Denys Vlasenko4f2ef4a2018-11-01 09:53:25 +010014123 argptr = xargv;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014124 for (i = 0; i < NOPTS; i++)
14125 optlist[i] = 2;
Denys Vlasenkoec05df12017-07-31 19:43:47 +020014126 if (options(/*cmdline:*/ 1, &login_sh)) {
Denis Vlasenko28bf6712008-02-14 15:01:47 +000014127 /* it already printed err message */
14128 raise_exception(EXERROR);
14129 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014130 xargv = argptr;
14131 xminusc = minusc;
14132 if (*xargv == NULL) {
14133 if (xminusc)
14134 ash_msg_and_raise_error(bb_msg_requires_arg, "-c");
14135 sflag = 1;
14136 }
14137 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
14138 iflag = 1;
14139 if (mflag == 2)
14140 mflag = iflag;
14141 for (i = 0; i < NOPTS; i++)
14142 if (optlist[i] == 2)
14143 optlist[i] = 0;
14144#if DEBUG == 2
14145 debug = 1;
14146#endif
Denys Vlasenko5f7c82b2017-02-03 13:00:06 +010014147 /* POSIX 1003.2: first arg after "-c CMD" is $0, remainder $1... */
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014148 if (xminusc) {
14149 minusc = *xargv++;
14150 if (*xargv)
14151 goto setarg0;
14152 } else if (!sflag) {
14153 setinputfile(*xargv, 0);
14154 setarg0:
14155 arg0 = *xargv++;
14156 commandname = arg0;
14157 }
14158
14159 shellparam.p = xargv;
14160#if ENABLE_ASH_GETOPTS
14161 shellparam.optind = 1;
14162 shellparam.optoff = -1;
14163#endif
Denis Vlasenko01631112007-12-16 17:20:38 +000014164 /* assert(shellparam.malloced == 0 && shellparam.nparam == 0); */
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014165 while (*xargv) {
14166 shellparam.nparam++;
14167 xargv++;
14168 }
14169 optschanged();
Denys Vlasenkoec05df12017-07-31 19:43:47 +020014170
14171 return login_sh;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014172}
14173
14174/*
Denys Vlasenko2eb0a7e2016-10-27 11:28:59 +020014175 * Read /etc/profile, ~/.profile, $ENV.
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014176 */
14177static void
14178read_profile(const char *name)
14179{
Denys Vlasenko46999802017-07-29 21:12:29 +020014180 name = expandstr(name, DQSYNTAX);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014181 if (setinputfile(name, INPUT_PUSH_FILE | INPUT_NOFILE_OK) < 0)
14182 return;
Denys Vlasenko0840c912016-10-01 15:27:44 +020014183 cmdloop(0);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014184 popfile();
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014185}
14186
Denis Vlasenko0c032a42007-02-23 01:03:40 +000014187/*
14188 * This routine is called when an error or an interrupt occurs in an
14189 * interactive shell and control is returned to the main command loop.
Denys Vlasenko5ac04f22016-10-27 14:46:50 +020014190 * (In dash, this function is auto-generated by build machinery).
Denis Vlasenko0c032a42007-02-23 01:03:40 +000014191 */
14192static void
14193reset(void)
14194{
14195 /* from eval.c: */
14196 evalskip = 0;
14197 loopnest = 0;
Denys Vlasenko5ac04f22016-10-27 14:46:50 +020014198
14199 /* from expand.c: */
14200 ifsfree();
14201
Denis Vlasenko0c032a42007-02-23 01:03:40 +000014202 /* from input.c: */
Denis Vlasenko41eb3002008-11-28 03:42:31 +000014203 g_parsefile->left_in_buffer = 0;
14204 g_parsefile->left_in_line = 0; /* clear input buffer */
Denis Vlasenko0c032a42007-02-23 01:03:40 +000014205 popallfiles();
Denys Vlasenko5ac04f22016-10-27 14:46:50 +020014206
Denis Vlasenko0c032a42007-02-23 01:03:40 +000014207 /* from redir.c: */
Denys Vlasenko1c79aeb2017-07-29 22:51:52 +020014208 unwindredir(NULL);
Denys Vlasenkob8ab27b2017-07-26 19:22:34 +020014209
14210 /* from var.c: */
Denys Vlasenko484fc202017-07-26 19:55:31 +020014211 unwindlocalvars(NULL);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000014212}
14213
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014214#if PROFILE
14215static short profile_buf[16384];
14216extern int etext();
14217#endif
14218
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000014219/*
14220 * Main routine. We initialize things, parse the arguments, execute
14221 * profiles if we're a login shell, and then call cmdloop to execute
14222 * commands. The setjmp call sets up the location to jump to when an
14223 * exception occurs. When an exception occurs the variable "state"
14224 * is used to figure out how far we had gotten.
14225 */
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +000014226int ash_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Ron Yorston8767c122018-11-05 13:13:08 +000014227#if NUM_SCRIPTS > 0
14228int ash_main(int argc, char **argv)
14229#else
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000014230int ash_main(int argc UNUSED_PARAM, char **argv)
Ron Yorston8767c122018-11-05 13:13:08 +000014231#endif
Denys Vlasenko4f2ef4a2018-11-01 09:53:25 +010014232/* note: 'argc' is used only if embedded scripts are enabled */
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014233{
Denis Vlasenko4e12b1a2008-12-23 23:36:47 +000014234 volatile smallint state;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014235 struct jmploc jmploc;
14236 struct stackmark smark;
Denys Vlasenkoec05df12017-07-31 19:43:47 +020014237 int login_sh;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014238
Denis Vlasenko01631112007-12-16 17:20:38 +000014239 /* Initialize global data */
14240 INIT_G_misc();
14241 INIT_G_memstack();
14242 INIT_G_var();
Denis Vlasenkoee87ebf2007-12-21 22:18:16 +000014243#if ENABLE_ASH_ALIAS
Denis Vlasenko01631112007-12-16 17:20:38 +000014244 INIT_G_alias();
Denis Vlasenkoee87ebf2007-12-21 22:18:16 +000014245#endif
Denis Vlasenko01631112007-12-16 17:20:38 +000014246 INIT_G_cmdtable();
14247
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014248#if PROFILE
14249 monitor(4, etext, profile_buf, sizeof(profile_buf), 50);
14250#endif
14251
14252#if ENABLE_FEATURE_EDITING
14253 line_input_state = new_line_input_t(FOR_SHELL | WITH_PATH_LOOKUP);
14254#endif
14255 state = 0;
14256 if (setjmp(jmploc.loc)) {
Denis Vlasenko7f88e342009-03-19 03:36:18 +000014257 smallint e;
Denis Vlasenko4e12b1a2008-12-23 23:36:47 +000014258 smallint s;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014259
14260 reset();
14261
Denis Vlasenko7f88e342009-03-19 03:36:18 +000014262 e = exception_type;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014263 s = state;
Denys Vlasenkob563f622010-09-25 17:15:13 +020014264 if (e == EXEXIT || s == 0 || iflag == 0 || shlvl) {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014265 exitshell();
Denys Vlasenkob563f622010-09-25 17:15:13 +020014266 }
14267 if (e == EXINT) {
Denys Vlasenko9c541002015-10-07 15:44:36 +020014268 newline_and_flush(stderr);
Denys Vlasenkob563f622010-09-25 17:15:13 +020014269 }
Denis Vlasenko7f88e342009-03-19 03:36:18 +000014270
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014271 popstackmark(&smark);
14272 FORCE_INT_ON; /* enable interrupts */
14273 if (s == 1)
14274 goto state1;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000014275 if (s == 2)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014276 goto state2;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000014277 if (s == 3)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014278 goto state3;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000014279 goto state4;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014280 }
14281 exception_handler = &jmploc;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014282 rootpid = getpid();
14283
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014284 init();
14285 setstackmark(&smark);
Denys Vlasenko4f2ef4a2018-11-01 09:53:25 +010014286
14287#if NUM_SCRIPTS > 0
14288 if (argc < 0)
14289 /* Non-NULL minusc tells procargs that an embedded script is being run */
14290 minusc = get_script_content(-argc - 1);
14291#endif
Denys Vlasenkoec05df12017-07-31 19:43:47 +020014292 login_sh = procargs(argv);
Denys Vlasenko474ed062016-10-30 18:30:29 +010014293#if DEBUG
14294 TRACE(("Shell args: "));
14295 trace_puts_args(argv);
14296#endif
Denis Vlasenko68404f12008-03-17 09:00:54 +000014297
Denys Vlasenkoec05df12017-07-31 19:43:47 +020014298 if (login_sh) {
Stefan Hellermann4ef14392013-03-15 02:45:50 +010014299 const char *hp;
14300
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014301 state = 1;
14302 read_profile("/etc/profile");
14303 state1:
14304 state = 2;
Stefan Hellermann4ef14392013-03-15 02:45:50 +010014305 hp = lookupvar("HOME");
Denys Vlasenko2eb0a7e2016-10-27 11:28:59 +020014306 if (hp)
14307 read_profile("$HOME/.profile");
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014308 }
14309 state2:
14310 state = 3;
14311 if (
14312#ifndef linux
Denis Vlasenko0c032a42007-02-23 01:03:40 +000014313 getuid() == geteuid() && getgid() == getegid() &&
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014314#endif
Denis Vlasenko0c032a42007-02-23 01:03:40 +000014315 iflag
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014316 ) {
Denys Vlasenko2eb0a7e2016-10-27 11:28:59 +020014317 const char *shinit = lookupvar("ENV");
14318 if (shinit != NULL && *shinit != '\0')
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014319 read_profile(shinit);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014320 }
Denys Vlasenko2eb0a7e2016-10-27 11:28:59 +020014321 popstackmark(&smark);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014322 state3:
14323 state = 4;
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000014324 if (minusc) {
14325 /* evalstring pushes parsefile stack.
14326 * Ensure we don't falsely claim that 0 (stdin)
Denis Vlasenko5368ad52009-03-20 10:20:08 +000014327 * is one of stacked source fds.
14328 * Testcase: ash -c 'exec 1>&0' must not complain. */
Denys Vlasenko79b3d422010-06-03 04:29:08 +020014329 // if (!sflag) g_parsefile->pf_fd = -1;
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +020014330 // ^^ not necessary since now we special-case fd 0
Denys Vlasenko035486c2017-07-31 04:09:19 +020014331 // in save_fd_on_redirect()
Denys Vlasenko1e3e2cc2017-07-25 20:31:14 +020014332 evalstring(minusc, sflag ? 0 : EV_EXIT);
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000014333 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014334
14335 if (sflag || minusc == NULL) {
Denys Vlasenko4840ae82011-09-04 15:28:03 +020014336#if MAX_HISTORY > 0 && ENABLE_FEATURE_EDITING_SAVEHISTORY
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +000014337 if (iflag) {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014338 const char *hp = lookupvar("HISTFILE");
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010014339 if (!hp) {
14340 hp = lookupvar("HOME");
Stefan Hellermann4ef14392013-03-15 02:45:50 +010014341 if (hp) {
Denys Vlasenko5f7c82b2017-02-03 13:00:06 +010014342 INT_OFF;
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010014343 hp = concat_path_file(hp, ".ash_history");
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020014344 setvar0("HISTFILE", hp);
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010014345 free((char*)hp);
Denys Vlasenko5f7c82b2017-02-03 13:00:06 +010014346 INT_ON;
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010014347 hp = lookupvar("HISTFILE");
14348 }
14349 }
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000014350 if (hp)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014351 line_input_state->hist_file = hp;
Denys Vlasenko2c4de5b2011-03-31 13:16:52 +020014352# if ENABLE_FEATURE_SH_HISTFILESIZE
14353 hp = lookupvar("HISTFILESIZE");
14354 line_input_state->max_history = size_from_HISTFILESIZE(hp);
14355# endif
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014356 }
14357#endif
14358 state4: /* XXX ??? - why isn't this before the "if" statement */
14359 cmdloop(1);
14360 }
14361#if PROFILE
14362 monitor(0);
14363#endif
14364#ifdef GPROF
14365 {
14366 extern void _mcleanup(void);
14367 _mcleanup();
14368 }
14369#endif
Denys Vlasenkob563f622010-09-25 17:15:13 +020014370 TRACE(("End of main reached\n"));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014371 exitshell();
14372 /* NOTREACHED */
14373}
14374
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014375
Eric Andersendf82f612001-06-28 07:46:40 +000014376/*-
14377 * Copyright (c) 1989, 1991, 1993, 1994
Eric Andersen2870d962001-07-02 17:27:21 +000014378 * The Regents of the University of California. All rights reserved.
Eric Andersendf82f612001-06-28 07:46:40 +000014379 *
14380 * This code is derived from software contributed to Berkeley by
14381 * Kenneth Almquist.
14382 *
14383 * Redistribution and use in source and binary forms, with or without
14384 * modification, are permitted provided that the following conditions
14385 * are met:
14386 * 1. Redistributions of source code must retain the above copyright
14387 * notice, this list of conditions and the following disclaimer.
14388 * 2. Redistributions in binary form must reproduce the above copyright
14389 * notice, this list of conditions and the following disclaimer in the
14390 * documentation and/or other materials provided with the distribution.
"Vladimir N. Oleynik"ddc280e2005-12-15 12:01:49 +000014391 * 3. Neither the name of the University nor the names of its contributors
Eric Andersendf82f612001-06-28 07:46:40 +000014392 * may be used to endorse or promote products derived from this software
14393 * without specific prior written permission.
14394 *
Denys Vlasenko95f79532017-08-02 14:26:33 +020014395 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND
Eric Andersendf82f612001-06-28 07:46:40 +000014396 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
14397 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
14398 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
14399 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
14400 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
14401 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
14402 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
14403 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
14404 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
14405 * SUCH DAMAGE.
14406 */