blob: 4c1b5e409e5416b05a2591cebe4ed0a338ce8676 [file] [log] [blame]
Eric Andersendf82f612001-06-28 07:46:40 +00001/* vi: set sw=4 ts=4: */
2/*
3 * ash shell port for busybox
4 *
Denys Vlasenko73067272010-01-12 22:11:24 +01005 * This code is derived from software contributed to Berkeley by
6 * Kenneth Almquist.
7 *
8 * Original BSD copyright notice is retained at the end of this file.
9 *
Eric Andersendf82f612001-06-28 07:46:40 +000010 * Copyright (c) 1989, 1991, 1993, 1994
Eric Andersen2870d962001-07-02 17:27:21 +000011 * The Regents of the University of California. All rights reserved.
Eric Andersencb57d552001-06-28 07:25:16 +000012 *
"Vladimir N. Oleynik"ddc280e2005-12-15 12:01:49 +000013 * Copyright (c) 1997-2005 Herbert Xu <herbert@gondor.apana.org.au>
Eric Andersen81fe1232003-07-29 06:38:40 +000014 * was re-ported from NetBSD and debianized.
15 *
Denys Vlasenko0ef64bd2010-08-16 20:14:46 +020016 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
Eric Andersencb57d552001-06-28 07:25:16 +000017 */
Denys Vlasenko771f1992010-07-16 14:31:34 +020018//config:config ASH
Denys Vlasenko4eed2c62017-07-18 22:01:24 +020019//config: bool "ash (77 kb)"
Denys Vlasenko771f1992010-07-16 14:31:34 +020020//config: default y
21//config: depends on !NOMMU
22//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +020023//config: The most complete and most pedantically correct shell included with
24//config: busybox. This shell is actually a derivative of the Debian 'dash'
25//config: shell (by Herbert Xu), which was created by porting the 'ash' shell
26//config: (written by Kenneth Almquist) from NetBSD.
Denys Vlasenko771f1992010-07-16 14:31:34 +020027//config:
Kang-Che Sung6cd02942017-01-06 17:02:03 +010028//config:# ash options
29//config:# note: Don't remove !NOMMU part in the next line; it would break
30//config:# menuconfig's indenting.
31//config:if !NOMMU && (ASH || SH_IS_ASH || BASH_IS_ASH)
32//config:
Denys Vlasenko514b51d2016-10-01 14:33:08 +020033//config:config ASH_OPTIMIZE_FOR_SIZE
34//config: bool "Optimize for size instead of speed"
35//config: default y
Denys Vlasenko0b883582016-12-23 16:49:07 +010036//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
Denys Vlasenko514b51d2016-10-01 14:33:08 +020037//config:
38//config:config ASH_INTERNAL_GLOB
39//config: bool "Use internal glob() implementation"
Denys Vlasenko326edc32016-12-22 14:36:49 +010040//config: default y # Y is bigger, but because of uclibc glob() bug, let Y be default for now
Denys Vlasenko0b883582016-12-23 16:49:07 +010041//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
Denys Vlasenko514b51d2016-10-01 14:33:08 +020042//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +020043//config: Do not use glob() function from libc, use internal implementation.
44//config: Use this if you are getting "glob.h: No such file or directory"
45//config: or similar build errors.
46//config: Note that as of now (2017-01), uclibc and musl glob() both have bugs
47//config: which would break ash if you select N here.
Denys Vlasenkof5604222017-01-10 14:58:54 +010048//config:
49//config:config ASH_BASH_COMPAT
50//config: bool "bash-compatible extensions"
51//config: default y
52//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
53//config:
Denys Vlasenko01f7b9e2018-01-26 15:15:43 +010054//config:config ASH_BASH_SOURCE_CURDIR
55//config: bool "'source' and '.' builtins search current directory after $PATH"
56//config: default n # do not encourage non-standard behavior
Denys Vlasenko54c21112018-01-27 20:46:45 +010057//config: depends on ASH_BASH_COMPAT
Denys Vlasenko01f7b9e2018-01-26 15:15:43 +010058//config: help
59//config: This is not compliant with standards. Avoid if possible.
60//config:
William Pitcockd8fd88a2018-01-24 18:33:18 +010061//config:config ASH_BASH_NOT_FOUND_HOOK
62//config: bool "command_not_found_handle hook support"
63//config: default y
Denys Vlasenko54c21112018-01-27 20:46:45 +010064//config: depends on ASH_BASH_COMPAT
William Pitcockd8fd88a2018-01-24 18:33:18 +010065//config: help
66//config: Enable support for the 'command_not_found_handle' hook function,
67//config: from GNU bash, which allows for alternative command not found
68//config: handling.
69//config:
Denys Vlasenkof5604222017-01-10 14:58:54 +010070//config:config ASH_JOB_CONTROL
71//config: bool "Job control"
72//config: default y
73//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
74//config:
75//config:config ASH_ALIAS
76//config: bool "Alias support"
77//config: default y
78//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
Denys Vlasenko514b51d2016-10-01 14:33:08 +020079//config:
80//config:config ASH_RANDOM_SUPPORT
81//config: bool "Pseudorandom generator and $RANDOM variable"
82//config: default y
Denys Vlasenko0b883582016-12-23 16:49:07 +010083//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
Denys Vlasenko514b51d2016-10-01 14:33:08 +020084//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +020085//config: Enable pseudorandom generator and dynamic variable "$RANDOM".
86//config: Each read of "$RANDOM" will generate a new pseudorandom value.
87//config: You can reset the generator by using a specified start value.
88//config: After "unset RANDOM" the generator will switch off and this
89//config: variable will no longer have special treatment.
Denys Vlasenko514b51d2016-10-01 14:33:08 +020090//config:
91//config:config ASH_EXPAND_PRMT
92//config: bool "Expand prompt string"
93//config: default y
Denys Vlasenko0b883582016-12-23 16:49:07 +010094//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
Denys Vlasenko514b51d2016-10-01 14:33:08 +020095//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +020096//config: $PS# may contain volatile content, such as backquote commands.
97//config: This option recreates the prompt string from the environment
98//config: variable each time it is displayed.
Denys Vlasenko514b51d2016-10-01 14:33:08 +020099//config:
Denys Vlasenko046341e2011-02-04 17:53:59 +0100100//config:config ASH_IDLE_TIMEOUT
Denys Vlasenkof5604222017-01-10 14:58:54 +0100101//config: bool "Idle timeout variable $TMOUT"
Denys Vlasenko771f1992010-07-16 14:31:34 +0200102//config: default y
Denys Vlasenko0b883582016-12-23 16:49:07 +0100103//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
Denys Vlasenko771f1992010-07-16 14:31:34 +0200104//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +0200105//config: Enable bash-like auto-logout after $TMOUT seconds of idle time.
Denys Vlasenko771f1992010-07-16 14:31:34 +0200106//config:
Denys Vlasenkof5604222017-01-10 14:58:54 +0100107//config:config ASH_MAIL
108//config: bool "Check for new mail in interactive shell"
Denys Vlasenko771f1992010-07-16 14:31:34 +0200109//config: default y
Denys Vlasenko0b883582016-12-23 16:49:07 +0100110//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
Denys Vlasenko771f1992010-07-16 14:31:34 +0200111//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +0200112//config: Enable "check for new mail" function:
113//config: if set, $MAIL file and $MAILPATH list of files
114//config: are checked for mtime changes, and "you have mail"
115//config: message is printed if change is detected.
Denys Vlasenko771f1992010-07-16 14:31:34 +0200116//config:
Denys Vlasenko265062d2017-01-10 15:13:30 +0100117//config:config ASH_ECHO
Denys Vlasenkof5604222017-01-10 14:58:54 +0100118//config: bool "echo builtin"
Denys Vlasenko771f1992010-07-16 14:31:34 +0200119//config: default y
Denys Vlasenko0b883582016-12-23 16:49:07 +0100120//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
Denys Vlasenko771f1992010-07-16 14:31:34 +0200121//config:
Denys Vlasenko265062d2017-01-10 15:13:30 +0100122//config:config ASH_PRINTF
Denys Vlasenkof5604222017-01-10 14:58:54 +0100123//config: bool "printf builtin"
Denys Vlasenko771f1992010-07-16 14:31:34 +0200124//config: default y
Denys Vlasenko0b883582016-12-23 16:49:07 +0100125//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
Denys Vlasenko771f1992010-07-16 14:31:34 +0200126//config:
Denys Vlasenko265062d2017-01-10 15:13:30 +0100127//config:config ASH_TEST
Denys Vlasenkof5604222017-01-10 14:58:54 +0100128//config: bool "test builtin"
Denys Vlasenko771f1992010-07-16 14:31:34 +0200129//config: default y
Denys Vlasenko0b883582016-12-23 16:49:07 +0100130//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
Denys Vlasenko771f1992010-07-16 14:31:34 +0200131//config:
Denys Vlasenko2ec34962014-09-08 16:52:39 +0200132//config:config ASH_HELP
133//config: bool "help builtin"
134//config: default y
Denys Vlasenko0b883582016-12-23 16:49:07 +0100135//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
Denys Vlasenkof5604222017-01-10 14:58:54 +0100136//config:
137//config:config ASH_GETOPTS
138//config: bool "getopts builtin"
139//config: default y
140//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
Denys Vlasenko2ec34962014-09-08 16:52:39 +0200141//config:
Denys Vlasenko771f1992010-07-16 14:31:34 +0200142//config:config ASH_CMDCMD
Denys Vlasenkof5604222017-01-10 14:58:54 +0100143//config: bool "command builtin"
Denys Vlasenko771f1992010-07-16 14:31:34 +0200144//config: default y
Denys Vlasenko0b883582016-12-23 16:49:07 +0100145//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
Denys Vlasenko771f1992010-07-16 14:31:34 +0200146//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +0200147//config: Enable support for the 'command' builtin, which allows
148//config: you to run the specified command or builtin,
149//config: even when there is a function with the same name.
Kang-Che Sung6cd02942017-01-06 17:02:03 +0100150//config:
151//config:endif # ash options
Denys Vlasenko771f1992010-07-16 14:31:34 +0200152
Denys Vlasenko20704f02011-03-23 17:59:27 +0100153//applet:IF_ASH(APPLET(ash, BB_DIR_BIN, BB_SUID_DROP))
Denys Vlasenko205d48e2017-01-29 14:57:33 +0100154// APPLET_ODDNAME:name main location suid_type help
155//applet:IF_SH_IS_ASH( APPLET_ODDNAME(sh, ash, BB_DIR_BIN, BB_SUID_DROP, ash))
Denys Vlasenko0b883582016-12-23 16:49:07 +0100156//applet:IF_BASH_IS_ASH(APPLET_ODDNAME(bash, ash, BB_DIR_BIN, BB_SUID_DROP, ash))
Denys Vlasenko20704f02011-03-23 17:59:27 +0100157
158//kbuild:lib-$(CONFIG_ASH) += ash.o ash_ptr_hack.o shell_common.o
Denys Vlasenko0b883582016-12-23 16:49:07 +0100159//kbuild:lib-$(CONFIG_SH_IS_ASH) += ash.o ash_ptr_hack.o shell_common.o
160//kbuild:lib-$(CONFIG_BASH_IS_ASH) += ash.o ash_ptr_hack.o shell_common.o
Denys Vlasenko20704f02011-03-23 17:59:27 +0100161//kbuild:lib-$(CONFIG_ASH_RANDOM_SUPPORT) += random.o
162
Denys Vlasenko67047462016-12-22 15:21:58 +0100163/*
Denys Vlasenko7d4aec02017-01-11 14:00:38 +0100164 * DEBUG=1 to compile in debugging ('set -o debug' turns on)
165 * DEBUG=2 to compile in and turn on debugging.
166 * When debugging is on ("set -o debug" was executed, or DEBUG=2),
167 * debugging info is written to ./trace, quit signal generates core dump.
Denys Vlasenko67047462016-12-22 15:21:58 +0100168 */
169#define DEBUG 0
170/* Tweak debug output verbosity here */
171#define DEBUG_TIME 0
172#define DEBUG_PID 1
173#define DEBUG_SIG 1
174#define DEBUG_INTONOFF 0
175
176#define PROFILE 0
177
178#define JOBS ENABLE_ASH_JOB_CONTROL
179
180#include <setjmp.h>
181#include <fnmatch.h>
182#include <sys/times.h>
183#include <sys/utsname.h> /* for setting $HOSTNAME */
Denys Vlasenko67047462016-12-22 15:21:58 +0100184#include "busybox.h" /* for applet_names */
185
Denys Vlasenko7d4aec02017-01-11 14:00:38 +0100186/* So far, all bash compat is controlled by one config option */
187/* Separate defines document which part of code implements what */
188/* function keyword */
189#define BASH_FUNCTION ENABLE_ASH_BASH_COMPAT
190#define IF_BASH_FUNCTION IF_ASH_BASH_COMPAT
191/* &>file */
192#define BASH_REDIR_OUTPUT ENABLE_ASH_BASH_COMPAT
193#define IF_BASH_REDIR_OUTPUT IF_ASH_BASH_COMPAT
194/* $'...' */
195#define BASH_DOLLAR_SQUOTE ENABLE_ASH_BASH_COMPAT
196#define IF_BASH_DOLLAR_SQUOTE IF_ASH_BASH_COMPAT
197#define BASH_PATTERN_SUBST ENABLE_ASH_BASH_COMPAT
198#define IF_BASH_PATTERN_SUBST IF_ASH_BASH_COMPAT
199#define BASH_SUBSTR ENABLE_ASH_BASH_COMPAT
200#define IF_BASH_SUBSTR IF_ASH_BASH_COMPAT
201/* [[ EXPR ]] */
202#define BASH_TEST2 (ENABLE_ASH_BASH_COMPAT * ENABLE_ASH_TEST)
203#define BASH_SOURCE ENABLE_ASH_BASH_COMPAT
204#define BASH_PIPEFAIL ENABLE_ASH_BASH_COMPAT
205#define BASH_HOSTNAME_VAR ENABLE_ASH_BASH_COMPAT
206#define BASH_SHLVL_VAR ENABLE_ASH_BASH_COMPAT
Denys Vlasenkof8cdc7a2017-08-04 15:24:49 +0200207#define BASH_XTRACEFD ENABLE_ASH_BASH_COMPAT
Johannes Schindelin3bef5d82017-08-08 16:46:39 +0200208#define BASH_READ_D ENABLE_ASH_BASH_COMPAT
209#define IF_BASH_READ_D IF_ASH_BASH_COMPAT
Denys Vlasenko7d4aec02017-01-11 14:00:38 +0100210
Denys Vlasenko67047462016-12-22 15:21:58 +0100211#if defined(__ANDROID_API__) && __ANDROID_API__ <= 24
212/* Bionic at least up to version 24 has no glob() */
213# undef ENABLE_ASH_INTERNAL_GLOB
214# define ENABLE_ASH_INTERNAL_GLOB 1
215#endif
216
217#if !ENABLE_ASH_INTERNAL_GLOB && defined(__UCLIBC__)
218# error uClibc glob() is buggy, use ASH_INTERNAL_GLOB.
219# error The bug is: for "$PWD"/<pattern> ash will escape e.g. dashes in "$PWD"
220# error with backslash, even ones which do not need to be: "/a-b" -> "/a\-b"
221# error glob() should unbackslash them and match. uClibc does not unbackslash,
222# error fails to match dirname, subsequently not expanding <pattern> in it.
223// Testcase:
224// if (glob("/etc/polkit\\-1", 0, NULL, &pglob)) - this returns 0 on uclibc, no bug
225// if (glob("/etc/polkit\\-1/*", 0, NULL, &pglob)) printf("uclibc bug!\n");
226#endif
227
228#if !ENABLE_ASH_INTERNAL_GLOB
229# include <glob.h>
230#endif
231
232#include "unicode.h"
233#include "shell_common.h"
Denys Vlasenko0b883582016-12-23 16:49:07 +0100234#if ENABLE_FEATURE_SH_MATH
Denys Vlasenko67047462016-12-22 15:21:58 +0100235# include "math.h"
Denys Vlasenkocf3a7962017-07-26 14:38:19 +0200236#else
237typedef long arith_t;
238# define ARITH_FMT "%ld"
Denys Vlasenko67047462016-12-22 15:21:58 +0100239#endif
240#if ENABLE_ASH_RANDOM_SUPPORT
241# include "random.h"
242#else
243# define CLEAR_RANDOM_T(rnd) ((void)0)
244#endif
245
246#include "NUM_APPLETS.h"
247#if NUM_APPLETS == 1
248/* STANDALONE does not make sense, and won't compile */
249# undef CONFIG_FEATURE_SH_STANDALONE
250# undef ENABLE_FEATURE_SH_STANDALONE
251# undef IF_FEATURE_SH_STANDALONE
252# undef IF_NOT_FEATURE_SH_STANDALONE
253# define ENABLE_FEATURE_SH_STANDALONE 0
254# define IF_FEATURE_SH_STANDALONE(...)
255# define IF_NOT_FEATURE_SH_STANDALONE(...) __VA_ARGS__
256#endif
257
258#ifndef PIPE_BUF
259# define PIPE_BUF 4096 /* amount of buffering in a pipe */
260#endif
261
262#if !BB_MMU
263# error "Do not even bother, ash will not run on NOMMU machine"
264#endif
265
Denys Vlasenko6f9442f2018-01-28 20:41:23 +0100266/* We use a trick to have more optimized code (fewer pointer reloads):
267 * ash.c: extern struct globals *const ash_ptr_to_globals;
268 * ash_ptr_hack.c: struct globals *ash_ptr_to_globals;
269 * This way, compiler in ash.c knows the pointer can not change.
270 *
271 * However, this may break on weird arches or toolchains. In this case,
272 * set "-DBB_GLOBAL_CONST=''" in CONFIG_EXTRA_CFLAGS to disable
273 * this optimization.
274 */
275#ifndef BB_GLOBAL_CONST
276# define BB_GLOBAL_CONST const
277#endif
278
Denis Vlasenkob012b102007-02-19 22:43:01 +0000279
Denis Vlasenko01631112007-12-16 17:20:38 +0000280/* ============ Hash table sizes. Configurable. */
281
282#define VTABSIZE 39
283#define ATABSIZE 39
284#define CMDTABLESIZE 31 /* should be prime */
285
286
Denis Vlasenkob012b102007-02-19 22:43:01 +0000287/* ============ Shell options */
288
289static const char *const optletters_optnames[] = {
290 "e" "errexit",
291 "f" "noglob",
292 "I" "ignoreeof",
293 "i" "interactive",
294 "m" "monitor",
295 "n" "noexec",
296 "s" "stdin",
297 "x" "xtrace",
298 "v" "verbose",
299 "C" "noclobber",
300 "a" "allexport",
301 "b" "notify",
302 "u" "nounset",
Denys Vlasenkoe9ac32a2009-12-05 02:01:25 +0100303 "\0" "vi"
Denys Vlasenko7d4aec02017-01-11 14:00:38 +0100304#if BASH_PIPEFAIL
Denys Vlasenkoe9ac32a2009-12-05 02:01:25 +0100305 ,"\0" "pipefail"
Michael Abbott359da5e2009-12-04 23:03:29 +0100306#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +0000307#if DEBUG
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000308 ,"\0" "nolog"
309 ,"\0" "debug"
Denis Vlasenkob012b102007-02-19 22:43:01 +0000310#endif
311};
312
Denys Vlasenko285ad152009-12-04 23:02:27 +0100313#define optletters(n) optletters_optnames[n][0]
314#define optnames(n) (optletters_optnames[n] + 1)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000315
Denis Vlasenko80b8b392007-06-25 10:55:35 +0000316enum { NOPTS = ARRAY_SIZE(optletters_optnames) };
Denis Vlasenkob012b102007-02-19 22:43:01 +0000317
Eric Andersenc470f442003-07-28 09:56:35 +0000318
Denis Vlasenkob012b102007-02-19 22:43:01 +0000319/* ============ Misc data */
Eric Andersenc470f442003-07-28 09:56:35 +0000320
Denys Vlasenkoea8b2522010-06-02 12:57:26 +0200321#define msg_illnum "Illegal number: %s"
Denis Vlasenkoaa744452007-02-23 01:04:22 +0000322
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +0000323/*
Eric Andersenc470f442003-07-28 09:56:35 +0000324 * We enclose jmp_buf in a structure so that we can declare pointers to
325 * jump locations. The global variable handler contains the location to
Denis Vlasenkof1733952009-03-19 23:21:55 +0000326 * jump to when an exception occurs, and the global variable exception_type
Eric Andersenaff114c2004-04-14 17:51:38 +0000327 * contains a code identifying the exception. To implement nested
Eric Andersenc470f442003-07-28 09:56:35 +0000328 * exception handlers, the user should save the value of handler on entry
329 * to an inner scope, set handler to point to a jmploc structure for the
330 * inner scope, and restore handler on exit from the scope.
331 */
Eric Andersenc470f442003-07-28 09:56:35 +0000332struct jmploc {
333 jmp_buf loc;
334};
Denis Vlasenko01631112007-12-16 17:20:38 +0000335
336struct globals_misc {
Denys Vlasenko4d12e942016-10-01 16:03:11 +0200337 uint8_t exitstatus; /* exit status of last command */
338 uint8_t back_exitstatus;/* exit status of backquoted command */
339 smallint job_warning; /* user was warned about stopped jobs (can be 2, 1 or 0). */
340 int rootpid; /* pid of main shell */
Denis Vlasenko01631112007-12-16 17:20:38 +0000341 /* shell level: 0 for the main shell, 1 for its children, and so on */
342 int shlvl;
343#define rootshell (!shlvl)
Denys Vlasenko675d24a2018-01-27 22:02:05 +0100344 int errlinno;
345
Denis Vlasenko01631112007-12-16 17:20:38 +0000346 char *minusc; /* argument to -c option */
347
348 char *curdir; // = nullstr; /* current working directory */
349 char *physdir; // = nullstr; /* physical working directory */
350
351 char *arg0; /* value of $0 */
352
353 struct jmploc *exception_handler;
Denis Vlasenko991a1da2008-02-10 19:02:53 +0000354
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200355 volatile int suppress_int; /* counter */
356 volatile /*sig_atomic_t*/ smallint pending_int; /* 1 = got SIGINT */
Denys Vlasenko458c1f22016-10-27 23:51:19 +0200357 volatile /*sig_atomic_t*/ smallint got_sigchld; /* 1 = got SIGCHLD */
Denys Vlasenko8f7b0242016-10-28 17:16:11 +0200358 volatile /*sig_atomic_t*/ smallint pending_sig; /* last pending signal */
Denis Vlasenko7f88e342009-03-19 03:36:18 +0000359 smallint exception_type; /* kind of exception (0..5) */
Denis Vlasenko01631112007-12-16 17:20:38 +0000360 /* exceptions */
Eric Andersenc470f442003-07-28 09:56:35 +0000361#define EXINT 0 /* SIGINT received */
362#define EXERROR 1 /* a generic error */
Eric Andersenc470f442003-07-28 09:56:35 +0000363#define EXEXIT 4 /* exit the shell */
Eric Andersen2870d962001-07-02 17:27:21 +0000364
Denis Vlasenkob07a4962008-06-22 13:16:23 +0000365 char nullstr[1]; /* zero length string */
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000366
367 char optlist[NOPTS];
368#define eflag optlist[0]
369#define fflag optlist[1]
370#define Iflag optlist[2]
371#define iflag optlist[3]
372#define mflag optlist[4]
373#define nflag optlist[5]
374#define sflag optlist[6]
375#define xflag optlist[7]
376#define vflag optlist[8]
377#define Cflag optlist[9]
378#define aflag optlist[10]
379#define bflag optlist[11]
380#define uflag optlist[12]
381#define viflag optlist[13]
Denys Vlasenko7d4aec02017-01-11 14:00:38 +0100382#if BASH_PIPEFAIL
Michael Abbott359da5e2009-12-04 23:03:29 +0100383# define pipefail optlist[14]
384#else
385# define pipefail 0
386#endif
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000387#if DEBUG
Denys Vlasenko7d4aec02017-01-11 14:00:38 +0100388# define nolog optlist[14 + BASH_PIPEFAIL]
389# define debug optlist[15 + BASH_PIPEFAIL]
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000390#endif
391
392 /* trap handler commands */
Denis Vlasenko01631112007-12-16 17:20:38 +0000393 /*
394 * Sigmode records the current value of the signal handlers for the various
395 * modes. A value of zero means that the current handler is not known.
Denis Vlasenkof8535cc2008-12-03 10:36:26 +0000396 * S_HARD_IGN indicates that the signal was ignored on entry to the shell.
Denis Vlasenko01631112007-12-16 17:20:38 +0000397 */
398 char sigmode[NSIG - 1];
Denis Vlasenkof8535cc2008-12-03 10:36:26 +0000399#define S_DFL 1 /* default signal handling (SIG_DFL) */
400#define S_CATCH 2 /* signal is caught */
401#define S_IGN 3 /* signal is ignored (SIG_IGN) */
Denys Vlasenko0f14f412017-08-06 20:06:19 +0200402#define S_HARD_IGN 4 /* signal is ignored permanently (it was SIG_IGN on entry to shell) */
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +0000403
Denis Vlasenko01631112007-12-16 17:20:38 +0000404 /* indicates specified signal received */
Denis Vlasenko4b875702009-03-19 13:30:04 +0000405 uint8_t gotsig[NSIG - 1]; /* offset by 1: "signal" 0 is meaningless */
Denys Vlasenko238bf182010-05-18 15:49:07 +0200406 uint8_t may_have_traps; /* 0: definitely no traps are set, 1: some traps may be set */
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000407 char *trap[NSIG];
Denys Vlasenko21d87d42009-09-25 00:06:51 +0200408 char **trap_ptr; /* used only by "trap hack" */
Denis Vlasenko448d30e2008-06-27 00:24:11 +0000409
410 /* Rarely referenced stuff */
411#if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenko3ea2e822009-10-09 20:59:04 +0200412 random_t random_gen;
Denis Vlasenko448d30e2008-06-27 00:24:11 +0000413#endif
414 pid_t backgndpid; /* pid of last background process */
Denis Vlasenko01631112007-12-16 17:20:38 +0000415};
Denys Vlasenko6f9442f2018-01-28 20:41:23 +0100416extern struct globals_misc *BB_GLOBAL_CONST ash_ptr_to_globals_misc;
Denis Vlasenko574f2f42008-02-27 18:41:59 +0000417#define G_misc (*ash_ptr_to_globals_misc)
Denys Vlasenko4d12e942016-10-01 16:03:11 +0200418#define exitstatus (G_misc.exitstatus )
419#define back_exitstatus (G_misc.back_exitstatus )
420#define job_warning (G_misc.job_warning)
Denis Vlasenko26bc57d2008-06-27 00:29:34 +0000421#define rootpid (G_misc.rootpid )
422#define shlvl (G_misc.shlvl )
Denys Vlasenko675d24a2018-01-27 22:02:05 +0100423#define errlinno (G_misc.errlinno )
Denis Vlasenko26bc57d2008-06-27 00:29:34 +0000424#define minusc (G_misc.minusc )
425#define curdir (G_misc.curdir )
426#define physdir (G_misc.physdir )
427#define arg0 (G_misc.arg0 )
Denis Vlasenko01631112007-12-16 17:20:38 +0000428#define exception_handler (G_misc.exception_handler)
Denis Vlasenko7f88e342009-03-19 03:36:18 +0000429#define exception_type (G_misc.exception_type )
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200430#define suppress_int (G_misc.suppress_int )
431#define pending_int (G_misc.pending_int )
Denys Vlasenko458c1f22016-10-27 23:51:19 +0200432#define got_sigchld (G_misc.got_sigchld )
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200433#define pending_sig (G_misc.pending_sig )
Denis Vlasenko26bc57d2008-06-27 00:29:34 +0000434#define nullstr (G_misc.nullstr )
435#define optlist (G_misc.optlist )
436#define sigmode (G_misc.sigmode )
437#define gotsig (G_misc.gotsig )
Denys Vlasenko238bf182010-05-18 15:49:07 +0200438#define may_have_traps (G_misc.may_have_traps )
Denis Vlasenko26bc57d2008-06-27 00:29:34 +0000439#define trap (G_misc.trap )
Denys Vlasenko21d87d42009-09-25 00:06:51 +0200440#define trap_ptr (G_misc.trap_ptr )
Denys Vlasenko3ea2e822009-10-09 20:59:04 +0200441#define random_gen (G_misc.random_gen )
Denis Vlasenko448d30e2008-06-27 00:24:11 +0000442#define backgndpid (G_misc.backgndpid )
Denis Vlasenko01631112007-12-16 17:20:38 +0000443#define INIT_G_misc() do { \
Denis Vlasenko574f2f42008-02-27 18:41:59 +0000444 (*(struct globals_misc**)&ash_ptr_to_globals_misc) = xzalloc(sizeof(G_misc)); \
445 barrier(); \
Denis Vlasenko01631112007-12-16 17:20:38 +0000446 curdir = nullstr; \
447 physdir = nullstr; \
Denys Vlasenko21d87d42009-09-25 00:06:51 +0200448 trap_ptr = trap; \
Denis Vlasenko01631112007-12-16 17:20:38 +0000449} while (0)
450
451
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000452/* ============ DEBUG */
453#if DEBUG
454static void trace_printf(const char *fmt, ...);
455static void trace_vprintf(const char *fmt, va_list va);
456# define TRACE(param) trace_printf param
457# define TRACEV(param) trace_vprintf param
Denis Vlasenko1bb3d7e2009-03-20 07:45:36 +0000458# define close(fd) do { \
459 int dfd = (fd); \
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +0000460 if (close(dfd) < 0) \
Denys Vlasenko883cea42009-07-11 15:31:59 +0200461 bb_error_msg("bug on %d: closing %d(0x%x)", \
Denis Vlasenko1bb3d7e2009-03-20 07:45:36 +0000462 __LINE__, dfd, dfd); \
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +0000463} while (0)
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000464#else
465# define TRACE(param)
466# define TRACEV(param)
467#endif
468
469
Denis Vlasenko559691a2008-10-05 18:39:31 +0000470/* ============ Utility functions */
Denys Vlasenko1961aea2013-02-26 00:36:53 +0100471#define is_name(c) ((c) == '_' || isalpha((unsigned char)(c)))
472#define is_in_name(c) ((c) == '_' || isalnum((unsigned char)(c)))
473
Denys Vlasenko37dc08b2016-10-02 04:38:07 +0200474static int
475isdigit_str9(const char *str)
Denis Vlasenko559691a2008-10-05 18:39:31 +0000476{
477 int maxlen = 9 + 1; /* max 9 digits: 999999999 */
478 while (--maxlen && isdigit(*str))
479 str++;
480 return (*str == '\0');
481}
Denis Vlasenko01631112007-12-16 17:20:38 +0000482
Denys Vlasenko37dc08b2016-10-02 04:38:07 +0200483static const char *
484var_end(const char *var)
Denys Vlasenko8837c5d2010-06-02 12:56:18 +0200485{
486 while (*var)
487 if (*var++ == '=')
488 break;
489 return var;
490}
491
Denis Vlasenko559691a2008-10-05 18:39:31 +0000492
493/* ============ Interrupts / exceptions */
Denys Vlasenko66c5b122011-02-08 05:07:02 +0100494
495static void exitshell(void) NORETURN;
496
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +0000497/*
Eric Andersen2870d962001-07-02 17:27:21 +0000498 * These macros allow the user to suspend the handling of interrupt signals
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +0000499 * over a period of time. This is similar to SIGHOLD or to sigblock, but
Eric Andersen2870d962001-07-02 17:27:21 +0000500 * much more efficient and portable. (But hacking the kernel is so much
501 * more fun than worrying about efficiency and portability. :-))
502 */
Denys Vlasenko06b11492016-11-04 16:43:18 +0100503#if DEBUG_INTONOFF
504# define INT_OFF do { \
505 TRACE(("%s:%d INT_OFF(%d)\n", __func__, __LINE__, suppress_int)); \
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200506 suppress_int++; \
Denys Vlasenkode892052016-10-02 01:49:13 +0200507 barrier(); \
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000508} while (0)
Denys Vlasenko06b11492016-11-04 16:43:18 +0100509#else
510# define INT_OFF do { \
511 suppress_int++; \
512 barrier(); \
513} while (0)
514#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +0000515
516/*
517 * Called to raise an exception. Since C doesn't include exceptions, we
518 * just do a longjmp to the exception handler. The type of exception is
Denis Vlasenko4b875702009-03-19 13:30:04 +0000519 * stored in the global variable "exception_type".
Denis Vlasenkob012b102007-02-19 22:43:01 +0000520 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000521static void raise_exception(int) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +0000522static void
523raise_exception(int e)
524{
525#if DEBUG
Denis Vlasenko2da584f2007-02-19 22:44:05 +0000526 if (exception_handler == NULL)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000527 abort();
528#endif
529 INT_OFF;
Denis Vlasenko7f88e342009-03-19 03:36:18 +0000530 exception_type = e;
Denis Vlasenko2da584f2007-02-19 22:44:05 +0000531 longjmp(exception_handler->loc, 1);
Denis Vlasenkob012b102007-02-19 22:43:01 +0000532}
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000533#if DEBUG
534#define raise_exception(e) do { \
535 TRACE(("raising exception %d on line %d\n", (e), __LINE__)); \
536 raise_exception(e); \
537} while (0)
538#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +0000539
540/*
Denys Vlasenkof37e1152016-10-07 03:17:28 +0200541 * Called when a SIGINT is received. (If the user specifies
Denis Vlasenkob012b102007-02-19 22:43:01 +0000542 * that SIGINT is to be trapped or ignored using the trap builtin, then
543 * this routine is not called.) Suppressint is nonzero when interrupts
544 * are held using the INT_OFF macro. (The test for iflag is just
545 * defensive programming.)
546 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000547static void raise_interrupt(void) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +0000548static void
549raise_interrupt(void)
550{
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200551 pending_int = 0;
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +0000552 /* Signal is not automatically unmasked after it is raised,
553 * do it ourself - unmask all signals */
Denis Vlasenko3f165fa2008-03-17 08:29:08 +0000554 sigprocmask_allsigs(SIG_UNBLOCK);
Denys Vlasenko238bf182010-05-18 15:49:07 +0200555 /* pending_sig = 0; - now done in signal_handler() */
Denis Vlasenko7c139b42007-03-21 20:17:27 +0000556
Denys Vlasenkoc0663c72016-10-27 21:09:01 +0200557 if (!(rootshell && iflag)) {
558 /* Kill ourself with SIGINT */
559 signal(SIGINT, SIG_DFL);
560 raise(SIGINT);
Denis Vlasenkob012b102007-02-19 22:43:01 +0000561 }
Denys Vlasenko4d12e942016-10-01 16:03:11 +0200562 /* bash: ^C even on empty command line sets $? */
563 exitstatus = SIGINT + 128;
Denys Vlasenkoc0663c72016-10-27 21:09:01 +0200564 raise_exception(EXINT);
Denis Vlasenkob012b102007-02-19 22:43:01 +0000565 /* NOTREACHED */
566}
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000567#if DEBUG
568#define raise_interrupt() do { \
569 TRACE(("raising interrupt on line %d\n", __LINE__)); \
570 raise_interrupt(); \
571} while (0)
572#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +0000573
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000574static IF_ASH_OPTIMIZE_FOR_SIZE(inline) void
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000575int_on(void)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000576{
Denys Vlasenkode892052016-10-02 01:49:13 +0200577 barrier();
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200578 if (--suppress_int == 0 && pending_int) {
Denis Vlasenkob012b102007-02-19 22:43:01 +0000579 raise_interrupt();
580 }
581}
Denys Vlasenko06b11492016-11-04 16:43:18 +0100582#if DEBUG_INTONOFF
583# define INT_ON do { \
584 TRACE(("%s:%d INT_ON(%d)\n", __func__, __LINE__, suppress_int-1)); \
585 int_on(); \
586} while (0)
587#else
588# define INT_ON int_on()
589#endif
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000590static IF_ASH_OPTIMIZE_FOR_SIZE(inline) void
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000591force_int_on(void)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000592{
Denys Vlasenkode892052016-10-02 01:49:13 +0200593 barrier();
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200594 suppress_int = 0;
595 if (pending_int)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000596 raise_interrupt();
597}
598#define FORCE_INT_ON force_int_on()
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000599
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200600#define SAVE_INT(v) ((v) = suppress_int)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000601
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000602#define RESTORE_INT(v) do { \
Denys Vlasenkode892052016-10-02 01:49:13 +0200603 barrier(); \
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200604 suppress_int = (v); \
605 if (suppress_int == 0 && pending_int) \
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000606 raise_interrupt(); \
607} while (0)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000608
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000609
Denis Vlasenkobc54cff2007-02-23 01:05:52 +0000610/* ============ Stdout/stderr output */
Eric Andersenc470f442003-07-28 09:56:35 +0000611
Eric Andersenc470f442003-07-28 09:56:35 +0000612static void
Denis Vlasenkob012b102007-02-19 22:43:01 +0000613outstr(const char *p, FILE *file)
Denis Vlasenkoe5570da2007-02-19 22:41:55 +0000614{
Denis Vlasenkob012b102007-02-19 22:43:01 +0000615 INT_OFF;
616 fputs(p, file);
617 INT_ON;
618}
619
620static void
621flush_stdout_stderr(void)
622{
623 INT_OFF;
Denys Vlasenko8131eea2009-11-02 14:19:51 +0100624 fflush_all();
Denis Vlasenkob012b102007-02-19 22:43:01 +0000625 INT_ON;
626}
627
Denys Vlasenko9c541002015-10-07 15:44:36 +0200628/* Was called outcslow(c,FILE*), but c was always '\n' */
Denis Vlasenkob012b102007-02-19 22:43:01 +0000629static void
Denys Vlasenko9c541002015-10-07 15:44:36 +0200630newline_and_flush(FILE *dest)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000631{
632 INT_OFF;
Denys Vlasenko9c541002015-10-07 15:44:36 +0200633 putc('\n', dest);
Denis Vlasenkob012b102007-02-19 22:43:01 +0000634 fflush(dest);
635 INT_ON;
636}
637
638static int out1fmt(const char *, ...) __attribute__((__format__(__printf__,1,2)));
639static int
640out1fmt(const char *fmt, ...)
641{
642 va_list ap;
643 int r;
644
645 INT_OFF;
646 va_start(ap, fmt);
647 r = vprintf(fmt, ap);
648 va_end(ap);
649 INT_ON;
650 return r;
651}
652
653static int fmtstr(char *, size_t, const char *, ...) __attribute__((__format__(__printf__,3,4)));
654static int
655fmtstr(char *outbuf, size_t length, const char *fmt, ...)
656{
657 va_list ap;
658 int ret;
659
Denis Vlasenkob012b102007-02-19 22:43:01 +0000660 INT_OFF;
Denys Vlasenkocf3a7962017-07-26 14:38:19 +0200661 va_start(ap, fmt);
Denis Vlasenkob012b102007-02-19 22:43:01 +0000662 ret = vsnprintf(outbuf, length, fmt, ap);
663 va_end(ap);
664 INT_ON;
665 return ret;
666}
667
668static void
669out1str(const char *p)
670{
671 outstr(p, stdout);
672}
673
674static void
675out2str(const char *p)
676{
677 outstr(p, stderr);
Denys Vlasenko8131eea2009-11-02 14:19:51 +0100678 flush_stdout_stderr();
Denis Vlasenkob012b102007-02-19 22:43:01 +0000679}
680
681
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +0000682/* ============ Parser structures */
Denis Vlasenko4d2183b2007-02-23 01:05:38 +0000683
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000684/* control characters in argument strings */
Denys Vlasenko2ce42e92009-11-29 02:18:13 +0100685#define CTL_FIRST CTLESC
Denys Vlasenkob6c84342009-08-29 20:23:20 +0200686#define CTLESC ((unsigned char)'\201') /* escape next character */
687#define CTLVAR ((unsigned char)'\202') /* variable defn */
688#define CTLENDVAR ((unsigned char)'\203')
689#define CTLBACKQ ((unsigned char)'\204')
Denys Vlasenkob6c84342009-08-29 20:23:20 +0200690#define CTLARI ((unsigned char)'\206') /* arithmetic expression */
691#define CTLENDARI ((unsigned char)'\207')
692#define CTLQUOTEMARK ((unsigned char)'\210')
Denys Vlasenko2ce42e92009-11-29 02:18:13 +0100693#define CTL_LAST CTLQUOTEMARK
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000694
695/* variable substitution byte (follows CTLVAR) */
696#define VSTYPE 0x0f /* type of variable substitution */
697#define VSNUL 0x10 /* colon--treat the empty string as unset */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000698
699/* values of VSTYPE field */
Denis Vlasenko92e13c22008-03-25 01:17:40 +0000700#define VSNORMAL 0x1 /* normal variable: $var or ${var} */
701#define VSMINUS 0x2 /* ${var-text} */
702#define VSPLUS 0x3 /* ${var+text} */
703#define VSQUESTION 0x4 /* ${var?message} */
704#define VSASSIGN 0x5 /* ${var=text} */
705#define VSTRIMRIGHT 0x6 /* ${var%pattern} */
706#define VSTRIMRIGHTMAX 0x7 /* ${var%%pattern} */
707#define VSTRIMLEFT 0x8 /* ${var#pattern} */
708#define VSTRIMLEFTMAX 0x9 /* ${var##pattern} */
709#define VSLENGTH 0xa /* ${#var} */
Denys Vlasenko7d4aec02017-01-11 14:00:38 +0100710#if BASH_SUBSTR
Denis Vlasenko92e13c22008-03-25 01:17:40 +0000711#define VSSUBSTR 0xc /* ${var:position:length} */
Denys Vlasenko7d4aec02017-01-11 14:00:38 +0100712#endif
713#if BASH_PATTERN_SUBST
Denis Vlasenko92e13c22008-03-25 01:17:40 +0000714#define VSREPLACE 0xd /* ${var/pattern/replacement} */
715#define VSREPLACEALL 0xe /* ${var//pattern/replacement} */
716#endif
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000717
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000718static const char dolatstr[] ALIGN1 = {
Ron Yorston549deab2015-05-18 09:57:51 +0200719 CTLQUOTEMARK, CTLVAR, VSNORMAL, '@', '=', CTLQUOTEMARK, '\0'
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000720};
Ron Yorston549deab2015-05-18 09:57:51 +0200721#define DOLATSTRLEN 6
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +0000722
Denis Vlasenko559691a2008-10-05 18:39:31 +0000723#define NCMD 0
724#define NPIPE 1
725#define NREDIR 2
726#define NBACKGND 3
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000727#define NSUBSHELL 4
Denis Vlasenko559691a2008-10-05 18:39:31 +0000728#define NAND 5
729#define NOR 6
730#define NSEMI 7
731#define NIF 8
732#define NWHILE 9
733#define NUNTIL 10
734#define NFOR 11
735#define NCASE 12
736#define NCLIST 13
737#define NDEFUN 14
738#define NARG 15
739#define NTO 16
Denys Vlasenko7d4aec02017-01-11 14:00:38 +0100740#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +0000741#define NTO2 17
742#endif
743#define NCLOBBER 18
744#define NFROM 19
745#define NFROMTO 20
746#define NAPPEND 21
747#define NTOFD 22
748#define NFROMFD 23
749#define NHERE 24
750#define NXHERE 25
751#define NNOT 26
Denis Vlasenko340299a2008-11-21 10:36:36 +0000752#define N_NUMBER 27
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000753
754union node;
755
756struct ncmd {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000757 smallint type; /* Nxxxx */
Denys Vlasenko675d24a2018-01-27 22:02:05 +0100758 int linno;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000759 union node *assign;
760 union node *args;
761 union node *redirect;
762};
763
764struct npipe {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000765 smallint type;
766 smallint pipe_backgnd;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000767 struct nodelist *cmdlist;
768};
769
770struct nredir {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000771 smallint type;
Denys Vlasenko675d24a2018-01-27 22:02:05 +0100772 int linno;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000773 union node *n;
774 union node *redirect;
775};
776
777struct nbinary {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000778 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000779 union node *ch1;
780 union node *ch2;
781};
782
783struct nif {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000784 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000785 union node *test;
786 union node *ifpart;
787 union node *elsepart;
788};
789
790struct nfor {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000791 smallint type;
Denys Vlasenko675d24a2018-01-27 22:02:05 +0100792 int linno;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000793 union node *args;
794 union node *body;
795 char *var;
796};
797
798struct ncase {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000799 smallint type;
Denys Vlasenko675d24a2018-01-27 22:02:05 +0100800 int linno;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000801 union node *expr;
802 union node *cases;
803};
804
805struct nclist {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000806 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000807 union node *next;
808 union node *pattern;
809 union node *body;
810};
811
Denys Vlasenko675d24a2018-01-27 22:02:05 +0100812struct ndefun {
813 smallint type;
814 int linno;
815 char *text;
816 union node *body;
817};
818
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000819struct narg {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000820 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000821 union node *next;
822 char *text;
823 struct nodelist *backquote;
824};
825
Denis Vlasenko559691a2008-10-05 18:39:31 +0000826/* nfile and ndup layout must match!
827 * NTOFD (>&fdnum) uses ndup structure, but we may discover mid-flight
828 * that it is actually NTO2 (>&file), and change its type.
829 */
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000830struct nfile {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000831 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000832 union node *next;
833 int fd;
Denis Vlasenko559691a2008-10-05 18:39:31 +0000834 int _unused_dupfd;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000835 union node *fname;
836 char *expfname;
837};
838
839struct ndup {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000840 smallint type;
Denis Vlasenko559691a2008-10-05 18:39:31 +0000841 union node *next;
842 int fd;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000843 int dupfd;
844 union node *vname;
Denis Vlasenko559691a2008-10-05 18:39:31 +0000845 char *_unused_expfname;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000846};
847
848struct nhere {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000849 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000850 union node *next;
851 int fd;
852 union node *doc;
853};
854
855struct nnot {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000856 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000857 union node *com;
858};
859
860union node {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000861 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000862 struct ncmd ncmd;
863 struct npipe npipe;
864 struct nredir nredir;
865 struct nbinary nbinary;
866 struct nif nif;
867 struct nfor nfor;
868 struct ncase ncase;
869 struct nclist nclist;
Denys Vlasenko675d24a2018-01-27 22:02:05 +0100870 struct ndefun ndefun;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000871 struct narg narg;
872 struct nfile nfile;
873 struct ndup ndup;
874 struct nhere nhere;
875 struct nnot nnot;
876};
877
Denys Vlasenko86e83ec2009-07-23 22:07:07 +0200878/*
879 * NODE_EOF is returned by parsecmd when it encounters an end of file.
880 * It must be distinct from NULL.
881 */
882#define NODE_EOF ((union node *) -1L)
883
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000884struct nodelist {
885 struct nodelist *next;
886 union node *n;
887};
888
889struct funcnode {
890 int count;
891 union node n;
892};
893
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000894/*
895 * Free a parse tree.
896 */
897static void
898freefunc(struct funcnode *f)
899{
900 if (f && --f->count < 0)
901 free(f);
902}
903
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000904
905/* ============ Debugging output */
906
907#if DEBUG
908
909static FILE *tracefile;
910
911static void
912trace_printf(const char *fmt, ...)
913{
914 va_list va;
915
916 if (debug != 1)
917 return;
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000918 if (DEBUG_TIME)
919 fprintf(tracefile, "%u ", (int) time(NULL));
920 if (DEBUG_PID)
921 fprintf(tracefile, "[%u] ", (int) getpid());
922 if (DEBUG_SIG)
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200923 fprintf(tracefile, "pending s:%d i:%d(supp:%d) ", pending_sig, pending_int, suppress_int);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000924 va_start(va, fmt);
925 vfprintf(tracefile, fmt, va);
926 va_end(va);
927}
928
929static void
930trace_vprintf(const char *fmt, va_list va)
931{
932 if (debug != 1)
933 return;
934 vfprintf(tracefile, fmt, va);
Denys Vlasenko474ed062016-10-30 18:30:29 +0100935 fprintf(tracefile, "\n");
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000936}
937
938static void
939trace_puts(const char *s)
940{
941 if (debug != 1)
942 return;
943 fputs(s, tracefile);
944}
945
946static void
947trace_puts_quoted(char *s)
948{
949 char *p;
950 char c;
951
952 if (debug != 1)
953 return;
954 putc('"', tracefile);
955 for (p = s; *p; p++) {
Denys Vlasenkocd716832009-11-28 22:14:02 +0100956 switch ((unsigned char)*p) {
957 case '\n': c = 'n'; goto backslash;
958 case '\t': c = 't'; goto backslash;
959 case '\r': c = 'r'; goto backslash;
960 case '\"': c = '\"'; goto backslash;
961 case '\\': c = '\\'; goto backslash;
962 case CTLESC: c = 'e'; goto backslash;
963 case CTLVAR: c = 'v'; goto backslash;
Denys Vlasenkocd716832009-11-28 22:14:02 +0100964 case CTLBACKQ: c = 'q'; goto backslash;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000965 backslash:
966 putc('\\', tracefile);
967 putc(c, tracefile);
968 break;
969 default:
970 if (*p >= ' ' && *p <= '~')
971 putc(*p, tracefile);
972 else {
973 putc('\\', tracefile);
Denys Vlasenkocd716832009-11-28 22:14:02 +0100974 putc((*p >> 6) & 03, tracefile);
975 putc((*p >> 3) & 07, tracefile);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000976 putc(*p & 07, tracefile);
977 }
978 break;
979 }
980 }
981 putc('"', tracefile);
982}
983
984static void
985trace_puts_args(char **ap)
986{
987 if (debug != 1)
988 return;
989 if (!*ap)
990 return;
991 while (1) {
992 trace_puts_quoted(*ap);
993 if (!*++ap) {
994 putc('\n', tracefile);
995 break;
996 }
997 putc(' ', tracefile);
998 }
999}
1000
1001static void
1002opentrace(void)
1003{
1004 char s[100];
1005#ifdef O_APPEND
1006 int flags;
1007#endif
1008
1009 if (debug != 1) {
1010 if (tracefile)
1011 fflush(tracefile);
1012 /* leave open because libedit might be using it */
1013 return;
1014 }
1015 strcpy(s, "./trace");
1016 if (tracefile) {
1017 if (!freopen(s, "a", tracefile)) {
1018 fprintf(stderr, "Can't re-open %s\n", s);
1019 debug = 0;
1020 return;
1021 }
1022 } else {
1023 tracefile = fopen(s, "a");
1024 if (tracefile == NULL) {
1025 fprintf(stderr, "Can't open %s\n", s);
1026 debug = 0;
1027 return;
1028 }
1029 }
1030#ifdef O_APPEND
Denis Vlasenkod37f2222007-08-19 13:42:08 +00001031 flags = fcntl(fileno(tracefile), F_GETFL);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001032 if (flags >= 0)
1033 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
1034#endif
1035 setlinebuf(tracefile);
1036 fputs("\nTracing started.\n", tracefile);
1037}
1038
1039static void
1040indent(int amount, char *pfx, FILE *fp)
1041{
1042 int i;
1043
1044 for (i = 0; i < amount; i++) {
1045 if (pfx && i == amount - 1)
1046 fputs(pfx, fp);
1047 putc('\t', fp);
1048 }
1049}
1050
1051/* little circular references here... */
1052static void shtree(union node *n, int ind, char *pfx, FILE *fp);
1053
1054static void
1055sharg(union node *arg, FILE *fp)
1056{
1057 char *p;
1058 struct nodelist *bqlist;
Denys Vlasenkocd716832009-11-28 22:14:02 +01001059 unsigned char subtype;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001060
1061 if (arg->type != NARG) {
1062 out1fmt("<node type %d>\n", arg->type);
1063 abort();
1064 }
1065 bqlist = arg->narg.backquote;
1066 for (p = arg->narg.text; *p; p++) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01001067 switch ((unsigned char)*p) {
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001068 case CTLESC:
Dan Fandrich77d48722010-09-07 23:38:28 -07001069 p++;
1070 putc(*p, fp);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001071 break;
1072 case CTLVAR:
1073 putc('$', fp);
1074 putc('{', fp);
1075 subtype = *++p;
1076 if (subtype == VSLENGTH)
1077 putc('#', fp);
1078
Dan Fandrich77d48722010-09-07 23:38:28 -07001079 while (*p != '=') {
1080 putc(*p, fp);
1081 p++;
1082 }
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001083
1084 if (subtype & VSNUL)
1085 putc(':', fp);
1086
1087 switch (subtype & VSTYPE) {
1088 case VSNORMAL:
1089 putc('}', fp);
1090 break;
1091 case VSMINUS:
1092 putc('-', fp);
1093 break;
1094 case VSPLUS:
1095 putc('+', fp);
1096 break;
1097 case VSQUESTION:
1098 putc('?', fp);
1099 break;
1100 case VSASSIGN:
1101 putc('=', fp);
1102 break;
1103 case VSTRIMLEFT:
1104 putc('#', fp);
1105 break;
1106 case VSTRIMLEFTMAX:
1107 putc('#', fp);
1108 putc('#', fp);
1109 break;
1110 case VSTRIMRIGHT:
1111 putc('%', fp);
1112 break;
1113 case VSTRIMRIGHTMAX:
1114 putc('%', fp);
1115 putc('%', fp);
1116 break;
1117 case VSLENGTH:
1118 break;
1119 default:
1120 out1fmt("<subtype %d>", subtype);
1121 }
1122 break;
1123 case CTLENDVAR:
1124 putc('}', fp);
1125 break;
1126 case CTLBACKQ:
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001127 putc('$', fp);
1128 putc('(', fp);
1129 shtree(bqlist->n, -1, NULL, fp);
1130 putc(')', fp);
1131 break;
1132 default:
1133 putc(*p, fp);
1134 break;
1135 }
1136 }
1137}
1138
Denys Vlasenko641dd7b2009-06-11 19:30:19 +02001139static void
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001140shcmd(union node *cmd, FILE *fp)
1141{
1142 union node *np;
1143 int first;
1144 const char *s;
1145 int dftfd;
1146
1147 first = 1;
1148 for (np = cmd->ncmd.args; np; np = np->narg.next) {
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001149 if (!first)
1150 putc(' ', fp);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001151 sharg(np, fp);
1152 first = 0;
1153 }
1154 for (np = cmd->ncmd.redirect; np; np = np->nfile.next) {
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001155 if (!first)
1156 putc(' ', fp);
1157 dftfd = 0;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001158 switch (np->nfile.type) {
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001159 case NTO: s = ">>"+1; dftfd = 1; break;
1160 case NCLOBBER: s = ">|"; dftfd = 1; break;
1161 case NAPPEND: s = ">>"; dftfd = 1; break;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01001162#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00001163 case NTO2:
1164#endif
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001165 case NTOFD: s = ">&"; dftfd = 1; break;
Denis Vlasenko559691a2008-10-05 18:39:31 +00001166 case NFROM: s = "<"; break;
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001167 case NFROMFD: s = "<&"; break;
1168 case NFROMTO: s = "<>"; break;
1169 default: s = "*error*"; break;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001170 }
1171 if (np->nfile.fd != dftfd)
1172 fprintf(fp, "%d", np->nfile.fd);
1173 fputs(s, fp);
1174 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
1175 fprintf(fp, "%d", np->ndup.dupfd);
1176 } else {
1177 sharg(np->nfile.fname, fp);
1178 }
1179 first = 0;
1180 }
1181}
1182
1183static void
1184shtree(union node *n, int ind, char *pfx, FILE *fp)
1185{
1186 struct nodelist *lp;
1187 const char *s;
1188
1189 if (n == NULL)
1190 return;
1191
1192 indent(ind, pfx, fp);
Denys Vlasenko86e83ec2009-07-23 22:07:07 +02001193
1194 if (n == NODE_EOF) {
1195 fputs("<EOF>", fp);
1196 return;
1197 }
1198
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001199 switch (n->type) {
1200 case NSEMI:
1201 s = "; ";
1202 goto binop;
1203 case NAND:
1204 s = " && ";
1205 goto binop;
1206 case NOR:
1207 s = " || ";
1208 binop:
1209 shtree(n->nbinary.ch1, ind, NULL, fp);
1210 /* if (ind < 0) */
1211 fputs(s, fp);
1212 shtree(n->nbinary.ch2, ind, NULL, fp);
1213 break;
1214 case NCMD:
1215 shcmd(n, fp);
1216 if (ind >= 0)
1217 putc('\n', fp);
1218 break;
1219 case NPIPE:
1220 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
Denys Vlasenko7cee00e2009-07-24 01:08:03 +02001221 shtree(lp->n, 0, NULL, fp);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001222 if (lp->next)
1223 fputs(" | ", fp);
1224 }
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00001225 if (n->npipe.pipe_backgnd)
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001226 fputs(" &", fp);
1227 if (ind >= 0)
1228 putc('\n', fp);
1229 break;
1230 default:
1231 fprintf(fp, "<node type %d>", n->type);
1232 if (ind >= 0)
1233 putc('\n', fp);
1234 break;
1235 }
1236}
1237
1238static void
1239showtree(union node *n)
1240{
1241 trace_puts("showtree called\n");
Denys Vlasenko883cea42009-07-11 15:31:59 +02001242 shtree(n, 1, NULL, stderr);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001243}
1244
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001245#endif /* DEBUG */
1246
1247
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00001248/* ============ Parser data */
1249
1250/*
Denis Vlasenkob012b102007-02-19 22:43:01 +00001251 * ash_vmsg() needs parsefile->fd, hence parsefile definition is moved up.
1252 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001253struct strlist {
1254 struct strlist *next;
1255 char *text;
1256};
1257
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001258struct alias;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001259
Denis Vlasenkob012b102007-02-19 22:43:01 +00001260struct strpush {
1261 struct strpush *prev; /* preceding string on stack */
Denis Vlasenko41eb3002008-11-28 03:42:31 +00001262 char *prev_string;
1263 int prev_left_in_line;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001264#if ENABLE_ASH_ALIAS
1265 struct alias *ap; /* if push was associated with an alias */
1266#endif
1267 char *string; /* remember the string since it may change */
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02001268
1269 /* Remember last two characters for pungetc. */
1270 int lastc[2];
1271
1272 /* Number of outstanding calls to pungetc. */
1273 int unget;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001274};
1275
Denys Vlasenko0485b672017-08-14 19:46:56 +02001276/*
1277 * The parsefile structure pointed to by the global variable parsefile
1278 * contains information about the current file being read.
1279 */
Denis Vlasenkob012b102007-02-19 22:43:01 +00001280struct parsefile {
1281 struct parsefile *prev; /* preceding file on stack */
1282 int linno; /* current line */
Denys Vlasenko79b3d422010-06-03 04:29:08 +02001283 int pf_fd; /* file descriptor (or -1 if string) */
Denis Vlasenko41eb3002008-11-28 03:42:31 +00001284 int left_in_line; /* number of chars left in this line */
1285 int left_in_buffer; /* number of chars left in this buffer past the line */
1286 char *next_to_pgetc; /* next char in buffer */
Denis Vlasenkob012b102007-02-19 22:43:01 +00001287 char *buf; /* input buffer */
1288 struct strpush *strpush; /* for pushing strings at this level */
1289 struct strpush basestrpush; /* so pushing one is fast */
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02001290
1291 /* Remember last two characters for pungetc. */
1292 int lastc[2];
1293
1294 /* Number of outstanding calls to pungetc. */
1295 int unget;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001296};
1297
Denis Vlasenko448d30e2008-06-27 00:24:11 +00001298static struct parsefile basepf; /* top level input file */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00001299static struct parsefile *g_parsefile = &basepf; /* current input file */
Denis Vlasenkob012b102007-02-19 22:43:01 +00001300static char *commandname; /* currently executing command */
Denis Vlasenkob012b102007-02-19 22:43:01 +00001301
1302
1303/* ============ Message printing */
1304
1305static void
1306ash_vmsg(const char *msg, va_list ap)
1307{
1308 fprintf(stderr, "%s: ", arg0);
1309 if (commandname) {
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00001310 if (strcmp(arg0, commandname))
1311 fprintf(stderr, "%s: ", commandname);
Denys Vlasenko79b3d422010-06-03 04:29:08 +02001312 if (!iflag || g_parsefile->pf_fd > 0)
Denys Vlasenko675d24a2018-01-27 22:02:05 +01001313 fprintf(stderr, "line %d: ", errlinno);
Eric Andersenc470f442003-07-28 09:56:35 +00001314 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00001315 vfprintf(stderr, msg, ap);
Denys Vlasenko9c541002015-10-07 15:44:36 +02001316 newline_and_flush(stderr);
Eric Andersenc470f442003-07-28 09:56:35 +00001317}
Denis Vlasenkob012b102007-02-19 22:43:01 +00001318
1319/*
1320 * Exverror is called to raise the error exception. If the second argument
1321 * is not NULL then error prints an error message using printf style
1322 * formatting. It then raises the error exception.
1323 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00001324static void ash_vmsg_and_raise(int, const char *, va_list) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001325static void
1326ash_vmsg_and_raise(int cond, const char *msg, va_list ap)
Eric Andersenc470f442003-07-28 09:56:35 +00001327{
Denis Vlasenkob012b102007-02-19 22:43:01 +00001328#if DEBUG
1329 if (msg) {
Denys Vlasenko474ed062016-10-30 18:30:29 +01001330 TRACE(("ash_vmsg_and_raise(%d):", cond));
Denis Vlasenkob012b102007-02-19 22:43:01 +00001331 TRACEV((msg, ap));
Denis Vlasenkob012b102007-02-19 22:43:01 +00001332 } else
Denys Vlasenko474ed062016-10-30 18:30:29 +01001333 TRACE(("ash_vmsg_and_raise(%d):NULL\n", cond));
Denis Vlasenkob012b102007-02-19 22:43:01 +00001334 if (msg)
1335#endif
1336 ash_vmsg(msg, ap);
1337
1338 flush_stdout_stderr();
1339 raise_exception(cond);
1340 /* NOTREACHED */
Eric Andersenc470f442003-07-28 09:56:35 +00001341}
Denis Vlasenkob012b102007-02-19 22:43:01 +00001342
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00001343static void ash_msg_and_raise_error(const char *, ...) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001344static void
1345ash_msg_and_raise_error(const char *msg, ...)
1346{
1347 va_list ap;
1348
Ron Yorstonea7d2f62017-01-03 11:18:23 +01001349 exitstatus = 2;
1350
Denis Vlasenkob012b102007-02-19 22:43:01 +00001351 va_start(ap, msg);
1352 ash_vmsg_and_raise(EXERROR, msg, ap);
1353 /* NOTREACHED */
1354 va_end(ap);
1355}
1356
Ron Yorstonbe366e52017-07-27 13:53:39 +01001357/*
Ron Yorstonbe366e52017-07-27 13:53:39 +01001358 * 'fmt' must be a string literal.
1359 */
Denys Vlasenko6f97b302017-09-29 18:17:25 +02001360#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 +01001361
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00001362static void raise_error_syntax(const char *) NORETURN;
1363static void
1364raise_error_syntax(const char *msg)
1365{
Denys Vlasenko675d24a2018-01-27 22:02:05 +01001366 errlinno = g_parsefile->linno;
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00001367 ash_msg_and_raise_error("syntax error: %s", msg);
1368 /* NOTREACHED */
1369}
1370
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00001371static void ash_msg_and_raise(int, const char *, ...) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001372static void
1373ash_msg_and_raise(int cond, const char *msg, ...)
1374{
1375 va_list ap;
1376
1377 va_start(ap, msg);
1378 ash_vmsg_and_raise(cond, msg, ap);
1379 /* NOTREACHED */
1380 va_end(ap);
1381}
1382
1383/*
1384 * error/warning routines for external builtins
1385 */
1386static void
1387ash_msg(const char *fmt, ...)
1388{
1389 va_list ap;
1390
1391 va_start(ap, fmt);
1392 ash_vmsg(fmt, ap);
1393 va_end(ap);
1394}
1395
1396/*
1397 * Return a string describing an error. The returned string may be a
1398 * pointer to a static buffer that will be overwritten on the next call.
1399 * Action describes the operation that got the error.
1400 */
1401static const char *
1402errmsg(int e, const char *em)
1403{
1404 if (e == ENOENT || e == ENOTDIR) {
1405 return em;
1406 }
1407 return strerror(e);
1408}
1409
1410
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001411/* ============ Memory allocation */
1412
Denys Vlasenkoe7670ff2009-10-11 00:45:25 +02001413#if 0
1414/* I consider these wrappers nearly useless:
1415 * ok, they return you to nearest exception handler, but
1416 * how much memory do you leak in the process, making
1417 * memory starvation worse?
1418 */
1419static void *
1420ckrealloc(void * p, size_t nbytes)
1421{
1422 p = realloc(p, nbytes);
1423 if (!p)
1424 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1425 return p;
1426}
1427
1428static void *
1429ckmalloc(size_t nbytes)
1430{
1431 return ckrealloc(NULL, nbytes);
1432}
1433
1434static void *
1435ckzalloc(size_t nbytes)
1436{
1437 return memset(ckmalloc(nbytes), 0, nbytes);
1438}
1439
1440static char *
1441ckstrdup(const char *s)
1442{
1443 char *p = strdup(s);
1444 if (!p)
1445 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1446 return p;
1447}
1448#else
1449/* Using bbox equivalents. They exit if out of memory */
1450# define ckrealloc xrealloc
1451# define ckmalloc xmalloc
1452# define ckzalloc xzalloc
1453# define ckstrdup xstrdup
1454#endif
1455
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001456/*
1457 * It appears that grabstackstr() will barf with such alignments
1458 * because stalloc() will return a string allocated in a new stackblock.
1459 */
1460#define SHELL_ALIGN(nbytes) (((nbytes) + SHELL_SIZE) & ~SHELL_SIZE)
1461enum {
1462 /* Most machines require the value returned from malloc to be aligned
1463 * in some way. The following macro will get this right
1464 * on many machines. */
Denys Vlasenko0e5e4ea2009-10-11 00:36:20 +02001465 SHELL_SIZE = sizeof(union { int i; char *cp; double d; }) - 1,
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001466 /* Minimum size of a block */
Denis Vlasenko01631112007-12-16 17:20:38 +00001467 MINSIZE = SHELL_ALIGN(504),
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001468};
1469
1470struct stack_block {
1471 struct stack_block *prev;
1472 char space[MINSIZE];
1473};
1474
1475struct stackmark {
1476 struct stack_block *stackp;
1477 char *stacknxt;
1478 size_t stacknleft;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001479};
1480
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001481
Denis Vlasenko01631112007-12-16 17:20:38 +00001482struct globals_memstack {
1483 struct stack_block *g_stackp; // = &stackbase;
Denis Vlasenko01631112007-12-16 17:20:38 +00001484 char *g_stacknxt; // = stackbase.space;
1485 char *sstrend; // = stackbase.space + MINSIZE;
1486 size_t g_stacknleft; // = MINSIZE;
Denis Vlasenko01631112007-12-16 17:20:38 +00001487 struct stack_block stackbase;
1488};
Denys Vlasenko6f9442f2018-01-28 20:41:23 +01001489extern struct globals_memstack *BB_GLOBAL_CONST ash_ptr_to_globals_memstack;
Denis Vlasenko574f2f42008-02-27 18:41:59 +00001490#define G_memstack (*ash_ptr_to_globals_memstack)
Denis Vlasenko01631112007-12-16 17:20:38 +00001491#define g_stackp (G_memstack.g_stackp )
Denis Vlasenko01631112007-12-16 17:20:38 +00001492#define g_stacknxt (G_memstack.g_stacknxt )
1493#define sstrend (G_memstack.sstrend )
1494#define g_stacknleft (G_memstack.g_stacknleft)
Denis Vlasenko01631112007-12-16 17:20:38 +00001495#define stackbase (G_memstack.stackbase )
1496#define INIT_G_memstack() do { \
Denis Vlasenko574f2f42008-02-27 18:41:59 +00001497 (*(struct globals_memstack**)&ash_ptr_to_globals_memstack) = xzalloc(sizeof(G_memstack)); \
1498 barrier(); \
Denis Vlasenko01631112007-12-16 17:20:38 +00001499 g_stackp = &stackbase; \
1500 g_stacknxt = stackbase.space; \
1501 g_stacknleft = MINSIZE; \
1502 sstrend = stackbase.space + MINSIZE; \
Denis Vlasenko01631112007-12-16 17:20:38 +00001503} while (0)
1504
Denys Vlasenkoe7670ff2009-10-11 00:45:25 +02001505
Denis Vlasenko01631112007-12-16 17:20:38 +00001506#define stackblock() ((void *)g_stacknxt)
1507#define stackblocksize() g_stacknleft
1508
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001509/*
1510 * Parse trees for commands are allocated in lifo order, so we use a stack
1511 * to make this more efficient, and also to avoid all sorts of exception
1512 * handling code to handle interrupts in the middle of a parse.
1513 *
1514 * The size 504 was chosen because the Ultrix malloc handles that size
1515 * well.
1516 */
1517static void *
1518stalloc(size_t nbytes)
1519{
1520 char *p;
1521 size_t aligned;
1522
1523 aligned = SHELL_ALIGN(nbytes);
Denis Vlasenko01631112007-12-16 17:20:38 +00001524 if (aligned > g_stacknleft) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001525 size_t len;
1526 size_t blocksize;
1527 struct stack_block *sp;
1528
1529 blocksize = aligned;
1530 if (blocksize < MINSIZE)
1531 blocksize = MINSIZE;
1532 len = sizeof(struct stack_block) - MINSIZE + blocksize;
1533 if (len < blocksize)
1534 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1535 INT_OFF;
1536 sp = ckmalloc(len);
Denis Vlasenko01631112007-12-16 17:20:38 +00001537 sp->prev = g_stackp;
1538 g_stacknxt = sp->space;
1539 g_stacknleft = blocksize;
1540 sstrend = g_stacknxt + blocksize;
1541 g_stackp = sp;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001542 INT_ON;
1543 }
Denis Vlasenko01631112007-12-16 17:20:38 +00001544 p = g_stacknxt;
1545 g_stacknxt += aligned;
1546 g_stacknleft -= aligned;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001547 return p;
1548}
1549
Denis Vlasenko597906c2008-02-20 16:38:54 +00001550static void *
1551stzalloc(size_t nbytes)
1552{
1553 return memset(stalloc(nbytes), 0, nbytes);
1554}
1555
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001556static void
1557stunalloc(void *p)
1558{
1559#if DEBUG
Denis Vlasenko01631112007-12-16 17:20:38 +00001560 if (!p || (g_stacknxt < (char *)p) || ((char *)p < g_stackp->space)) {
Bernhard Reutner-Fischer5e25ddb2008-05-19 09:48:17 +00001561 write(STDERR_FILENO, "stunalloc\n", 10);
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001562 abort();
1563 }
1564#endif
Denis Vlasenko01631112007-12-16 17:20:38 +00001565 g_stacknleft += g_stacknxt - (char *)p;
1566 g_stacknxt = p;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001567}
1568
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001569/*
1570 * Like strdup but works with the ash stack.
1571 */
1572static char *
Denys Vlasenko8e2bc472016-09-28 23:02:57 +02001573sstrdup(const char *p)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001574{
1575 size_t len = strlen(p) + 1;
1576 return memcpy(stalloc(len), p, len);
1577}
1578
Denys Vlasenko03c36e02018-01-10 15:18:35 +01001579static ALWAYS_INLINE void
Denys Vlasenko60ca8342016-09-30 11:21:21 +02001580grabstackblock(size_t len)
1581{
Denys Vlasenkoa318bba2016-10-26 18:26:27 +02001582 stalloc(len);
Denys Vlasenko60ca8342016-09-30 11:21:21 +02001583}
1584
1585static void
1586pushstackmark(struct stackmark *mark, size_t len)
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001587{
Denis Vlasenko01631112007-12-16 17:20:38 +00001588 mark->stackp = g_stackp;
1589 mark->stacknxt = g_stacknxt;
1590 mark->stacknleft = g_stacknleft;
Denys Vlasenko60ca8342016-09-30 11:21:21 +02001591 grabstackblock(len);
1592}
1593
1594static void
1595setstackmark(struct stackmark *mark)
1596{
1597 pushstackmark(mark, g_stacknxt == g_stackp->space && g_stackp != &stackbase);
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001598}
1599
1600static void
1601popstackmark(struct stackmark *mark)
1602{
1603 struct stack_block *sp;
1604
Denis Vlasenko93ebd4f2007-03-13 20:55:36 +00001605 if (!mark->stackp)
1606 return;
1607
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001608 INT_OFF;
Denis Vlasenko01631112007-12-16 17:20:38 +00001609 while (g_stackp != mark->stackp) {
1610 sp = g_stackp;
1611 g_stackp = sp->prev;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001612 free(sp);
1613 }
Denis Vlasenko01631112007-12-16 17:20:38 +00001614 g_stacknxt = mark->stacknxt;
1615 g_stacknleft = mark->stacknleft;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001616 sstrend = mark->stacknxt + mark->stacknleft;
1617 INT_ON;
1618}
1619
1620/*
1621 * When the parser reads in a string, it wants to stick the string on the
1622 * stack and only adjust the stack pointer when it knows how big the
1623 * string is. Stackblock (defined in stack.h) returns a pointer to a block
1624 * of space on top of the stack and stackblocklen returns the length of
1625 * this block. Growstackblock will grow this space by at least one byte,
1626 * possibly moving it (like realloc). Grabstackblock actually allocates the
1627 * part of the block that has been used.
1628 */
1629static void
1630growstackblock(void)
1631{
1632 size_t newlen;
1633
Denis Vlasenko01631112007-12-16 17:20:38 +00001634 newlen = g_stacknleft * 2;
1635 if (newlen < g_stacknleft)
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001636 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1637 if (newlen < 128)
1638 newlen += 128;
1639
Denis Vlasenko01631112007-12-16 17:20:38 +00001640 if (g_stacknxt == g_stackp->space && g_stackp != &stackbase) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001641 struct stack_block *sp;
1642 struct stack_block *prevstackp;
1643 size_t grosslen;
1644
1645 INT_OFF;
Denis Vlasenko01631112007-12-16 17:20:38 +00001646 sp = g_stackp;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001647 prevstackp = sp->prev;
1648 grosslen = newlen + sizeof(struct stack_block) - MINSIZE;
1649 sp = ckrealloc(sp, grosslen);
1650 sp->prev = prevstackp;
Denis Vlasenko01631112007-12-16 17:20:38 +00001651 g_stackp = sp;
1652 g_stacknxt = sp->space;
1653 g_stacknleft = newlen;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001654 sstrend = sp->space + newlen;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001655 INT_ON;
1656 } else {
Denis Vlasenko01631112007-12-16 17:20:38 +00001657 char *oldspace = g_stacknxt;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001658 size_t oldlen = g_stacknleft;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001659 char *p = stalloc(newlen);
1660
1661 /* free the space we just allocated */
Denis Vlasenko01631112007-12-16 17:20:38 +00001662 g_stacknxt = memcpy(p, oldspace, oldlen);
1663 g_stacknleft += newlen;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001664 }
1665}
1666
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001667/*
1668 * The following routines are somewhat easier to use than the above.
1669 * The user declares a variable of type STACKSTR, which may be declared
1670 * to be a register. The macro STARTSTACKSTR initializes things. Then
1671 * the user uses the macro STPUTC to add characters to the string. In
1672 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
1673 * grown as necessary. When the user is done, she can just leave the
1674 * string there and refer to it using stackblock(). Or she can allocate
1675 * the space for it using grabstackstr(). If it is necessary to allow
1676 * someone else to use the stack temporarily and then continue to grow
1677 * the string, the user should use grabstack to allocate the space, and
1678 * then call ungrabstr(p) to return to the previous mode of operation.
1679 *
1680 * USTPUTC is like STPUTC except that it doesn't check for overflow.
1681 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
1682 * is space for at least one character.
1683 */
1684static void *
1685growstackstr(void)
1686{
1687 size_t len = stackblocksize();
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001688 growstackblock();
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001689 return (char *)stackblock() + len;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001690}
1691
1692/*
1693 * Called from CHECKSTRSPACE.
1694 */
1695static char *
1696makestrspace(size_t newlen, char *p)
1697{
Denis Vlasenko01631112007-12-16 17:20:38 +00001698 size_t len = p - g_stacknxt;
Denys Vlasenko53d6e032016-09-30 11:24:12 +02001699 size_t size;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001700
1701 for (;;) {
1702 size_t nleft;
1703
1704 size = stackblocksize();
1705 nleft = size - len;
1706 if (nleft >= newlen)
1707 break;
1708 growstackblock();
1709 }
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001710 return (char *)stackblock() + len;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001711}
1712
1713static char *
1714stack_nputstr(const char *s, size_t n, char *p)
1715{
1716 p = makestrspace(n, p);
Denys Vlasenko5ace96a2017-07-23 21:46:02 +02001717 p = (char *)mempcpy(p, s, n);
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001718 return p;
1719}
1720
1721static char *
1722stack_putstr(const char *s, char *p)
1723{
1724 return stack_nputstr(s, strlen(s), p);
1725}
1726
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001727static char *
1728_STPUTC(int c, char *p)
1729{
1730 if (p == sstrend)
1731 p = growstackstr();
1732 *p++ = c;
1733 return p;
1734}
1735
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00001736#define STARTSTACKSTR(p) ((p) = stackblock())
1737#define STPUTC(c, p) ((p) = _STPUTC((c), (p)))
Denis Vlasenko843cbd52008-06-27 00:23:18 +00001738#define CHECKSTRSPACE(n, p) do { \
1739 char *q = (p); \
1740 size_t l = (n); \
1741 size_t m = sstrend - q; \
1742 if (l > m) \
1743 (p) = makestrspace(l, q); \
1744} while (0)
Denis Vlasenkoef527f52008-06-23 01:52:30 +00001745#define USTPUTC(c, p) (*(p)++ = (c))
Denis Vlasenko843cbd52008-06-27 00:23:18 +00001746#define STACKSTRNUL(p) do { \
1747 if ((p) == sstrend) \
1748 (p) = growstackstr(); \
1749 *(p) = '\0'; \
1750} while (0)
Denis Vlasenkoef527f52008-06-23 01:52:30 +00001751#define STUNPUTC(p) (--(p))
1752#define STTOPC(p) ((p)[-1])
1753#define STADJUST(amount, p) ((p) += (amount))
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001754
1755#define grabstackstr(p) stalloc((char *)(p) - (char *)stackblock())
Denis Vlasenkoef527f52008-06-23 01:52:30 +00001756#define ungrabstackstr(s, p) stunalloc(s)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001757#define stackstrend() ((void *)sstrend)
1758
1759
1760/* ============ String helpers */
1761
1762/*
1763 * prefix -- see if pfx is a prefix of string.
1764 */
1765static char *
1766prefix(const char *string, const char *pfx)
1767{
1768 while (*pfx) {
1769 if (*pfx++ != *string++)
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00001770 return NULL;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001771 }
1772 return (char *) string;
1773}
1774
1775/*
1776 * Check for a valid number. This should be elsewhere.
1777 */
1778static int
1779is_number(const char *p)
1780{
1781 do {
1782 if (!isdigit(*p))
1783 return 0;
1784 } while (*++p != '\0');
1785 return 1;
1786}
1787
1788/*
1789 * Convert a string of digits to an integer, printing an error message on
1790 * failure.
1791 */
1792static int
1793number(const char *s)
1794{
1795 if (!is_number(s))
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02001796 ash_msg_and_raise_error(msg_illnum, s);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001797 return atoi(s);
1798}
1799
1800/*
Denys Vlasenko42ba7572017-07-21 13:20:14 +02001801 * Produce a single quoted string suitable as input to the shell.
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001802 * The return string is allocated on the stack.
1803 */
1804static char *
1805single_quote(const char *s)
1806{
1807 char *p;
1808
1809 STARTSTACKSTR(p);
1810
1811 do {
1812 char *q;
1813 size_t len;
1814
1815 len = strchrnul(s, '\'') - s;
1816
1817 q = p = makestrspace(len + 3, p);
1818
1819 *q++ = '\'';
Denys Vlasenko94af83e2017-07-23 21:55:40 +02001820 q = (char *)mempcpy(q, s, len);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001821 *q++ = '\'';
1822 s += len;
1823
1824 STADJUST(q - p, p);
1825
Denys Vlasenkocd716832009-11-28 22:14:02 +01001826 if (*s != '\'')
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001827 break;
Denys Vlasenkocd716832009-11-28 22:14:02 +01001828 len = 0;
1829 do len++; while (*++s == '\'');
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001830
1831 q = p = makestrspace(len + 3, p);
1832
1833 *q++ = '"';
Denys Vlasenko5ace96a2017-07-23 21:46:02 +02001834 q = (char *)mempcpy(q, s - len, len);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001835 *q++ = '"';
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001836
1837 STADJUST(q - p, p);
1838 } while (*s);
1839
Denys Vlasenkocd716832009-11-28 22:14:02 +01001840 USTPUTC('\0', p);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001841
1842 return stackblock();
1843}
1844
Denys Vlasenko42ba7572017-07-21 13:20:14 +02001845/*
1846 * Produce a possibly single quoted string suitable as input to the shell.
Denys Vlasenko42ba7572017-07-21 13:20:14 +02001847 * If quoting was done, the return string is allocated on the stack,
1848 * otherwise a pointer to the original string is returned.
1849 */
1850static const char *
1851maybe_single_quote(const char *s)
1852{
1853 const char *p = s;
1854
1855 while (*p) {
1856 /* Assuming ACSII */
1857 /* quote ctrl_chars space !"#$%&'()* */
1858 if (*p < '+')
1859 goto need_quoting;
1860 /* quote ;<=>? */
1861 if (*p >= ';' && *p <= '?')
1862 goto need_quoting;
1863 /* quote `[\ */
1864 if (*p == '`')
1865 goto need_quoting;
1866 if (*p == '[')
1867 goto need_quoting;
1868 if (*p == '\\')
1869 goto need_quoting;
1870 /* quote {|}~ DEL and high bytes */
1871 if (*p > 'z')
1872 goto need_quoting;
1873 /* Not quoting these: +,-./ 0-9 :@ A-Z ]^_ a-z */
1874 /* TODO: maybe avoid quoting % */
1875 p++;
1876 }
1877 return s;
1878
1879 need_quoting:
1880 return single_quote(s);
1881}
1882
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001883
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00001884/* ============ nextopt */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001885
1886static char **argptr; /* argument list for builtin commands */
1887static char *optionarg; /* set by nextopt (like getopt) */
1888static char *optptr; /* used by nextopt */
1889
1890/*
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001891 * XXX - should get rid of. Have all builtins use getopt(3).
1892 * The library getopt must have the BSD extension static variable
1893 * "optreset", otherwise it can't be used within the shell safely.
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001894 *
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001895 * Standard option processing (a la getopt) for builtin routines.
1896 * The only argument that is passed to nextopt is the option string;
1897 * the other arguments are unnecessary. It returns the character,
1898 * or '\0' on end of input.
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001899 */
1900static int
1901nextopt(const char *optstring)
1902{
1903 char *p;
1904 const char *q;
1905 char c;
1906
1907 p = optptr;
1908 if (p == NULL || *p == '\0') {
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001909 /* We ate entire "-param", take next one */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001910 p = *argptr;
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001911 if (p == NULL)
1912 return '\0';
1913 if (*p != '-')
1914 return '\0';
1915 if (*++p == '\0') /* just "-" ? */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001916 return '\0';
1917 argptr++;
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001918 if (LONE_DASH(p)) /* "--" ? */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001919 return '\0';
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001920 /* p => next "-param" */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001921 }
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001922 /* p => some option char in the middle of a "-param" */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001923 c = *p++;
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +00001924 for (q = optstring; *q != c;) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001925 if (*q == '\0')
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00001926 ash_msg_and_raise_error("illegal option -%c", c);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001927 if (*++q == ':')
1928 q++;
1929 }
1930 if (*++q == ':') {
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001931 if (*p == '\0') {
1932 p = *argptr++;
1933 if (p == NULL)
1934 ash_msg_and_raise_error("no arg for -%c option", c);
1935 }
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001936 optionarg = p;
1937 p = NULL;
1938 }
1939 optptr = p;
1940 return c;
1941}
1942
1943
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00001944/* ============ Shell variables */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001945
Denis Vlasenko01631112007-12-16 17:20:38 +00001946struct shparam {
1947 int nparam; /* # of positional parameters (without $0) */
1948#if ENABLE_ASH_GETOPTS
1949 int optind; /* next parameter to be processed by getopts */
1950 int optoff; /* used by getopts */
1951#endif
1952 unsigned char malloced; /* if parameter list dynamically allocated */
1953 char **p; /* parameter list */
1954};
1955
1956/*
1957 * Free the list of positional parameters.
1958 */
1959static void
1960freeparam(volatile struct shparam *param)
1961{
Denis Vlasenko01631112007-12-16 17:20:38 +00001962 if (param->malloced) {
Denis Vlasenko3177ba02008-07-13 20:39:23 +00001963 char **ap, **ap1;
1964 ap = ap1 = param->p;
1965 while (*ap)
1966 free(*ap++);
1967 free(ap1);
Denis Vlasenko01631112007-12-16 17:20:38 +00001968 }
1969}
1970
1971#if ENABLE_ASH_GETOPTS
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02001972static void FAST_FUNC getoptsreset(const char *value);
Denis Vlasenko01631112007-12-16 17:20:38 +00001973#endif
1974
1975struct var {
1976 struct var *next; /* next entry in hash list */
1977 int flags; /* flags are defined above */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001978 const char *var_text; /* name=value */
1979 void (*var_func)(const char *) FAST_FUNC; /* function to be called when */
Denis Vlasenko01631112007-12-16 17:20:38 +00001980 /* the variable gets set/unset */
1981};
1982
1983struct localvar {
1984 struct localvar *next; /* next local variable in list */
1985 struct var *vp; /* the variable that was made local */
1986 int flags; /* saved flags */
1987 const char *text; /* saved text */
1988};
1989
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001990/* flags */
1991#define VEXPORT 0x01 /* variable is exported */
1992#define VREADONLY 0x02 /* variable cannot be modified */
1993#define VSTRFIXED 0x04 /* variable struct is statically allocated */
1994#define VTEXTFIXED 0x08 /* text is statically allocated */
1995#define VSTACK 0x10 /* text is allocated on the stack */
1996#define VUNSET 0x20 /* the variable is not set */
1997#define VNOFUNC 0x40 /* don't call the callback function */
1998#define VNOSET 0x80 /* do not set variable - just readonly test */
1999#define VNOSAVE 0x100 /* when text is on the heap before setvareq */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00002000#if ENABLE_ASH_RANDOM_SUPPORT
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00002001# define VDYNAMIC 0x200 /* dynamic variable */
2002#else
2003# define VDYNAMIC 0
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002004#endif
2005
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00002006
Denis Vlasenko01631112007-12-16 17:20:38 +00002007/* Need to be before varinit_data[] */
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00002008#if ENABLE_LOCALE_SUPPORT
Denys Vlasenko2634bf32009-06-09 18:40:07 +02002009static void FAST_FUNC
Denis Vlasenkoa8915072007-02-23 21:10:06 +00002010change_lc_all(const char *value)
2011{
2012 if (value && *value != '\0')
2013 setlocale(LC_ALL, value);
2014}
Denys Vlasenko2634bf32009-06-09 18:40:07 +02002015static void FAST_FUNC
Denis Vlasenkoa8915072007-02-23 21:10:06 +00002016change_lc_ctype(const char *value)
2017{
2018 if (value && *value != '\0')
2019 setlocale(LC_CTYPE, value);
2020}
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00002021#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002022#if ENABLE_ASH_MAIL
2023static void chkmail(void);
Denys Vlasenko8c52f802011-02-04 17:36:21 +01002024static void changemail(const char *var_value) FAST_FUNC;
2025#else
2026# define chkmail() ((void)0)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002027#endif
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02002028static void changepath(const char *) FAST_FUNC;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002029#if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02002030static void change_random(const char *) FAST_FUNC;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002031#endif
2032
Denis Vlasenko01631112007-12-16 17:20:38 +00002033static const struct {
2034 int flags;
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002035 const char *var_text;
2036 void (*var_func)(const char *) FAST_FUNC;
Denis Vlasenko01631112007-12-16 17:20:38 +00002037} varinit_data[] = {
Denys Vlasenko566a3132012-07-07 21:40:35 +02002038 /*
2039 * Note: VEXPORT would not work correctly here for NOFORK applets:
2040 * some environment strings may be constant.
2041 */
Denis Vlasenko01631112007-12-16 17:20:38 +00002042 { VSTRFIXED|VTEXTFIXED , defifsvar , NULL },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002043#if ENABLE_ASH_MAIL
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002044 { VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL" , changemail },
2045 { VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH" , changemail },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002046#endif
Denis Vlasenko01631112007-12-16 17:20:38 +00002047 { VSTRFIXED|VTEXTFIXED , bb_PATH_root_path, changepath },
2048 { VSTRFIXED|VTEXTFIXED , "PS1=$ " , NULL },
2049 { VSTRFIXED|VTEXTFIXED , "PS2=> " , NULL },
2050 { VSTRFIXED|VTEXTFIXED , "PS4=+ " , NULL },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002051#if ENABLE_ASH_GETOPTS
Denys Vlasenkoe627ac92016-09-30 14:36:59 +02002052 { VSTRFIXED|VTEXTFIXED , defoptindvar, getoptsreset },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002053#endif
Denys Vlasenko675d24a2018-01-27 22:02:05 +01002054 { VSTRFIXED|VTEXTFIXED , NULL /* inited to linenovar */, NULL },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002055#if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002056 { VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM", change_random },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002057#endif
2058#if ENABLE_LOCALE_SUPPORT
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002059 { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_ALL" , change_lc_all },
2060 { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_CTYPE" , change_lc_ctype },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002061#endif
2062#if ENABLE_FEATURE_EDITING_SAVEHISTORY
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002063 { VSTRFIXED|VTEXTFIXED|VUNSET, "HISTFILE" , NULL },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002064#endif
2065};
2066
Denis Vlasenko0b769642008-07-24 07:54:57 +00002067struct redirtab;
Denis Vlasenko01631112007-12-16 17:20:38 +00002068
2069struct globals_var {
2070 struct shparam shellparam; /* $@ current positional parameters */
2071 struct redirtab *redirlist;
Denys Vlasenkod07a15b2017-07-30 16:51:05 +02002072 int preverrout_fd; /* stderr fd: usually 2, unless redirect moved it */
Denis Vlasenko01631112007-12-16 17:20:38 +00002073 struct var *vartab[VTABSIZE];
2074 struct var varinit[ARRAY_SIZE(varinit_data)];
Denys Vlasenko675d24a2018-01-27 22:02:05 +01002075 int lineno;
2076 char linenovar[sizeof("LINENO=") + sizeof(int)*3];
Denis Vlasenko01631112007-12-16 17:20:38 +00002077};
Denys Vlasenko6f9442f2018-01-28 20:41:23 +01002078extern struct globals_var *BB_GLOBAL_CONST ash_ptr_to_globals_var;
Denis Vlasenko574f2f42008-02-27 18:41:59 +00002079#define G_var (*ash_ptr_to_globals_var)
Denis Vlasenko01631112007-12-16 17:20:38 +00002080#define shellparam (G_var.shellparam )
Denis Vlasenko0b769642008-07-24 07:54:57 +00002081//#define redirlist (G_var.redirlist )
Denis Vlasenko01631112007-12-16 17:20:38 +00002082#define preverrout_fd (G_var.preverrout_fd)
2083#define vartab (G_var.vartab )
2084#define varinit (G_var.varinit )
Denys Vlasenko675d24a2018-01-27 22:02:05 +01002085#define lineno (G_var.lineno )
2086#define linenovar (G_var.linenovar )
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002087#define vifs varinit[0]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002088#if ENABLE_ASH_MAIL
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002089# define vmail (&vifs)[1]
2090# define vmpath (&vmail)[1]
2091# define vpath (&vmpath)[1]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002092#else
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002093# define vpath (&vifs)[1]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002094#endif
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002095#define vps1 (&vpath)[1]
2096#define vps2 (&vps1)[1]
2097#define vps4 (&vps2)[1]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002098#if ENABLE_ASH_GETOPTS
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002099# define voptind (&vps4)[1]
Denys Vlasenko675d24a2018-01-27 22:02:05 +01002100# define vlineno (&voptind)[1]
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002101# if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenko675d24a2018-01-27 22:02:05 +01002102# define vrandom (&vlineno)[1]
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002103# endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002104#else
Denys Vlasenko675d24a2018-01-27 22:02:05 +01002105# define vlineno (&vps4)[1]
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002106# if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenko675d24a2018-01-27 22:02:05 +01002107# define vrandom (&vlineno)[1]
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002108# endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002109#endif
Denys Vlasenko675d24a2018-01-27 22:02:05 +01002110#define INIT_G_var() do { \
2111 unsigned i; \
2112 (*(struct globals_var**)&ash_ptr_to_globals_var) = xzalloc(sizeof(G_var)); \
2113 barrier(); \
2114 for (i = 0; i < ARRAY_SIZE(varinit_data); i++) { \
2115 varinit[i].flags = varinit_data[i].flags; \
2116 varinit[i].var_text = varinit_data[i].var_text; \
2117 varinit[i].var_func = varinit_data[i].var_func; \
2118 } \
2119 strcpy(linenovar, "LINENO="); \
2120 vlineno.var_text = linenovar; \
2121} while (0)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002122
2123/*
2124 * The following macros access the values of the above variables.
2125 * They have to skip over the name. They return the null string
2126 * for unset variables.
2127 */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002128#define ifsval() (vifs.var_text + 4)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002129#define ifsset() ((vifs.flags & VUNSET) == 0)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002130#if ENABLE_ASH_MAIL
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002131# define mailval() (vmail.var_text + 5)
2132# define mpathval() (vmpath.var_text + 9)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002133# define mpathset() ((vmpath.flags & VUNSET) == 0)
2134#endif
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002135#define pathval() (vpath.var_text + 5)
2136#define ps1val() (vps1.var_text + 4)
2137#define ps2val() (vps2.var_text + 4)
2138#define ps4val() (vps4.var_text + 4)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002139#if ENABLE_ASH_GETOPTS
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002140# define optindval() (voptind.var_text + 7)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002141#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002142
Denis Vlasenko01631112007-12-16 17:20:38 +00002143#if ENABLE_ASH_GETOPTS
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02002144static void FAST_FUNC
Denis Vlasenko01631112007-12-16 17:20:38 +00002145getoptsreset(const char *value)
2146{
Denys Vlasenko46289452017-08-11 00:59:36 +02002147 shellparam.optind = 1;
2148 if (is_number(value))
2149 shellparam.optind = number(value) ?: 1;
Denis Vlasenko01631112007-12-16 17:20:38 +00002150 shellparam.optoff = -1;
2151}
2152#endif
2153
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002154/*
2155 * Compares two strings up to the first = or '\0'. The first
2156 * string must be terminated by '='; the second may be terminated by
2157 * either '=' or '\0'.
2158 */
2159static int
2160varcmp(const char *p, const char *q)
2161{
2162 int c, d;
2163
2164 while ((c = *p) == (d = *q)) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02002165 if (c == '\0' || c == '=')
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002166 goto out;
2167 p++;
2168 q++;
2169 }
2170 if (c == '=')
Denis Vlasenko9650f362007-02-23 01:04:37 +00002171 c = '\0';
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002172 if (d == '=')
Denis Vlasenko9650f362007-02-23 01:04:37 +00002173 d = '\0';
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002174 out:
2175 return c - d;
2176}
2177
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002178/*
2179 * Find the appropriate entry in the hash table from the name.
2180 */
2181static struct var **
2182hashvar(const char *p)
2183{
2184 unsigned hashval;
2185
2186 hashval = ((unsigned char) *p) << 4;
2187 while (*p && *p != '=')
2188 hashval += (unsigned char) *p++;
2189 return &vartab[hashval % VTABSIZE];
2190}
2191
2192static int
2193vpcmp(const void *a, const void *b)
2194{
2195 return varcmp(*(const char **)a, *(const char **)b);
2196}
2197
2198/*
2199 * This routine initializes the builtin variables.
2200 */
2201static void
2202initvar(void)
2203{
2204 struct var *vp;
2205 struct var *end;
2206 struct var **vpp;
2207
2208 /*
2209 * PS1 depends on uid
2210 */
2211#if ENABLE_FEATURE_EDITING && ENABLE_FEATURE_EDITING_FANCY_PROMPT
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002212 vps1.var_text = "PS1=\\w \\$ ";
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002213#else
2214 if (!geteuid())
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002215 vps1.var_text = "PS1=# ";
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002216#endif
2217 vp = varinit;
Denis Vlasenko80b8b392007-06-25 10:55:35 +00002218 end = vp + ARRAY_SIZE(varinit);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002219 do {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002220 vpp = hashvar(vp->var_text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002221 vp->next = *vpp;
2222 *vpp = vp;
2223 } while (++vp < end);
2224}
2225
2226static struct var **
2227findvar(struct var **vpp, const char *name)
2228{
2229 for (; *vpp; vpp = &(*vpp)->next) {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002230 if (varcmp((*vpp)->var_text, name) == 0) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002231 break;
2232 }
2233 }
2234 return vpp;
2235}
2236
2237/*
2238 * Find the value of a variable. Returns NULL if not set.
2239 */
Denys Vlasenko03dad222010-01-12 23:29:57 +01002240static const char* FAST_FUNC
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002241lookupvar(const char *name)
2242{
2243 struct var *v;
2244
2245 v = *findvar(hashvar(name), name);
2246 if (v) {
Denis Vlasenko448d30e2008-06-27 00:24:11 +00002247#if ENABLE_ASH_RANDOM_SUPPORT
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002248 /*
2249 * Dynamic variables are implemented roughly the same way they are
2250 * in bash. Namely, they're "special" so long as they aren't unset.
2251 * As soon as they're unset, they're no longer dynamic, and dynamic
2252 * lookup will no longer happen at that point. -- PFM.
2253 */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002254 if (v->flags & VDYNAMIC)
2255 v->var_func(NULL);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002256#endif
Denys Vlasenko675d24a2018-01-27 22:02:05 +01002257 if (!(v->flags & VUNSET)) {
2258 if (v == &vlineno && v->var_text == linenovar) {
2259 fmtstr(linenovar+7, sizeof(linenovar)-7, "%d", lineno);
2260 }
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002261 return var_end(v->var_text);
Denys Vlasenko675d24a2018-01-27 22:02:05 +01002262 }
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002263 }
2264 return NULL;
2265}
2266
Denys Vlasenko0b883582016-12-23 16:49:07 +01002267#if ENABLE_UNICODE_SUPPORT
Denys Vlasenko37dc08b2016-10-02 04:38:07 +02002268static void
2269reinit_unicode_for_ash(void)
Denys Vlasenkoe9ab07c2014-08-13 18:00:08 +02002270{
2271 /* Unicode support should be activated even if LANG is set
2272 * _during_ shell execution, not only if it was set when
2273 * shell was started. Therefore, re-check LANG every time:
2274 */
2275 if (ENABLE_FEATURE_CHECK_UNICODE_IN_ENV
2276 || ENABLE_UNICODE_USING_LOCALE
2277 ) {
2278 const char *s = lookupvar("LC_ALL");
2279 if (!s) s = lookupvar("LC_CTYPE");
2280 if (!s) s = lookupvar("LANG");
2281 reinit_unicode(s);
2282 }
2283}
Denys Vlasenko0b883582016-12-23 16:49:07 +01002284#else
2285# define reinit_unicode_for_ash() ((void)0)
2286#endif
Denys Vlasenkoe9ab07c2014-08-13 18:00:08 +02002287
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002288/*
2289 * Search the environment of a builtin command.
2290 */
Denys Vlasenko488e6092017-07-26 23:08:36 +02002291static ALWAYS_INLINE const char *
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002292bltinlookup(const char *name)
2293{
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002294 return lookupvar(name);
2295}
2296
2297/*
2298 * Same as setvar except that the variable and value are passed in
2299 * the first argument as name=value. Since the first argument will
2300 * be actually stored in the table, it should not be a string that
2301 * will go away.
2302 * Called with interrupts off.
2303 */
Denys Vlasenkod04fc712017-07-26 20:06:48 +02002304static struct var *
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002305setvareq(char *s, int flags)
2306{
2307 struct var *vp, **vpp;
2308
2309 vpp = hashvar(s);
2310 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
Denys Vlasenkod04fc712017-07-26 20:06:48 +02002311 vpp = findvar(vpp, s);
2312 vp = *vpp;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002313 if (vp) {
2314 if ((vp->flags & (VREADONLY|VDYNAMIC)) == VREADONLY) {
2315 const char *n;
2316
2317 if (flags & VNOSAVE)
2318 free(s);
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002319 n = vp->var_text;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +02002320 exitstatus = 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002321 ash_msg_and_raise_error("%.*s: is read only", strchrnul(n, '=') - n, n);
2322 }
2323
2324 if (flags & VNOSET)
Denys Vlasenkod04fc712017-07-26 20:06:48 +02002325 goto out;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002326
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002327 if (vp->var_func && !(flags & VNOFUNC))
2328 vp->var_func(var_end(s));
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002329
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002330 if (!(vp->flags & (VTEXTFIXED|VSTACK)))
2331 free((char*)vp->var_text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002332
Denys Vlasenkob28d4c32017-07-25 16:29:36 +02002333 if (((flags & (VEXPORT|VREADONLY|VSTRFIXED|VUNSET)) | (vp->flags & VSTRFIXED)) == VUNSET) {
2334 *vpp = vp->next;
2335 free(vp);
2336 out_free:
2337 if ((flags & (VTEXTFIXED|VSTACK|VNOSAVE)) == VNOSAVE)
2338 free(s);
Denys Vlasenkod04fc712017-07-26 20:06:48 +02002339 goto out;
Denys Vlasenkob28d4c32017-07-25 16:29:36 +02002340 }
2341
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002342 flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
2343 } else {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002344 /* variable s is not found */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002345 if (flags & VNOSET)
Denys Vlasenkod04fc712017-07-26 20:06:48 +02002346 goto out;
Denys Vlasenkob28d4c32017-07-25 16:29:36 +02002347 if ((flags & (VEXPORT|VREADONLY|VSTRFIXED|VUNSET)) == VUNSET)
2348 goto out_free;
Denis Vlasenko597906c2008-02-20 16:38:54 +00002349 vp = ckzalloc(sizeof(*vp));
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002350 vp->next = *vpp;
Denis Vlasenko597906c2008-02-20 16:38:54 +00002351 /*vp->func = NULL; - ckzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002352 *vpp = vp;
2353 }
2354 if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE)))
2355 s = ckstrdup(s);
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002356 vp->var_text = s;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002357 vp->flags = flags;
Denys Vlasenkod04fc712017-07-26 20:06:48 +02002358
2359 out:
2360 return vp;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002361}
2362
2363/*
2364 * Set the value of a variable. The flags argument is ored with the
2365 * flags of the variable. If val is NULL, the variable is unset.
2366 */
Denys Vlasenkod04fc712017-07-26 20:06:48 +02002367static struct var *
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002368setvar(const char *name, const char *val, int flags)
2369{
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002370 const char *q;
2371 char *p;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002372 char *nameeq;
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002373 size_t namelen;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002374 size_t vallen;
Denys Vlasenkod04fc712017-07-26 20:06:48 +02002375 struct var *vp;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002376
2377 q = endofname(name);
2378 p = strchrnul(q, '=');
2379 namelen = p - name;
2380 if (!namelen || p != q)
2381 ash_msg_and_raise_error("%.*s: bad variable name", namelen, name);
2382 vallen = 0;
2383 if (val == NULL) {
2384 flags |= VUNSET;
2385 } else {
2386 vallen = strlen(val);
2387 }
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002388
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002389 INT_OFF;
2390 nameeq = ckmalloc(namelen + vallen + 2);
Denys Vlasenkoda2244f2017-07-21 18:51:29 +02002391 p = mempcpy(nameeq, name, namelen);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002392 if (val) {
2393 *p++ = '=';
Denys Vlasenkoda2244f2017-07-21 18:51:29 +02002394 p = mempcpy(p, val, vallen);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002395 }
2396 *p = '\0';
Denys Vlasenkod04fc712017-07-26 20:06:48 +02002397 vp = setvareq(nameeq, flags | VNOSAVE);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002398 INT_ON;
Denys Vlasenkod04fc712017-07-26 20:06:48 +02002399
2400 return vp;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002401}
2402
Denys Vlasenko03dad222010-01-12 23:29:57 +01002403static void FAST_FUNC
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02002404setvar0(const char *name, const char *val)
Denys Vlasenko03dad222010-01-12 23:29:57 +01002405{
2406 setvar(name, val, 0);
2407}
2408
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002409/*
2410 * Unset the specified variable.
2411 */
Denys Vlasenkob28d4c32017-07-25 16:29:36 +02002412static void
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002413unsetvar(const char *s)
2414{
Denys Vlasenkocf3a7962017-07-26 14:38:19 +02002415 setvar(s, NULL, 0);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002416}
2417
2418/*
2419 * Process a linked list of variable assignments.
2420 */
2421static void
2422listsetvar(struct strlist *list_set_var, int flags)
2423{
2424 struct strlist *lp = list_set_var;
2425
2426 if (!lp)
2427 return;
2428 INT_OFF;
2429 do {
2430 setvareq(lp->text, flags);
Denis Vlasenko9650f362007-02-23 01:04:37 +00002431 lp = lp->next;
2432 } while (lp);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002433 INT_ON;
2434}
2435
2436/*
2437 * Generate a list of variables satisfying the given conditions.
2438 */
Denys Vlasenkoa5060b82017-11-03 14:16:25 +01002439#if !ENABLE_FEATURE_SH_NOFORK
2440# define listvars(on, off, lp, end) listvars(on, off, end)
2441#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002442static char **
Denys Vlasenkoa5060b82017-11-03 14:16:25 +01002443listvars(int on, int off, struct strlist *lp, char ***end)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002444{
2445 struct var **vpp;
2446 struct var *vp;
2447 char **ep;
2448 int mask;
2449
2450 STARTSTACKSTR(ep);
2451 vpp = vartab;
2452 mask = on | off;
2453 do {
2454 for (vp = *vpp; vp; vp = vp->next) {
2455 if ((vp->flags & mask) == on) {
Denys Vlasenkoa5060b82017-11-03 14:16:25 +01002456#if ENABLE_FEATURE_SH_NOFORK
2457 /* If variable with the same name is both
2458 * exported and temporarily set for a command:
2459 * export ZVAR=5
2460 * ZVAR=6 printenv
2461 * then "ZVAR=6" will be both in vartab and
2462 * lp lists. Do not pass it twice to printenv.
2463 */
2464 struct strlist *lp1 = lp;
2465 while (lp1) {
2466 if (strcmp(lp1->text, vp->var_text) == 0)
2467 goto skip;
2468 lp1 = lp1->next;
2469 }
2470#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002471 if (ep == stackstrend())
2472 ep = growstackstr();
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002473 *ep++ = (char*)vp->var_text;
Denys Vlasenkoa5060b82017-11-03 14:16:25 +01002474#if ENABLE_FEATURE_SH_NOFORK
2475 skip: ;
2476#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002477 }
2478 }
2479 } while (++vpp < vartab + VTABSIZE);
Denys Vlasenkoa5060b82017-11-03 14:16:25 +01002480
2481#if ENABLE_FEATURE_SH_NOFORK
2482 while (lp) {
2483 if (ep == stackstrend())
2484 ep = growstackstr();
2485 *ep++ = lp->text;
2486 lp = lp->next;
2487 }
2488#endif
2489
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002490 if (ep == stackstrend())
2491 ep = growstackstr();
2492 if (end)
2493 *end = ep;
2494 *ep++ = NULL;
2495 return grabstackstr(ep);
2496}
2497
2498
2499/* ============ Path search helper
2500 *
2501 * The variable path (passed by reference) should be set to the start
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002502 * of the path before the first call; path_advance will update
2503 * this value as it proceeds. Successive calls to path_advance will return
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002504 * the possible path expansions in sequence. If an option (indicated by
2505 * a percent sign) appears in the path entry then the global variable
2506 * pathopt will be set to point to it; otherwise pathopt will be set to
2507 * NULL.
2508 */
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002509static const char *pathopt; /* set by path_advance */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002510
2511static char *
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002512path_advance(const char **path, const char *name)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002513{
2514 const char *p;
2515 char *q;
2516 const char *start;
2517 size_t len;
2518
2519 if (*path == NULL)
2520 return NULL;
2521 start = *path;
Denis Vlasenkof7d56652008-03-25 05:51:41 +00002522 for (p = start; *p && *p != ':' && *p != '%'; p++)
2523 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002524 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
2525 while (stackblocksize() < len)
2526 growstackblock();
2527 q = stackblock();
2528 if (p != start) {
Denys Vlasenko5ace96a2017-07-23 21:46:02 +02002529 q = mempcpy(q, start, p - start);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002530 *q++ = '/';
2531 }
2532 strcpy(q, name);
2533 pathopt = NULL;
2534 if (*p == '%') {
2535 pathopt = ++p;
Denis Vlasenkof7d56652008-03-25 05:51:41 +00002536 while (*p && *p != ':')
2537 p++;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002538 }
2539 if (*p == ':')
2540 *path = p + 1;
2541 else
2542 *path = NULL;
2543 return stalloc(len);
2544}
2545
2546
2547/* ============ Prompt */
2548
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +00002549static smallint doprompt; /* if set, prompt the user */
2550static smallint needprompt; /* true if interactive and at start of line */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002551
2552#if ENABLE_FEATURE_EDITING
2553static line_input_t *line_input_state;
2554static const char *cmdedit_prompt;
2555static void
2556putprompt(const char *s)
2557{
2558 if (ENABLE_ASH_EXPAND_PRMT) {
2559 free((char*)cmdedit_prompt);
Denis Vlasenko4222ae42007-02-25 02:37:49 +00002560 cmdedit_prompt = ckstrdup(s);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002561 return;
2562 }
2563 cmdedit_prompt = s;
2564}
2565#else
2566static void
2567putprompt(const char *s)
2568{
2569 out2str(s);
2570}
2571#endif
2572
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002573/* expandstr() needs parsing machinery, so it is far away ahead... */
Denys Vlasenko46999802017-07-29 21:12:29 +02002574static const char *expandstr(const char *ps, int syntax_type);
2575/* Values for syntax param */
2576#define BASESYNTAX 0 /* not in quotes */
2577#define DQSYNTAX 1 /* in double quotes */
2578#define SQSYNTAX 2 /* in single quotes */
2579#define ARISYNTAX 3 /* in arithmetic */
Denys Vlasenko5f0a75f2017-07-29 22:58:44 +02002580#if ENABLE_ASH_EXPAND_PRMT
2581# define PSSYNTAX 4 /* prompt. never passed to SIT() */
2582#endif
Denys Vlasenko46999802017-07-29 21:12:29 +02002583/* PSSYNTAX expansion is identical to DQSYNTAX, except keeping '\$' as '\$' */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002584
Denys Vlasenko46999802017-07-29 21:12:29 +02002585/*
2586 * called by editline -- any expansions to the prompt should be added here.
2587 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002588static void
Denys Vlasenko958581a2010-09-12 15:04:27 +02002589setprompt_if(smallint do_set, int whichprompt)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002590{
2591 const char *prompt;
Denys Vlasenko958581a2010-09-12 15:04:27 +02002592 IF_ASH_EXPAND_PRMT(struct stackmark smark;)
2593
2594 if (!do_set)
2595 return;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002596
2597 needprompt = 0;
2598
2599 switch (whichprompt) {
2600 case 1:
2601 prompt = ps1val();
2602 break;
2603 case 2:
2604 prompt = ps2val();
2605 break;
2606 default: /* 0 */
2607 prompt = nullstr;
2608 }
2609#if ENABLE_ASH_EXPAND_PRMT
Denys Vlasenko60ca8342016-09-30 11:21:21 +02002610 pushstackmark(&smark, stackblocksize());
Denys Vlasenko46999802017-07-29 21:12:29 +02002611 putprompt(expandstr(prompt, PSSYNTAX));
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002612 popstackmark(&smark);
Denys Vlasenko48c803a2017-07-01 23:24:48 +02002613#else
2614 putprompt(prompt);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002615#endif
2616}
2617
2618
2619/* ============ The cd and pwd commands */
2620
2621#define CD_PHYSICAL 1
2622#define CD_PRINT 2
2623
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002624static int
2625cdopt(void)
2626{
2627 int flags = 0;
2628 int i, j;
2629
2630 j = 'L';
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02002631 while ((i = nextopt("LP")) != '\0') {
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002632 if (i != j) {
2633 flags ^= CD_PHYSICAL;
2634 j = i;
2635 }
2636 }
2637
2638 return flags;
2639}
2640
2641/*
2642 * Update curdir (the name of the current directory) in response to a
2643 * cd command.
2644 */
2645static const char *
2646updatepwd(const char *dir)
2647{
2648 char *new;
2649 char *p;
2650 char *cdcomppath;
2651 const char *lim;
2652
Denys Vlasenko8e2bc472016-09-28 23:02:57 +02002653 cdcomppath = sstrdup(dir);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002654 STARTSTACKSTR(new);
2655 if (*dir != '/') {
2656 if (curdir == nullstr)
2657 return 0;
2658 new = stack_putstr(curdir, new);
2659 }
2660 new = makestrspace(strlen(dir) + 2, new);
Denis Vlasenko29eb3592008-05-18 14:06:08 +00002661 lim = (char *)stackblock() + 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002662 if (*dir != '/') {
2663 if (new[-1] != '/')
2664 USTPUTC('/', new);
2665 if (new > lim && *lim == '/')
2666 lim++;
2667 } else {
2668 USTPUTC('/', new);
2669 cdcomppath++;
2670 if (dir[1] == '/' && dir[2] != '/') {
2671 USTPUTC('/', new);
2672 cdcomppath++;
2673 lim++;
2674 }
2675 }
2676 p = strtok(cdcomppath, "/");
2677 while (p) {
2678 switch (*p) {
2679 case '.':
2680 if (p[1] == '.' && p[2] == '\0') {
2681 while (new > lim) {
2682 STUNPUTC(new);
2683 if (new[-1] == '/')
2684 break;
2685 }
2686 break;
Denis Vlasenko16abcd92007-04-13 23:59:52 +00002687 }
2688 if (p[1] == '\0')
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002689 break;
2690 /* fall through */
2691 default:
2692 new = stack_putstr(p, new);
2693 USTPUTC('/', new);
2694 }
Denys Vlasenko00da72b2015-10-23 18:43:16 +02002695 p = strtok(NULL, "/");
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002696 }
2697 if (new > lim)
2698 STUNPUTC(new);
2699 *new = 0;
2700 return stackblock();
2701}
2702
2703/*
2704 * Find out what the current directory is. If we already know the current
2705 * directory, this routine returns immediately.
2706 */
2707static char *
2708getpwd(void)
2709{
Denis Vlasenko01631112007-12-16 17:20:38 +00002710 char *dir = getcwd(NULL, 0); /* huh, using glibc extension? */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002711 return dir ? dir : nullstr;
2712}
2713
2714static void
2715setpwd(const char *val, int setold)
2716{
2717 char *oldcur, *dir;
2718
2719 oldcur = dir = curdir;
2720
2721 if (setold) {
2722 setvar("OLDPWD", oldcur, VEXPORT);
2723 }
2724 INT_OFF;
2725 if (physdir != nullstr) {
2726 if (physdir != oldcur)
2727 free(physdir);
2728 physdir = nullstr;
2729 }
2730 if (oldcur == val || !val) {
2731 char *s = getpwd();
2732 physdir = s;
2733 if (!val)
2734 dir = s;
2735 } else
2736 dir = ckstrdup(val);
2737 if (oldcur != dir && oldcur != nullstr) {
2738 free(oldcur);
2739 }
2740 curdir = dir;
2741 INT_ON;
2742 setvar("PWD", dir, VEXPORT);
2743}
2744
2745static void hashcd(void);
2746
2747/*
Denys Vlasenko70392332016-10-27 02:31:55 +02002748 * Actually do the chdir. We also call hashcd to let other routines
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002749 * know that the current directory has changed.
2750 */
2751static int
2752docd(const char *dest, int flags)
2753{
Denys Vlasenko4b1100e2010-03-05 14:10:54 +01002754 const char *dir = NULL;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002755 int err;
2756
2757 TRACE(("docd(\"%s\", %d) called\n", dest, flags));
2758
2759 INT_OFF;
2760 if (!(flags & CD_PHYSICAL)) {
2761 dir = updatepwd(dest);
2762 if (dir)
2763 dest = dir;
2764 }
2765 err = chdir(dest);
2766 if (err)
2767 goto out;
2768 setpwd(dir, 1);
2769 hashcd();
2770 out:
2771 INT_ON;
2772 return err;
2773}
2774
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02002775static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00002776cdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002777{
2778 const char *dest;
2779 const char *path;
2780 const char *p;
2781 char c;
2782 struct stat statb;
2783 int flags;
2784
2785 flags = cdopt();
2786 dest = *argptr;
2787 if (!dest)
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02002788 dest = bltinlookup("HOME");
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002789 else if (LONE_DASH(dest)) {
2790 dest = bltinlookup("OLDPWD");
2791 flags |= CD_PRINT;
2792 }
2793 if (!dest)
2794 dest = nullstr;
2795 if (*dest == '/')
Denys Vlasenko0e081d02016-10-26 19:56:05 +02002796 goto step6;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002797 if (*dest == '.') {
2798 c = dest[1];
2799 dotdot:
2800 switch (c) {
2801 case '\0':
2802 case '/':
2803 goto step6;
2804 case '.':
2805 c = dest[2];
2806 if (c != '.')
2807 goto dotdot;
2808 }
2809 }
2810 if (!*dest)
2811 dest = ".";
2812 path = bltinlookup("CDPATH");
Denys Vlasenko0e081d02016-10-26 19:56:05 +02002813 while (path) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002814 c = *path;
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002815 p = path_advance(&path, dest);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002816 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
2817 if (c && c != ':')
2818 flags |= CD_PRINT;
2819 docd:
2820 if (!docd(p, flags))
2821 goto out;
Denys Vlasenko0e081d02016-10-26 19:56:05 +02002822 goto err;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002823 }
Denys Vlasenko0e081d02016-10-26 19:56:05 +02002824 }
2825
2826 step6:
2827 p = dest;
2828 goto docd;
2829
2830 err:
Johannes Schindelin687aac02017-08-22 22:03:22 +02002831 ash_msg_and_raise_perror("can't cd to %s", dest);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002832 /* NOTREACHED */
2833 out:
2834 if (flags & CD_PRINT)
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02002835 out1fmt("%s\n", curdir);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002836 return 0;
2837}
2838
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02002839static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00002840pwdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002841{
2842 int flags;
2843 const char *dir = curdir;
2844
2845 flags = cdopt();
2846 if (flags) {
2847 if (physdir == nullstr)
2848 setpwd(dir, 0);
2849 dir = physdir;
2850 }
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02002851 out1fmt("%s\n", dir);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002852 return 0;
2853}
2854
Denis Vlasenko0c032a42007-02-23 01:03:40 +00002855
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00002856/* ============ ... */
Eric Andersenc470f442003-07-28 09:56:35 +00002857
Denis Vlasenko834dee72008-10-07 09:18:30 +00002858
Denys Vlasenko82dd14a2010-05-17 10:10:01 +02002859#define IBUFSIZ (ENABLE_FEATURE_EDITING ? CONFIG_FEATURE_EDITING_MAX_LEN : 1024)
Eric Andersenc470f442003-07-28 09:56:35 +00002860
Eric Andersenc470f442003-07-28 09:56:35 +00002861/* Syntax classes */
Denis Vlasenko834dee72008-10-07 09:18:30 +00002862#define CWORD 0 /* character is nothing special */
2863#define CNL 1 /* newline character */
2864#define CBACK 2 /* a backslash character */
2865#define CSQUOTE 3 /* single quote */
2866#define CDQUOTE 4 /* double quote */
Eric Andersenc470f442003-07-28 09:56:35 +00002867#define CENDQUOTE 5 /* a terminating quote */
Denis Vlasenko834dee72008-10-07 09:18:30 +00002868#define CBQUOTE 6 /* backwards single quote */
2869#define CVAR 7 /* a dollar sign */
2870#define CENDVAR 8 /* a '}' character */
2871#define CLP 9 /* a left paren in arithmetic */
2872#define CRP 10 /* a right paren in arithmetic */
Eric Andersenc470f442003-07-28 09:56:35 +00002873#define CENDFILE 11 /* end of file */
Denis Vlasenko834dee72008-10-07 09:18:30 +00002874#define CCTL 12 /* like CWORD, except it must be escaped */
2875#define CSPCL 13 /* these terminate a word */
2876#define CIGN 14 /* character should be ignored */
Eric Andersenc470f442003-07-28 09:56:35 +00002877
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002878#define PEOF 256
Denis Vlasenko131ae172007-02-18 13:00:19 +00002879#if ENABLE_ASH_ALIAS
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002880# define PEOA 257
Eric Andersenc470f442003-07-28 09:56:35 +00002881#endif
2882
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002883#define USE_SIT_FUNCTION ENABLE_ASH_OPTIMIZE_FOR_SIZE
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002884
Denys Vlasenko0b883582016-12-23 16:49:07 +01002885#if ENABLE_FEATURE_SH_MATH
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002886# define SIT_ITEM(a,b,c,d) (a | (b << 4) | (c << 8) | (d << 12))
Eric Andersenc470f442003-07-28 09:56:35 +00002887#else
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002888# define SIT_ITEM(a,b,c,d) (a | (b << 4) | (c << 8))
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002889#endif
Denys Vlasenko3e134eb2016-04-22 18:09:21 +02002890static const uint16_t S_I_T[] ALIGN2 = {
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002891#if ENABLE_ASH_ALIAS
2892 SIT_ITEM(CSPCL , CIGN , CIGN , CIGN ), /* 0, PEOA */
2893#endif
2894 SIT_ITEM(CSPCL , CWORD , CWORD, CWORD ), /* 1, ' ' */
2895 SIT_ITEM(CNL , CNL , CNL , CNL ), /* 2, \n */
2896 SIT_ITEM(CWORD , CCTL , CCTL , CWORD ), /* 3, !*-/:=?[]~ */
2897 SIT_ITEM(CDQUOTE , CENDQUOTE, CWORD, CWORD ), /* 4, '"' */
2898 SIT_ITEM(CVAR , CVAR , CWORD, CVAR ), /* 5, $ */
2899 SIT_ITEM(CSQUOTE , CWORD , CENDQUOTE, CWORD), /* 6, "'" */
2900 SIT_ITEM(CSPCL , CWORD , CWORD, CLP ), /* 7, ( */
2901 SIT_ITEM(CSPCL , CWORD , CWORD, CRP ), /* 8, ) */
2902 SIT_ITEM(CBACK , CBACK , CCTL , CBACK ), /* 9, \ */
2903 SIT_ITEM(CBQUOTE , CBQUOTE , CWORD, CBQUOTE), /* 10, ` */
2904 SIT_ITEM(CENDVAR , CENDVAR , CWORD, CENDVAR), /* 11, } */
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002905#if !USE_SIT_FUNCTION
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002906 SIT_ITEM(CENDFILE, CENDFILE , CENDFILE, CENDFILE),/* 12, PEOF */
2907 SIT_ITEM(CWORD , CWORD , CWORD, CWORD ), /* 13, 0-9A-Za-z */
2908 SIT_ITEM(CCTL , CCTL , CCTL , CCTL ) /* 14, CTLESC ... */
2909#endif
2910#undef SIT_ITEM
Eric Andersenc470f442003-07-28 09:56:35 +00002911};
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002912/* Constants below must match table above */
2913enum {
2914#if ENABLE_ASH_ALIAS
2915 CSPCL_CIGN_CIGN_CIGN , /* 0 */
2916#endif
2917 CSPCL_CWORD_CWORD_CWORD , /* 1 */
2918 CNL_CNL_CNL_CNL , /* 2 */
2919 CWORD_CCTL_CCTL_CWORD , /* 3 */
2920 CDQUOTE_CENDQUOTE_CWORD_CWORD , /* 4 */
2921 CVAR_CVAR_CWORD_CVAR , /* 5 */
2922 CSQUOTE_CWORD_CENDQUOTE_CWORD , /* 6 */
2923 CSPCL_CWORD_CWORD_CLP , /* 7 */
2924 CSPCL_CWORD_CWORD_CRP , /* 8 */
2925 CBACK_CBACK_CCTL_CBACK , /* 9 */
2926 CBQUOTE_CBQUOTE_CWORD_CBQUOTE , /* 10 */
2927 CENDVAR_CENDVAR_CWORD_CENDVAR , /* 11 */
2928 CENDFILE_CENDFILE_CENDFILE_CENDFILE, /* 12 */
2929 CWORD_CWORD_CWORD_CWORD , /* 13 */
2930 CCTL_CCTL_CCTL_CCTL , /* 14 */
2931};
Eric Andersen2870d962001-07-02 17:27:21 +00002932
Denys Vlasenkocd716832009-11-28 22:14:02 +01002933/* c in SIT(c, syntax) must be an *unsigned char* or PEOA or PEOF,
2934 * caller must ensure proper cast on it if c is *char_ptr!
2935 */
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002936#if USE_SIT_FUNCTION
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002937
Denis Vlasenko0c032a42007-02-23 01:03:40 +00002938static int
2939SIT(int c, int syntax)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002940{
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02002941 /* Used to also have '/' in this string: "\t\n !\"$&'()*-/:;<=>?[\\]`|}~" */
2942 static const char spec_symbls[] ALIGN1 = "\t\n !\"$&'()*-:;<=>?[\\]`|}~";
2943 /*
2944 * This causes '/' to be prepended with CTLESC in dquoted string,
2945 * making "./file"* treated incorrectly because we feed
2946 * ".\/file*" string to glob(), confusing it (see expandmeta func).
2947 * The "homegrown" glob implementation is okay with that,
2948 * but glibc one isn't. With '/' always treated as CWORD,
2949 * both work fine.
2950 */
Denys Vlasenkocd716832009-11-28 22:14:02 +01002951# if ENABLE_ASH_ALIAS
2952 static const uint8_t syntax_index_table[] ALIGN1 = {
Eric Andersenc470f442003-07-28 09:56:35 +00002953 1, 2, 1, 3, 4, 5, 1, 6, /* "\t\n !\"$&'" */
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02002954 7, 8, 3, 3,/*3,*/3, 1, 1, /* "()*-/:;<" */
Eric Andersenc470f442003-07-28 09:56:35 +00002955 3, 1, 3, 3, 9, 3, 10, 1, /* "=>?[\\]`|" */
2956 11, 3 /* "}~" */
2957 };
Denys Vlasenkocd716832009-11-28 22:14:02 +01002958# else
2959 static const uint8_t syntax_index_table[] ALIGN1 = {
Eric Andersenc470f442003-07-28 09:56:35 +00002960 0, 1, 0, 2, 3, 4, 0, 5, /* "\t\n !\"$&'" */
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02002961 6, 7, 2, 2,/*2,*/2, 0, 0, /* "()*-/:;<" */
Eric Andersenc470f442003-07-28 09:56:35 +00002962 2, 0, 2, 2, 8, 2, 9, 0, /* "=>?[\\]`|" */
2963 10, 2 /* "}~" */
2964 };
Denys Vlasenkocd716832009-11-28 22:14:02 +01002965# endif
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002966 const char *s;
2967 int indx;
2968
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002969 if (c == PEOF)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002970 return CENDFILE;
Denys Vlasenkocd716832009-11-28 22:14:02 +01002971# if ENABLE_ASH_ALIAS
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002972 if (c == PEOA)
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002973 indx = 0;
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002974 else
Denys Vlasenkocd716832009-11-28 22:14:02 +01002975# endif
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002976 {
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002977 /* Cast is purely for paranoia here,
2978 * just in case someone passed signed char to us */
2979 if ((unsigned char)c >= CTL_FIRST
2980 && (unsigned char)c <= CTL_LAST
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002981 ) {
2982 return CCTL;
2983 }
2984 s = strchrnul(spec_symbls, c);
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002985 if (*s == '\0')
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002986 return CWORD;
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002987 indx = syntax_index_table[s - spec_symbls];
2988 }
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002989 return (S_I_T[indx] >> (syntax*4)) & 0xf;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002990}
2991
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00002992#else /* !USE_SIT_FUNCTION */
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002993
Denys Vlasenko3e134eb2016-04-22 18:09:21 +02002994static const uint8_t syntax_index_table[] ALIGN1 = {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002995 /* BASESYNTAX_DQSYNTAX_SQSYNTAX_ARISYNTAX */
Denys Vlasenkocd716832009-11-28 22:14:02 +01002996 /* 0 */ CWORD_CWORD_CWORD_CWORD,
2997 /* 1 */ CWORD_CWORD_CWORD_CWORD,
2998 /* 2 */ CWORD_CWORD_CWORD_CWORD,
2999 /* 3 */ CWORD_CWORD_CWORD_CWORD,
3000 /* 4 */ CWORD_CWORD_CWORD_CWORD,
3001 /* 5 */ CWORD_CWORD_CWORD_CWORD,
3002 /* 6 */ CWORD_CWORD_CWORD_CWORD,
3003 /* 7 */ CWORD_CWORD_CWORD_CWORD,
3004 /* 8 */ CWORD_CWORD_CWORD_CWORD,
3005 /* 9 "\t" */ CSPCL_CWORD_CWORD_CWORD,
3006 /* 10 "\n" */ CNL_CNL_CNL_CNL,
3007 /* 11 */ CWORD_CWORD_CWORD_CWORD,
3008 /* 12 */ CWORD_CWORD_CWORD_CWORD,
3009 /* 13 */ CWORD_CWORD_CWORD_CWORD,
3010 /* 14 */ CWORD_CWORD_CWORD_CWORD,
3011 /* 15 */ CWORD_CWORD_CWORD_CWORD,
3012 /* 16 */ CWORD_CWORD_CWORD_CWORD,
3013 /* 17 */ CWORD_CWORD_CWORD_CWORD,
3014 /* 18 */ CWORD_CWORD_CWORD_CWORD,
3015 /* 19 */ CWORD_CWORD_CWORD_CWORD,
3016 /* 20 */ CWORD_CWORD_CWORD_CWORD,
3017 /* 21 */ CWORD_CWORD_CWORD_CWORD,
3018 /* 22 */ CWORD_CWORD_CWORD_CWORD,
3019 /* 23 */ CWORD_CWORD_CWORD_CWORD,
3020 /* 24 */ CWORD_CWORD_CWORD_CWORD,
3021 /* 25 */ CWORD_CWORD_CWORD_CWORD,
3022 /* 26 */ CWORD_CWORD_CWORD_CWORD,
3023 /* 27 */ CWORD_CWORD_CWORD_CWORD,
3024 /* 28 */ CWORD_CWORD_CWORD_CWORD,
3025 /* 29 */ CWORD_CWORD_CWORD_CWORD,
3026 /* 30 */ CWORD_CWORD_CWORD_CWORD,
3027 /* 31 */ CWORD_CWORD_CWORD_CWORD,
3028 /* 32 " " */ CSPCL_CWORD_CWORD_CWORD,
3029 /* 33 "!" */ CWORD_CCTL_CCTL_CWORD,
3030 /* 34 """ */ CDQUOTE_CENDQUOTE_CWORD_CWORD,
3031 /* 35 "#" */ CWORD_CWORD_CWORD_CWORD,
3032 /* 36 "$" */ CVAR_CVAR_CWORD_CVAR,
3033 /* 37 "%" */ CWORD_CWORD_CWORD_CWORD,
3034 /* 38 "&" */ CSPCL_CWORD_CWORD_CWORD,
3035 /* 39 "'" */ CSQUOTE_CWORD_CENDQUOTE_CWORD,
3036 /* 40 "(" */ CSPCL_CWORD_CWORD_CLP,
3037 /* 41 ")" */ CSPCL_CWORD_CWORD_CRP,
3038 /* 42 "*" */ CWORD_CCTL_CCTL_CWORD,
3039 /* 43 "+" */ CWORD_CWORD_CWORD_CWORD,
3040 /* 44 "," */ CWORD_CWORD_CWORD_CWORD,
3041 /* 45 "-" */ CWORD_CCTL_CCTL_CWORD,
3042 /* 46 "." */ CWORD_CWORD_CWORD_CWORD,
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02003043/* "/" was CWORD_CCTL_CCTL_CWORD, see comment in SIT() function why this is changed: */
3044 /* 47 "/" */ CWORD_CWORD_CWORD_CWORD,
Denys Vlasenkocd716832009-11-28 22:14:02 +01003045 /* 48 "0" */ CWORD_CWORD_CWORD_CWORD,
3046 /* 49 "1" */ CWORD_CWORD_CWORD_CWORD,
3047 /* 50 "2" */ CWORD_CWORD_CWORD_CWORD,
3048 /* 51 "3" */ CWORD_CWORD_CWORD_CWORD,
3049 /* 52 "4" */ CWORD_CWORD_CWORD_CWORD,
3050 /* 53 "5" */ CWORD_CWORD_CWORD_CWORD,
3051 /* 54 "6" */ CWORD_CWORD_CWORD_CWORD,
3052 /* 55 "7" */ CWORD_CWORD_CWORD_CWORD,
3053 /* 56 "8" */ CWORD_CWORD_CWORD_CWORD,
3054 /* 57 "9" */ CWORD_CWORD_CWORD_CWORD,
3055 /* 58 ":" */ CWORD_CCTL_CCTL_CWORD,
3056 /* 59 ";" */ CSPCL_CWORD_CWORD_CWORD,
3057 /* 60 "<" */ CSPCL_CWORD_CWORD_CWORD,
3058 /* 61 "=" */ CWORD_CCTL_CCTL_CWORD,
3059 /* 62 ">" */ CSPCL_CWORD_CWORD_CWORD,
3060 /* 63 "?" */ CWORD_CCTL_CCTL_CWORD,
3061 /* 64 "@" */ CWORD_CWORD_CWORD_CWORD,
3062 /* 65 "A" */ CWORD_CWORD_CWORD_CWORD,
3063 /* 66 "B" */ CWORD_CWORD_CWORD_CWORD,
3064 /* 67 "C" */ CWORD_CWORD_CWORD_CWORD,
3065 /* 68 "D" */ CWORD_CWORD_CWORD_CWORD,
3066 /* 69 "E" */ CWORD_CWORD_CWORD_CWORD,
3067 /* 70 "F" */ CWORD_CWORD_CWORD_CWORD,
3068 /* 71 "G" */ CWORD_CWORD_CWORD_CWORD,
3069 /* 72 "H" */ CWORD_CWORD_CWORD_CWORD,
3070 /* 73 "I" */ CWORD_CWORD_CWORD_CWORD,
3071 /* 74 "J" */ CWORD_CWORD_CWORD_CWORD,
3072 /* 75 "K" */ CWORD_CWORD_CWORD_CWORD,
3073 /* 76 "L" */ CWORD_CWORD_CWORD_CWORD,
3074 /* 77 "M" */ CWORD_CWORD_CWORD_CWORD,
3075 /* 78 "N" */ CWORD_CWORD_CWORD_CWORD,
3076 /* 79 "O" */ CWORD_CWORD_CWORD_CWORD,
3077 /* 80 "P" */ CWORD_CWORD_CWORD_CWORD,
3078 /* 81 "Q" */ CWORD_CWORD_CWORD_CWORD,
3079 /* 82 "R" */ CWORD_CWORD_CWORD_CWORD,
3080 /* 83 "S" */ CWORD_CWORD_CWORD_CWORD,
3081 /* 84 "T" */ CWORD_CWORD_CWORD_CWORD,
3082 /* 85 "U" */ CWORD_CWORD_CWORD_CWORD,
3083 /* 86 "V" */ CWORD_CWORD_CWORD_CWORD,
3084 /* 87 "W" */ CWORD_CWORD_CWORD_CWORD,
3085 /* 88 "X" */ CWORD_CWORD_CWORD_CWORD,
3086 /* 89 "Y" */ CWORD_CWORD_CWORD_CWORD,
3087 /* 90 "Z" */ CWORD_CWORD_CWORD_CWORD,
3088 /* 91 "[" */ CWORD_CCTL_CCTL_CWORD,
3089 /* 92 "\" */ CBACK_CBACK_CCTL_CBACK,
3090 /* 93 "]" */ CWORD_CCTL_CCTL_CWORD,
3091 /* 94 "^" */ CWORD_CWORD_CWORD_CWORD,
3092 /* 95 "_" */ CWORD_CWORD_CWORD_CWORD,
3093 /* 96 "`" */ CBQUOTE_CBQUOTE_CWORD_CBQUOTE,
3094 /* 97 "a" */ CWORD_CWORD_CWORD_CWORD,
3095 /* 98 "b" */ CWORD_CWORD_CWORD_CWORD,
3096 /* 99 "c" */ CWORD_CWORD_CWORD_CWORD,
3097 /* 100 "d" */ CWORD_CWORD_CWORD_CWORD,
3098 /* 101 "e" */ CWORD_CWORD_CWORD_CWORD,
3099 /* 102 "f" */ CWORD_CWORD_CWORD_CWORD,
3100 /* 103 "g" */ CWORD_CWORD_CWORD_CWORD,
3101 /* 104 "h" */ CWORD_CWORD_CWORD_CWORD,
3102 /* 105 "i" */ CWORD_CWORD_CWORD_CWORD,
3103 /* 106 "j" */ CWORD_CWORD_CWORD_CWORD,
3104 /* 107 "k" */ CWORD_CWORD_CWORD_CWORD,
3105 /* 108 "l" */ CWORD_CWORD_CWORD_CWORD,
3106 /* 109 "m" */ CWORD_CWORD_CWORD_CWORD,
3107 /* 110 "n" */ CWORD_CWORD_CWORD_CWORD,
3108 /* 111 "o" */ CWORD_CWORD_CWORD_CWORD,
3109 /* 112 "p" */ CWORD_CWORD_CWORD_CWORD,
3110 /* 113 "q" */ CWORD_CWORD_CWORD_CWORD,
3111 /* 114 "r" */ CWORD_CWORD_CWORD_CWORD,
3112 /* 115 "s" */ CWORD_CWORD_CWORD_CWORD,
3113 /* 116 "t" */ CWORD_CWORD_CWORD_CWORD,
3114 /* 117 "u" */ CWORD_CWORD_CWORD_CWORD,
3115 /* 118 "v" */ CWORD_CWORD_CWORD_CWORD,
3116 /* 119 "w" */ CWORD_CWORD_CWORD_CWORD,
3117 /* 120 "x" */ CWORD_CWORD_CWORD_CWORD,
3118 /* 121 "y" */ CWORD_CWORD_CWORD_CWORD,
3119 /* 122 "z" */ CWORD_CWORD_CWORD_CWORD,
3120 /* 123 "{" */ CWORD_CWORD_CWORD_CWORD,
3121 /* 124 "|" */ CSPCL_CWORD_CWORD_CWORD,
3122 /* 125 "}" */ CENDVAR_CENDVAR_CWORD_CENDVAR,
3123 /* 126 "~" */ CWORD_CCTL_CCTL_CWORD,
3124 /* 127 del */ CWORD_CWORD_CWORD_CWORD,
3125 /* 128 0x80 */ CWORD_CWORD_CWORD_CWORD,
3126 /* 129 CTLESC */ CCTL_CCTL_CCTL_CCTL,
3127 /* 130 CTLVAR */ CCTL_CCTL_CCTL_CCTL,
3128 /* 131 CTLENDVAR */ CCTL_CCTL_CCTL_CCTL,
3129 /* 132 CTLBACKQ */ CCTL_CCTL_CCTL_CCTL,
3130 /* 133 CTLQUOTE */ CCTL_CCTL_CCTL_CCTL,
3131 /* 134 CTLARI */ CCTL_CCTL_CCTL_CCTL,
3132 /* 135 CTLENDARI */ CCTL_CCTL_CCTL_CCTL,
3133 /* 136 CTLQUOTEMARK */ CCTL_CCTL_CCTL_CCTL,
3134 /* 137 */ CWORD_CWORD_CWORD_CWORD,
3135 /* 138 */ CWORD_CWORD_CWORD_CWORD,
3136 /* 139 */ CWORD_CWORD_CWORD_CWORD,
3137 /* 140 */ CWORD_CWORD_CWORD_CWORD,
3138 /* 141 */ CWORD_CWORD_CWORD_CWORD,
3139 /* 142 */ CWORD_CWORD_CWORD_CWORD,
3140 /* 143 */ CWORD_CWORD_CWORD_CWORD,
3141 /* 144 */ CWORD_CWORD_CWORD_CWORD,
3142 /* 145 */ CWORD_CWORD_CWORD_CWORD,
3143 /* 146 */ CWORD_CWORD_CWORD_CWORD,
3144 /* 147 */ CWORD_CWORD_CWORD_CWORD,
3145 /* 148 */ CWORD_CWORD_CWORD_CWORD,
3146 /* 149 */ CWORD_CWORD_CWORD_CWORD,
3147 /* 150 */ CWORD_CWORD_CWORD_CWORD,
3148 /* 151 */ CWORD_CWORD_CWORD_CWORD,
3149 /* 152 */ CWORD_CWORD_CWORD_CWORD,
3150 /* 153 */ CWORD_CWORD_CWORD_CWORD,
3151 /* 154 */ CWORD_CWORD_CWORD_CWORD,
3152 /* 155 */ CWORD_CWORD_CWORD_CWORD,
3153 /* 156 */ CWORD_CWORD_CWORD_CWORD,
3154 /* 157 */ CWORD_CWORD_CWORD_CWORD,
3155 /* 158 */ CWORD_CWORD_CWORD_CWORD,
3156 /* 159 */ CWORD_CWORD_CWORD_CWORD,
3157 /* 160 */ CWORD_CWORD_CWORD_CWORD,
3158 /* 161 */ CWORD_CWORD_CWORD_CWORD,
3159 /* 162 */ CWORD_CWORD_CWORD_CWORD,
3160 /* 163 */ CWORD_CWORD_CWORD_CWORD,
3161 /* 164 */ CWORD_CWORD_CWORD_CWORD,
3162 /* 165 */ CWORD_CWORD_CWORD_CWORD,
3163 /* 166 */ CWORD_CWORD_CWORD_CWORD,
3164 /* 167 */ CWORD_CWORD_CWORD_CWORD,
3165 /* 168 */ CWORD_CWORD_CWORD_CWORD,
3166 /* 169 */ CWORD_CWORD_CWORD_CWORD,
3167 /* 170 */ CWORD_CWORD_CWORD_CWORD,
3168 /* 171 */ CWORD_CWORD_CWORD_CWORD,
3169 /* 172 */ CWORD_CWORD_CWORD_CWORD,
3170 /* 173 */ CWORD_CWORD_CWORD_CWORD,
3171 /* 174 */ CWORD_CWORD_CWORD_CWORD,
3172 /* 175 */ CWORD_CWORD_CWORD_CWORD,
3173 /* 176 */ CWORD_CWORD_CWORD_CWORD,
3174 /* 177 */ CWORD_CWORD_CWORD_CWORD,
3175 /* 178 */ CWORD_CWORD_CWORD_CWORD,
3176 /* 179 */ CWORD_CWORD_CWORD_CWORD,
3177 /* 180 */ CWORD_CWORD_CWORD_CWORD,
3178 /* 181 */ CWORD_CWORD_CWORD_CWORD,
3179 /* 182 */ CWORD_CWORD_CWORD_CWORD,
3180 /* 183 */ CWORD_CWORD_CWORD_CWORD,
3181 /* 184 */ CWORD_CWORD_CWORD_CWORD,
3182 /* 185 */ CWORD_CWORD_CWORD_CWORD,
3183 /* 186 */ CWORD_CWORD_CWORD_CWORD,
3184 /* 187 */ CWORD_CWORD_CWORD_CWORD,
3185 /* 188 */ CWORD_CWORD_CWORD_CWORD,
3186 /* 189 */ CWORD_CWORD_CWORD_CWORD,
3187 /* 190 */ CWORD_CWORD_CWORD_CWORD,
3188 /* 191 */ CWORD_CWORD_CWORD_CWORD,
3189 /* 192 */ CWORD_CWORD_CWORD_CWORD,
3190 /* 193 */ CWORD_CWORD_CWORD_CWORD,
3191 /* 194 */ CWORD_CWORD_CWORD_CWORD,
3192 /* 195 */ CWORD_CWORD_CWORD_CWORD,
3193 /* 196 */ CWORD_CWORD_CWORD_CWORD,
3194 /* 197 */ CWORD_CWORD_CWORD_CWORD,
3195 /* 198 */ CWORD_CWORD_CWORD_CWORD,
3196 /* 199 */ CWORD_CWORD_CWORD_CWORD,
3197 /* 200 */ CWORD_CWORD_CWORD_CWORD,
3198 /* 201 */ CWORD_CWORD_CWORD_CWORD,
3199 /* 202 */ CWORD_CWORD_CWORD_CWORD,
3200 /* 203 */ CWORD_CWORD_CWORD_CWORD,
3201 /* 204 */ CWORD_CWORD_CWORD_CWORD,
3202 /* 205 */ CWORD_CWORD_CWORD_CWORD,
3203 /* 206 */ CWORD_CWORD_CWORD_CWORD,
3204 /* 207 */ CWORD_CWORD_CWORD_CWORD,
3205 /* 208 */ CWORD_CWORD_CWORD_CWORD,
3206 /* 209 */ CWORD_CWORD_CWORD_CWORD,
3207 /* 210 */ CWORD_CWORD_CWORD_CWORD,
3208 /* 211 */ CWORD_CWORD_CWORD_CWORD,
3209 /* 212 */ CWORD_CWORD_CWORD_CWORD,
3210 /* 213 */ CWORD_CWORD_CWORD_CWORD,
3211 /* 214 */ CWORD_CWORD_CWORD_CWORD,
3212 /* 215 */ CWORD_CWORD_CWORD_CWORD,
3213 /* 216 */ CWORD_CWORD_CWORD_CWORD,
3214 /* 217 */ CWORD_CWORD_CWORD_CWORD,
3215 /* 218 */ CWORD_CWORD_CWORD_CWORD,
3216 /* 219 */ CWORD_CWORD_CWORD_CWORD,
3217 /* 220 */ CWORD_CWORD_CWORD_CWORD,
3218 /* 221 */ CWORD_CWORD_CWORD_CWORD,
3219 /* 222 */ CWORD_CWORD_CWORD_CWORD,
3220 /* 223 */ CWORD_CWORD_CWORD_CWORD,
3221 /* 224 */ CWORD_CWORD_CWORD_CWORD,
3222 /* 225 */ CWORD_CWORD_CWORD_CWORD,
3223 /* 226 */ CWORD_CWORD_CWORD_CWORD,
3224 /* 227 */ CWORD_CWORD_CWORD_CWORD,
3225 /* 228 */ CWORD_CWORD_CWORD_CWORD,
3226 /* 229 */ CWORD_CWORD_CWORD_CWORD,
3227 /* 230 */ CWORD_CWORD_CWORD_CWORD,
3228 /* 231 */ CWORD_CWORD_CWORD_CWORD,
3229 /* 232 */ CWORD_CWORD_CWORD_CWORD,
3230 /* 233 */ CWORD_CWORD_CWORD_CWORD,
3231 /* 234 */ CWORD_CWORD_CWORD_CWORD,
3232 /* 235 */ CWORD_CWORD_CWORD_CWORD,
3233 /* 236 */ CWORD_CWORD_CWORD_CWORD,
3234 /* 237 */ CWORD_CWORD_CWORD_CWORD,
3235 /* 238 */ CWORD_CWORD_CWORD_CWORD,
3236 /* 239 */ CWORD_CWORD_CWORD_CWORD,
3237 /* 230 */ CWORD_CWORD_CWORD_CWORD,
3238 /* 241 */ CWORD_CWORD_CWORD_CWORD,
3239 /* 242 */ CWORD_CWORD_CWORD_CWORD,
3240 /* 243 */ CWORD_CWORD_CWORD_CWORD,
3241 /* 244 */ CWORD_CWORD_CWORD_CWORD,
3242 /* 245 */ CWORD_CWORD_CWORD_CWORD,
3243 /* 246 */ CWORD_CWORD_CWORD_CWORD,
3244 /* 247 */ CWORD_CWORD_CWORD_CWORD,
3245 /* 248 */ CWORD_CWORD_CWORD_CWORD,
3246 /* 249 */ CWORD_CWORD_CWORD_CWORD,
3247 /* 250 */ CWORD_CWORD_CWORD_CWORD,
3248 /* 251 */ CWORD_CWORD_CWORD_CWORD,
3249 /* 252 */ CWORD_CWORD_CWORD_CWORD,
3250 /* 253 */ CWORD_CWORD_CWORD_CWORD,
3251 /* 254 */ CWORD_CWORD_CWORD_CWORD,
3252 /* 255 */ CWORD_CWORD_CWORD_CWORD,
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01003253 /* PEOF */ CENDFILE_CENDFILE_CENDFILE_CENDFILE,
Denys Vlasenkocd716832009-11-28 22:14:02 +01003254# if ENABLE_ASH_ALIAS
3255 /* PEOA */ CSPCL_CIGN_CIGN_CIGN,
3256# endif
Eric Andersen2870d962001-07-02 17:27:21 +00003257};
3258
Denys Vlasenko2fe66b12016-12-12 17:39:12 +01003259#if 1
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01003260# define SIT(c, syntax) ((S_I_T[syntax_index_table[c]] >> ((syntax)*4)) & 0xf)
Denys Vlasenko2fe66b12016-12-12 17:39:12 +01003261#else /* debug version, caught one signed char bug */
3262# define SIT(c, syntax) \
3263 ({ \
3264 if ((c) < 0 || (c) > (PEOF + ENABLE_ASH_ALIAS)) \
3265 bb_error_msg_and_die("line:%d c:%d", __LINE__, (c)); \
Denys Vlasenko0b883582016-12-23 16:49:07 +01003266 if ((syntax) < 0 || (syntax) > (2 + ENABLE_FEATURE_SH_MATH)) \
Denys Vlasenko2fe66b12016-12-12 17:39:12 +01003267 bb_error_msg_and_die("line:%d c:%d", __LINE__, (c)); \
3268 ((S_I_T[syntax_index_table[c]] >> ((syntax)*4)) & 0xf); \
3269 })
3270#endif
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00003271
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01003272#endif /* !USE_SIT_FUNCTION */
Eric Andersenc470f442003-07-28 09:56:35 +00003273
Eric Andersen2870d962001-07-02 17:27:21 +00003274
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00003275/* ============ Alias handling */
Denis Vlasenkofc06f292007-02-23 21:09:35 +00003276
Denis Vlasenko131ae172007-02-18 13:00:19 +00003277#if ENABLE_ASH_ALIAS
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00003278
3279#define ALIASINUSE 1
3280#define ALIASDEAD 2
3281
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00003282struct alias {
3283 struct alias *next;
3284 char *name;
3285 char *val;
3286 int flag;
3287};
3288
Denis Vlasenko01631112007-12-16 17:20:38 +00003289
3290static struct alias **atab; // [ATABSIZE];
3291#define INIT_G_alias() do { \
3292 atab = xzalloc(ATABSIZE * sizeof(atab[0])); \
3293} while (0)
3294
Eric Andersen2870d962001-07-02 17:27:21 +00003295
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00003296static struct alias **
Denys Vlasenko37dc08b2016-10-02 04:38:07 +02003297__lookupalias(const char *name)
3298{
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00003299 unsigned int hashval;
3300 struct alias **app;
3301 const char *p;
3302 unsigned int ch;
3303
3304 p = name;
3305
3306 ch = (unsigned char)*p;
3307 hashval = ch << 4;
3308 while (ch) {
3309 hashval += ch;
3310 ch = (unsigned char)*++p;
3311 }
3312 app = &atab[hashval % ATABSIZE];
3313
3314 for (; *app; app = &(*app)->next) {
3315 if (strcmp(name, (*app)->name) == 0) {
3316 break;
3317 }
3318 }
3319
3320 return app;
3321}
3322
3323static struct alias *
3324lookupalias(const char *name, int check)
3325{
3326 struct alias *ap = *__lookupalias(name);
3327
3328 if (check && ap && (ap->flag & ALIASINUSE))
3329 return NULL;
3330 return ap;
3331}
3332
3333static struct alias *
3334freealias(struct alias *ap)
3335{
3336 struct alias *next;
3337
3338 if (ap->flag & ALIASINUSE) {
3339 ap->flag |= ALIASDEAD;
3340 return ap;
3341 }
3342
3343 next = ap->next;
3344 free(ap->name);
3345 free(ap->val);
3346 free(ap);
3347 return next;
3348}
Eric Andersencb57d552001-06-28 07:25:16 +00003349
Eric Andersenc470f442003-07-28 09:56:35 +00003350static void
3351setalias(const char *name, const char *val)
Eric Andersencb57d552001-06-28 07:25:16 +00003352{
3353 struct alias *ap, **app;
3354
3355 app = __lookupalias(name);
3356 ap = *app;
Denis Vlasenkob012b102007-02-19 22:43:01 +00003357 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +00003358 if (ap) {
3359 if (!(ap->flag & ALIASINUSE)) {
Denis Vlasenkob012b102007-02-19 22:43:01 +00003360 free(ap->val);
Eric Andersencb57d552001-06-28 07:25:16 +00003361 }
Denis Vlasenko0c032a42007-02-23 01:03:40 +00003362 ap->val = ckstrdup(val);
Eric Andersencb57d552001-06-28 07:25:16 +00003363 ap->flag &= ~ALIASDEAD;
3364 } else {
3365 /* not found */
Denis Vlasenko597906c2008-02-20 16:38:54 +00003366 ap = ckzalloc(sizeof(struct alias));
Denis Vlasenko0c032a42007-02-23 01:03:40 +00003367 ap->name = ckstrdup(name);
3368 ap->val = ckstrdup(val);
Denis Vlasenko597906c2008-02-20 16:38:54 +00003369 /*ap->flag = 0; - ckzalloc did it */
3370 /*ap->next = NULL;*/
Eric Andersencb57d552001-06-28 07:25:16 +00003371 *app = ap;
3372 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00003373 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +00003374}
3375
Eric Andersenc470f442003-07-28 09:56:35 +00003376static int
3377unalias(const char *name)
Eric Andersen2870d962001-07-02 17:27:21 +00003378{
Eric Andersencb57d552001-06-28 07:25:16 +00003379 struct alias **app;
3380
3381 app = __lookupalias(name);
3382
3383 if (*app) {
Denis Vlasenkob012b102007-02-19 22:43:01 +00003384 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +00003385 *app = freealias(*app);
Denis Vlasenkob012b102007-02-19 22:43:01 +00003386 INT_ON;
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003387 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003388 }
3389
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003390 return 1;
Eric Andersencb57d552001-06-28 07:25:16 +00003391}
3392
Eric Andersenc470f442003-07-28 09:56:35 +00003393static void
3394rmaliases(void)
Eric Andersen2870d962001-07-02 17:27:21 +00003395{
Eric Andersencb57d552001-06-28 07:25:16 +00003396 struct alias *ap, **app;
3397 int i;
3398
Denis Vlasenkob012b102007-02-19 22:43:01 +00003399 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +00003400 for (i = 0; i < ATABSIZE; i++) {
3401 app = &atab[i];
3402 for (ap = *app; ap; ap = *app) {
3403 *app = freealias(*app);
3404 if (ap == *app) {
3405 app = &ap->next;
3406 }
3407 }
3408 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00003409 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +00003410}
3411
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00003412static void
3413printalias(const struct alias *ap)
3414{
3415 out1fmt("%s=%s\n", ap->name, single_quote(ap->val));
3416}
3417
Eric Andersencb57d552001-06-28 07:25:16 +00003418/*
3419 * TODO - sort output
3420 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02003421static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003422aliascmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003423{
3424 char *n, *v;
3425 int ret = 0;
3426 struct alias *ap;
3427
Denis Vlasenko68404f12008-03-17 09:00:54 +00003428 if (!argv[1]) {
Eric Andersencb57d552001-06-28 07:25:16 +00003429 int i;
3430
Denis Vlasenko68404f12008-03-17 09:00:54 +00003431 for (i = 0; i < ATABSIZE; i++) {
Eric Andersencb57d552001-06-28 07:25:16 +00003432 for (ap = atab[i]; ap; ap = ap->next) {
3433 printalias(ap);
3434 }
Denis Vlasenko68404f12008-03-17 09:00:54 +00003435 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003436 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003437 }
3438 while ((n = *++argv) != NULL) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +00003439 v = strchr(n+1, '=');
3440 if (v == NULL) { /* n+1: funny ksh stuff */
3441 ap = *__lookupalias(n);
3442 if (ap == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00003443 fprintf(stderr, "%s: %s not found\n", "alias", n);
Eric Andersencb57d552001-06-28 07:25:16 +00003444 ret = 1;
3445 } else
3446 printalias(ap);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003447 } else {
Eric Andersencb57d552001-06-28 07:25:16 +00003448 *v++ = '\0';
3449 setalias(n, v);
3450 }
3451 }
3452
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003453 return ret;
Eric Andersencb57d552001-06-28 07:25:16 +00003454}
3455
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02003456static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003457unaliascmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +00003458{
3459 int i;
3460
Denys Vlasenko6c149f42017-04-12 21:31:32 +02003461 while (nextopt("a") != '\0') {
3462 rmaliases();
3463 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003464 }
3465 for (i = 0; *argptr; argptr++) {
3466 if (unalias(*argptr)) {
Eric Andersenc470f442003-07-28 09:56:35 +00003467 fprintf(stderr, "%s: %s not found\n", "unalias", *argptr);
Eric Andersencb57d552001-06-28 07:25:16 +00003468 i = 1;
3469 }
3470 }
3471
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003472 return i;
Eric Andersencb57d552001-06-28 07:25:16 +00003473}
Denis Vlasenkofc06f292007-02-23 21:09:35 +00003474
Denis Vlasenko131ae172007-02-18 13:00:19 +00003475#endif /* ASH_ALIAS */
Eric Andersencb57d552001-06-28 07:25:16 +00003476
Eric Andersenc470f442003-07-28 09:56:35 +00003477
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003478/* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */
Denys Vlasenko285ad152009-12-04 23:02:27 +01003479#define FORK_FG 0
3480#define FORK_BG 1
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003481#define FORK_NOJOB 2
3482
3483/* mode flags for showjob(s) */
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02003484#define SHOW_ONLY_PGID 0x01 /* show only pgid (jobs -p) */
3485#define SHOW_PIDS 0x02 /* show individual pids, not just one line per job */
3486#define SHOW_CHANGED 0x04 /* only jobs whose state has changed */
Denys Vlasenko9c541002015-10-07 15:44:36 +02003487#define SHOW_STDERR 0x08 /* print to stderr (else stdout) */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003488
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003489/*
3490 * A job structure contains information about a job. A job is either a
3491 * single process or a set of processes contained in a pipeline. In the
3492 * latter case, pidlist will be non-NULL, and will point to a -1 terminated
3493 * array of pids.
3494 */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003495struct procstat {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003496 pid_t ps_pid; /* process id */
3497 int ps_status; /* last process status from wait() */
3498 char *ps_cmd; /* text of command being run */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003499};
3500
3501struct job {
3502 struct procstat ps0; /* status of process */
3503 struct procstat *ps; /* status or processes when more than one */
3504#if JOBS
3505 int stopstatus; /* status of a stopped job */
3506#endif
Denys Vlasenko4c179372017-01-11 18:44:15 +01003507 unsigned nprocs; /* number of processes */
3508
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003509#define JOBRUNNING 0 /* at least one proc running */
3510#define JOBSTOPPED 1 /* all procs are stopped */
3511#define JOBDONE 2 /* all procs are completed */
Denys Vlasenko4c179372017-01-11 18:44:15 +01003512 unsigned
3513 state: 8,
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003514#if JOBS
3515 sigint: 1, /* job was killed by SIGINT */
3516 jobctl: 1, /* job running under job control */
3517#endif
3518 waited: 1, /* true if this entry has been waited for */
3519 used: 1, /* true if this entry is in used */
3520 changed: 1; /* true if status has changed */
3521 struct job *prev_job; /* previous job */
3522};
3523
Denis Vlasenko68404f12008-03-17 09:00:54 +00003524static struct job *makejob(/*union node *,*/ int);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003525static int forkshell(struct job *, union node *, int);
3526static int waitforjob(struct job *);
3527
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00003528#if !JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +00003529enum { doing_jobctl = 0 };
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00003530#define setjobctl(on) do {} while (0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003531#else
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003532static smallint doing_jobctl; //references:8
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003533static void setjobctl(int);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003534#endif
3535
3536/*
Denis Vlasenko4b875702009-03-19 13:30:04 +00003537 * Ignore a signal.
3538 */
3539static void
3540ignoresig(int signo)
3541{
3542 /* Avoid unnecessary system calls. Is it already SIG_IGNed? */
3543 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
3544 /* No, need to do it */
3545 signal(signo, SIG_IGN);
3546 }
3547 sigmode[signo - 1] = S_HARD_IGN;
3548}
3549
3550/*
Denys Vlasenko238bf182010-05-18 15:49:07 +02003551 * Only one usage site - in setsignal()
Denis Vlasenko4b875702009-03-19 13:30:04 +00003552 */
3553static void
Denys Vlasenko238bf182010-05-18 15:49:07 +02003554signal_handler(int signo)
Denis Vlasenko4b875702009-03-19 13:30:04 +00003555{
Denys Vlasenko458c1f22016-10-27 23:51:19 +02003556 if (signo == SIGCHLD) {
3557 got_sigchld = 1;
3558 if (!trap[SIGCHLD])
3559 return;
3560 }
3561
Denis Vlasenko4b875702009-03-19 13:30:04 +00003562 gotsig[signo - 1] = 1;
Denys Vlasenko458c1f22016-10-27 23:51:19 +02003563 pending_sig = signo;
Denis Vlasenko4b875702009-03-19 13:30:04 +00003564
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02003565 if (signo == SIGINT && !trap[SIGINT]) {
3566 if (!suppress_int) {
3567 pending_sig = 0;
Denis Vlasenko4b875702009-03-19 13:30:04 +00003568 raise_interrupt(); /* does not return */
3569 }
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02003570 pending_int = 1;
Denis Vlasenko4b875702009-03-19 13:30:04 +00003571 }
3572}
3573
3574/*
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003575 * Set the signal handler for the specified signal. The routine figures
3576 * out what it should be set to.
3577 */
3578static void
3579setsignal(int signo)
3580{
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003581 char *t;
3582 char cur_act, new_act;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003583 struct sigaction act;
3584
3585 t = trap[signo];
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003586 new_act = S_DFL;
3587 if (t != NULL) { /* trap for this sig is set */
3588 new_act = S_CATCH;
3589 if (t[0] == '\0') /* trap is "": ignore this sig */
3590 new_act = S_IGN;
3591 }
3592
3593 if (rootshell && new_act == S_DFL) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003594 switch (signo) {
3595 case SIGINT:
3596 if (iflag || minusc || sflag == 0)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003597 new_act = S_CATCH;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003598 break;
3599 case SIGQUIT:
3600#if DEBUG
3601 if (debug)
3602 break;
3603#endif
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003604 /* man bash:
3605 * "In all cases, bash ignores SIGQUIT. Non-builtin
3606 * commands run by bash have signal handlers
3607 * set to the values inherited by the shell
3608 * from its parent". */
3609 new_act = S_IGN;
3610 break;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003611 case SIGTERM:
3612 if (iflag)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003613 new_act = S_IGN;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003614 break;
3615#if JOBS
3616 case SIGTSTP:
3617 case SIGTTOU:
3618 if (mflag)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003619 new_act = S_IGN;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003620 break;
3621#endif
3622 }
3623 }
Denys Vlasenko49e6bf22017-08-04 14:28:16 +02003624 /* if !rootshell, we reset SIGQUIT to DFL,
3625 * whereas we have to restore it to what shell got on entry.
3626 * This is handled by the fact that if signal was IGNored on entry,
3627 * then cur_act is S_HARD_IGN and we never change its sigaction
3628 * (see code below).
3629 */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003630
Denys Vlasenko458c1f22016-10-27 23:51:19 +02003631 if (signo == SIGCHLD)
3632 new_act = S_CATCH;
3633
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003634 t = &sigmode[signo - 1];
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003635 cur_act = *t;
3636 if (cur_act == 0) {
3637 /* current setting is not yet known */
3638 if (sigaction(signo, NULL, &act)) {
3639 /* pretend it worked; maybe we should give a warning,
3640 * but other shells don't. We don't alter sigmode,
3641 * so we retry every time.
3642 * btw, in Linux it never fails. --vda */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003643 return;
3644 }
3645 if (act.sa_handler == SIG_IGN) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003646 cur_act = S_HARD_IGN;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003647 if (mflag
3648 && (signo == SIGTSTP || signo == SIGTTIN || signo == SIGTTOU)
3649 ) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003650 cur_act = S_IGN; /* don't hard ignore these */
Denis Vlasenko991a1da2008-02-10 19:02:53 +00003651 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003652 }
Denys Vlasenko0f14f412017-08-06 20:06:19 +02003653 if (act.sa_handler == SIG_DFL && new_act == S_DFL) {
3654 /* installing SIG_DFL over SIG_DFL is a no-op */
3655 /* saves one sigaction call in each "sh -c SCRIPT" invocation */
3656 *t = S_DFL;
3657 return;
3658 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003659 }
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003660 if (cur_act == S_HARD_IGN || cur_act == new_act)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003661 return;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003662
Denys Vlasenko49e6bf22017-08-04 14:28:16 +02003663 *t = new_act;
3664
Denis Vlasenko991a1da2008-02-10 19:02:53 +00003665 act.sa_handler = SIG_DFL;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003666 switch (new_act) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003667 case S_CATCH:
Denys Vlasenko238bf182010-05-18 15:49:07 +02003668 act.sa_handler = signal_handler;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003669 break;
3670 case S_IGN:
3671 act.sa_handler = SIG_IGN;
3672 break;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003673 }
Ian Wienand89b3cba2011-04-16 20:05:14 +02003674 /* flags and mask matter only if !DFL and !IGN, but we do it
3675 * for all cases for more deterministic behavior:
3676 */
Denys Vlasenko49e6bf22017-08-04 14:28:16 +02003677 act.sa_flags = 0; //TODO: why not SA_RESTART?
Ian Wienand89b3cba2011-04-16 20:05:14 +02003678 sigfillset(&act.sa_mask);
3679
Denis Vlasenko8e2cfec2008-03-12 23:19:35 +00003680 sigaction_set(signo, &act);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003681}
3682
3683/* mode flags for set_curjob */
3684#define CUR_DELETE 2
3685#define CUR_RUNNING 1
3686#define CUR_STOPPED 0
3687
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003688#if JOBS
3689/* pgrp of shell on invocation */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003690static int initialpgrp; //references:2
3691static int ttyfd = -1; //5
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003692#endif
3693/* array of jobs */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003694static struct job *jobtab; //5
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003695/* size of array */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003696static unsigned njobs; //4
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003697/* current job */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003698static struct job *curjob; //lots
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003699/* number of presumed living untracked jobs */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003700static int jobless; //4
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003701
Denys Vlasenko098b7132017-01-11 19:59:03 +01003702#if 0
3703/* Bash has a feature: it restores termios after a successful wait for
3704 * a foreground job which had at least one stopped or sigkilled member.
3705 * The probable rationale is that SIGSTOP and SIGKILL can preclude task from
3706 * properly restoring tty state. Should we do this too?
3707 * A reproducer: ^Z an interactive python:
3708 *
3709 * # python
3710 * Python 2.7.12 (...)
3711 * >>> ^Z
3712 * { python leaves tty in -icanon -echo state. We do survive that... }
3713 * [1]+ Stopped python
3714 * { ...however, next program (python #2) does not survive it well: }
3715 * # python
3716 * Python 2.7.12 (...)
3717 * >>> Traceback (most recent call last):
3718 * { above, I typed "qwerty<CR>", but -echo state is still in effect }
3719 * File "<stdin>", line 1, in <module>
3720 * NameError: name 'qwerty' is not defined
3721 *
3722 * The implementation below is modeled on bash code and seems to work.
3723 * However, I'm not sure we should do this. For one: what if I'd fg
3724 * the stopped python instead? It'll be confused by "restored" tty state.
3725 */
3726static struct termios shell_tty_info;
3727static void
3728get_tty_state(void)
3729{
3730 if (rootshell && ttyfd >= 0)
3731 tcgetattr(ttyfd, &shell_tty_info);
3732}
3733static void
3734set_tty_state(void)
3735{
3736 /* if (rootshell) - caller ensures this */
3737 if (ttyfd >= 0)
3738 tcsetattr(ttyfd, TCSADRAIN, &shell_tty_info);
3739}
3740static int
3741job_signal_status(struct job *jp)
3742{
3743 int status;
3744 unsigned i;
3745 struct procstat *ps = jp->ps;
3746 for (i = 0; i < jp->nprocs; i++) {
3747 status = ps[i].ps_status;
3748 if (WIFSIGNALED(status) || WIFSTOPPED(status))
3749 return status;
3750 }
3751 return 0;
3752}
3753static void
3754restore_tty_if_stopped_or_signaled(struct job *jp)
3755{
3756//TODO: check what happens if we come from waitforjob() in expbackq()
3757 if (rootshell) {
3758 int s = job_signal_status(jp);
3759 if (s) /* WIFSIGNALED(s) || WIFSTOPPED(s) */
3760 set_tty_state();
3761 }
3762}
3763#else
3764# define get_tty_state() ((void)0)
3765# define restore_tty_if_stopped_or_signaled(jp) ((void)0)
3766#endif
3767
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003768static void
3769set_curjob(struct job *jp, unsigned mode)
3770{
3771 struct job *jp1;
3772 struct job **jpp, **curp;
3773
3774 /* first remove from list */
3775 jpp = curp = &curjob;
Denys Vlasenko940c7202011-03-02 04:07:14 +01003776 while (1) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003777 jp1 = *jpp;
3778 if (jp1 == jp)
3779 break;
3780 jpp = &jp1->prev_job;
Denys Vlasenko940c7202011-03-02 04:07:14 +01003781 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003782 *jpp = jp1->prev_job;
3783
3784 /* Then re-insert in correct position */
3785 jpp = curp;
3786 switch (mode) {
3787 default:
3788#if DEBUG
3789 abort();
3790#endif
3791 case CUR_DELETE:
3792 /* job being deleted */
3793 break;
3794 case CUR_RUNNING:
3795 /* newly created job or backgrounded job,
Denys Vlasenko60cb48c2013-01-14 15:57:44 +01003796 * put after all stopped jobs.
3797 */
Denys Vlasenko940c7202011-03-02 04:07:14 +01003798 while (1) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003799 jp1 = *jpp;
3800#if JOBS
3801 if (!jp1 || jp1->state != JOBSTOPPED)
3802#endif
3803 break;
3804 jpp = &jp1->prev_job;
Denys Vlasenko940c7202011-03-02 04:07:14 +01003805 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003806 /* FALLTHROUGH */
3807#if JOBS
3808 case CUR_STOPPED:
3809#endif
3810 /* newly stopped job - becomes curjob */
3811 jp->prev_job = *jpp;
3812 *jpp = jp;
3813 break;
3814 }
3815}
3816
3817#if JOBS || DEBUG
3818static int
3819jobno(const struct job *jp)
3820{
3821 return jp - jobtab + 1;
3822}
3823#endif
3824
3825/*
3826 * Convert a job name to a job structure.
3827 */
Denis Vlasenko85c24712008-03-17 09:04:04 +00003828#if !JOBS
3829#define getjob(name, getctl) getjob(name)
3830#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003831static struct job *
3832getjob(const char *name, int getctl)
3833{
3834 struct job *jp;
3835 struct job *found;
Denys Vlasenkoffc39202009-08-17 02:12:20 +02003836 const char *err_msg = "%s: no such job";
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003837 unsigned num;
3838 int c;
3839 const char *p;
3840 char *(*match)(const char *, const char *);
3841
3842 jp = curjob;
3843 p = name;
3844 if (!p)
3845 goto currentjob;
3846
3847 if (*p != '%')
3848 goto err;
3849
3850 c = *++p;
3851 if (!c)
3852 goto currentjob;
3853
3854 if (!p[1]) {
3855 if (c == '+' || c == '%') {
3856 currentjob:
3857 err_msg = "No current job";
3858 goto check;
3859 }
3860 if (c == '-') {
3861 if (jp)
3862 jp = jp->prev_job;
3863 err_msg = "No previous job";
3864 check:
3865 if (!jp)
3866 goto err;
3867 goto gotit;
3868 }
3869 }
3870
3871 if (is_number(p)) {
3872 num = atoi(p);
Denys Vlasenko46a45ce2016-09-29 01:10:08 +02003873 if (num > 0 && num <= njobs) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003874 jp = jobtab + num - 1;
3875 if (jp->used)
3876 goto gotit;
3877 goto err;
3878 }
3879 }
3880
3881 match = prefix;
3882 if (*p == '?') {
3883 match = strstr;
3884 p++;
3885 }
3886
Denys Vlasenkoffc39202009-08-17 02:12:20 +02003887 found = NULL;
3888 while (jp) {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003889 if (match(jp->ps[0].ps_cmd, p)) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003890 if (found)
3891 goto err;
3892 found = jp;
3893 err_msg = "%s: ambiguous";
3894 }
3895 jp = jp->prev_job;
3896 }
Denys Vlasenkoffc39202009-08-17 02:12:20 +02003897 if (!found)
3898 goto err;
3899 jp = found;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003900
3901 gotit:
3902#if JOBS
3903 err_msg = "job %s not created under job control";
3904 if (getctl && jp->jobctl == 0)
3905 goto err;
3906#endif
3907 return jp;
3908 err:
3909 ash_msg_and_raise_error(err_msg, name);
3910}
3911
3912/*
3913 * Mark a job structure as unused.
3914 */
3915static void
3916freejob(struct job *jp)
3917{
3918 struct procstat *ps;
3919 int i;
3920
3921 INT_OFF;
3922 for (i = jp->nprocs, ps = jp->ps; --i >= 0; ps++) {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003923 if (ps->ps_cmd != nullstr)
3924 free(ps->ps_cmd);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003925 }
3926 if (jp->ps != &jp->ps0)
3927 free(jp->ps);
3928 jp->used = 0;
3929 set_curjob(jp, CUR_DELETE);
3930 INT_ON;
3931}
3932
3933#if JOBS
3934static void
3935xtcsetpgrp(int fd, pid_t pgrp)
3936{
3937 if (tcsetpgrp(fd, pgrp))
Ron Yorstonbe366e52017-07-27 13:53:39 +01003938 ash_msg_and_raise_perror("can't set tty process group");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003939}
3940
3941/*
3942 * Turn job control on and off.
3943 *
3944 * Note: This code assumes that the third arg to ioctl is a character
3945 * pointer, which is true on Berkeley systems but not System V. Since
3946 * System V doesn't have job control yet, this isn't a problem now.
3947 *
3948 * Called with interrupts off.
3949 */
3950static void
3951setjobctl(int on)
3952{
3953 int fd;
3954 int pgrp;
3955
Denis Vlasenkob07a4962008-06-22 13:16:23 +00003956 if (on == doing_jobctl || rootshell == 0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003957 return;
3958 if (on) {
3959 int ofd;
3960 ofd = fd = open(_PATH_TTY, O_RDWR);
3961 if (fd < 0) {
3962 /* BTW, bash will try to open(ttyname(0)) if open("/dev/tty") fails.
3963 * That sometimes helps to acquire controlling tty.
3964 * Obviously, a workaround for bugs when someone
3965 * failed to provide a controlling tty to bash! :) */
Denis Vlasenkoed270a52007-11-26 05:37:07 +00003966 fd = 2;
3967 while (!isatty(fd))
3968 if (--fd < 0)
3969 goto out;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003970 }
Denys Vlasenko64774602016-10-26 15:24:30 +02003971 /* fd is a tty at this point */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003972 fd = fcntl(fd, F_DUPFD, 10);
Denys Vlasenko10ad6222017-04-17 16:13:32 +02003973 if (ofd >= 0) /* if it is "/dev/tty", close. If 0/1/2, don't */
Denis Vlasenkoed270a52007-11-26 05:37:07 +00003974 close(ofd);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003975 if (fd < 0)
Denys Vlasenko64774602016-10-26 15:24:30 +02003976 goto out; /* F_DUPFD failed */
Denis Vlasenko96e1b382007-09-30 23:50:48 +00003977 close_on_exec_on(fd);
Denys Vlasenko940c7202011-03-02 04:07:14 +01003978 while (1) { /* while we are in the background */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003979 pgrp = tcgetpgrp(fd);
3980 if (pgrp < 0) {
3981 out:
3982 ash_msg("can't access tty; job control turned off");
3983 mflag = on = 0;
3984 goto close;
3985 }
3986 if (pgrp == getpgrp())
3987 break;
3988 killpg(0, SIGTTIN);
Denys Vlasenko940c7202011-03-02 04:07:14 +01003989 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003990 initialpgrp = pgrp;
3991
3992 setsignal(SIGTSTP);
3993 setsignal(SIGTTOU);
3994 setsignal(SIGTTIN);
3995 pgrp = rootpid;
3996 setpgid(0, pgrp);
3997 xtcsetpgrp(fd, pgrp);
3998 } else {
3999 /* turning job control off */
4000 fd = ttyfd;
4001 pgrp = initialpgrp;
Denis Vlasenko08c8c1d2007-04-28 22:39:02 +00004002 /* was xtcsetpgrp, but this can make exiting ash
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004003 * loop forever if pty is already deleted */
Denis Vlasenko08c8c1d2007-04-28 22:39:02 +00004004 tcsetpgrp(fd, pgrp);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004005 setpgid(0, pgrp);
4006 setsignal(SIGTSTP);
4007 setsignal(SIGTTOU);
4008 setsignal(SIGTTIN);
4009 close:
Denis Vlasenkoed270a52007-11-26 05:37:07 +00004010 if (fd >= 0)
4011 close(fd);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004012 fd = -1;
4013 }
4014 ttyfd = fd;
Denis Vlasenkob07a4962008-06-22 13:16:23 +00004015 doing_jobctl = on;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004016}
4017
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02004018static int FAST_FUNC
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004019killcmd(int argc, char **argv)
4020{
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00004021 if (argv[1] && strcmp(argv[1], "-l") != 0) {
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004022 int i = 1;
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00004023 do {
4024 if (argv[i][0] == '%') {
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004025 /*
4026 * "kill %N" - job kill
4027 * Converting to pgrp / pid kill
4028 */
4029 struct job *jp;
4030 char *dst;
4031 int j, n;
4032
4033 jp = getjob(argv[i], 0);
4034 /*
4035 * In jobs started under job control, we signal
4036 * entire process group by kill -PGRP_ID.
4037 * This happens, f.e., in interactive shell.
4038 *
4039 * Otherwise, we signal each child via
4040 * kill PID1 PID2 PID3.
4041 * Testcases:
4042 * sh -c 'sleep 1|sleep 1 & kill %1'
4043 * sh -c 'true|sleep 2 & sleep 1; kill %1'
4044 * sh -c 'true|sleep 1 & sleep 2; kill %1'
4045 */
4046 n = jp->nprocs; /* can't be 0 (I hope) */
4047 if (jp->jobctl)
4048 n = 1;
4049 dst = alloca(n * sizeof(int)*4);
4050 argv[i] = dst;
4051 for (j = 0; j < n; j++) {
4052 struct procstat *ps = &jp->ps[j];
4053 /* Skip non-running and not-stopped members
4054 * (i.e. dead members) of the job
4055 */
4056 if (ps->ps_status != -1 && !WIFSTOPPED(ps->ps_status))
4057 continue;
4058 /*
4059 * kill_main has matching code to expect
4060 * leading space. Needed to not confuse
4061 * negative pids with "kill -SIGNAL_NO" syntax
4062 */
4063 dst += sprintf(dst, jp->jobctl ? " -%u" : " %u", (int)ps->ps_pid);
4064 }
4065 *dst = '\0';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004066 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00004067 } while (argv[++i]);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004068 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00004069 return kill_main(argc, argv);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004070}
4071
4072static void
Denys Vlasenko285ad152009-12-04 23:02:27 +01004073showpipe(struct job *jp /*, FILE *out*/)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004074{
Denys Vlasenko285ad152009-12-04 23:02:27 +01004075 struct procstat *ps;
4076 struct procstat *psend;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004077
Denys Vlasenko285ad152009-12-04 23:02:27 +01004078 psend = jp->ps + jp->nprocs;
4079 for (ps = jp->ps + 1; ps < psend; ps++)
4080 printf(" | %s", ps->ps_cmd);
Denys Vlasenko9c541002015-10-07 15:44:36 +02004081 newline_and_flush(stdout);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004082 flush_stdout_stderr();
4083}
4084
4085
4086static int
4087restartjob(struct job *jp, int mode)
4088{
4089 struct procstat *ps;
4090 int i;
4091 int status;
4092 pid_t pgid;
4093
4094 INT_OFF;
4095 if (jp->state == JOBDONE)
4096 goto out;
4097 jp->state = JOBRUNNING;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004098 pgid = jp->ps[0].ps_pid;
Denys Vlasenko098b7132017-01-11 19:59:03 +01004099 if (mode == FORK_FG) {
4100 get_tty_state();
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004101 xtcsetpgrp(ttyfd, pgid);
Denys Vlasenko098b7132017-01-11 19:59:03 +01004102 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004103 killpg(pgid, SIGCONT);
4104 ps = jp->ps;
4105 i = jp->nprocs;
4106 do {
Denys Vlasenko285ad152009-12-04 23:02:27 +01004107 if (WIFSTOPPED(ps->ps_status)) {
4108 ps->ps_status = -1;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004109 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00004110 ps++;
4111 } while (--i);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004112 out:
4113 status = (mode == FORK_FG) ? waitforjob(jp) : 0;
4114 INT_ON;
4115 return status;
4116}
4117
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02004118static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00004119fg_bgcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004120{
4121 struct job *jp;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004122 int mode;
4123 int retval;
4124
4125 mode = (**argv == 'f') ? FORK_FG : FORK_BG;
4126 nextopt(nullstr);
4127 argv = argptr;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004128 do {
4129 jp = getjob(*argv, 1);
4130 if (mode == FORK_BG) {
4131 set_curjob(jp, CUR_RUNNING);
Denys Vlasenko285ad152009-12-04 23:02:27 +01004132 printf("[%d] ", jobno(jp));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004133 }
Denys Vlasenko285ad152009-12-04 23:02:27 +01004134 out1str(jp->ps[0].ps_cmd);
4135 showpipe(jp /*, stdout*/);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004136 retval = restartjob(jp, mode);
4137 } while (*argv && *++argv);
4138 return retval;
4139}
4140#endif
4141
4142static int
Denys Vlasenko9c541002015-10-07 15:44:36 +02004143sprint_status48(char *s, int status, int sigonly)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004144{
4145 int col;
4146 int st;
4147
4148 col = 0;
4149 if (!WIFEXITED(status)) {
Johannes Schindelin9d4dc842017-07-14 22:25:58 +02004150#if JOBS
4151 if (WIFSTOPPED(status))
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004152 st = WSTOPSIG(status);
4153 else
Johannes Schindelin9d4dc842017-07-14 22:25:58 +02004154#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004155 st = WTERMSIG(status);
4156 if (sigonly) {
4157 if (st == SIGINT || st == SIGPIPE)
4158 goto out;
Johannes Schindelin9d4dc842017-07-14 22:25:58 +02004159#if JOBS
4160 if (WIFSTOPPED(status))
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004161 goto out;
Johannes Schindelin9d4dc842017-07-14 22:25:58 +02004162#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004163 }
4164 st &= 0x7f;
Denys Vlasenko7c6f2462011-02-14 17:17:10 +01004165//TODO: use bbox's get_signame? strsignal adds ~600 bytes to text+rodata
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004166 col = fmtstr(s, 32, strsignal(st));
4167 if (WCOREDUMP(status)) {
Denys Vlasenko9c541002015-10-07 15:44:36 +02004168 strcpy(s + col, " (core dumped)");
4169 col += sizeof(" (core dumped)")-1;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004170 }
4171 } else if (!sigonly) {
4172 st = WEXITSTATUS(status);
Denys Vlasenko9c541002015-10-07 15:44:36 +02004173 col = fmtstr(s, 16, (st ? "Done(%d)" : "Done"), st);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004174 }
4175 out:
4176 return col;
4177}
4178
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004179static int
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004180wait_block_or_sig(int *status)
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004181{
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004182 int pid;
4183
4184 do {
Denys Vlasenko1ab7c2f2016-11-03 20:17:23 +01004185 sigset_t mask;
4186
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004187 /* Poll all children for changes in their state */
4188 got_sigchld = 0;
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004189 /* if job control is active, accept stopped processes too */
4190 pid = waitpid(-1, status, doing_jobctl ? (WNOHANG|WUNTRACED) : WNOHANG);
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004191 if (pid != 0)
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004192 break; /* Error (e.g. EINTR, ECHILD) or pid */
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004193
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004194 /* Children exist, but none are ready. Sleep until interesting signal */
Denys Vlasenko1ab7c2f2016-11-03 20:17:23 +01004195#if 1
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004196 sigfillset(&mask);
4197 sigprocmask(SIG_SETMASK, &mask, &mask);
4198 while (!got_sigchld && !pending_sig)
4199 sigsuspend(&mask);
4200 sigprocmask(SIG_SETMASK, &mask, NULL);
Denys Vlasenko1ab7c2f2016-11-03 20:17:23 +01004201#else /* unsafe: a signal can set pending_sig after check, but before pause() */
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004202 while (!got_sigchld && !pending_sig)
4203 pause();
4204#endif
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004205
4206 /* If it was SIGCHLD, poll children again */
4207 } while (got_sigchld);
4208
4209 return pid;
4210}
4211
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004212#define DOWAIT_NONBLOCK 0
4213#define DOWAIT_BLOCK 1
4214#define DOWAIT_BLOCK_OR_SIG 2
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004215
4216static int
Denys Vlasenkob543bda2016-10-27 20:08:28 +02004217dowait(int block, struct job *job)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004218{
4219 int pid;
4220 int status;
4221 struct job *jp;
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004222 struct job *thisjob = NULL;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004223
Denys Vlasenkob543bda2016-10-27 20:08:28 +02004224 TRACE(("dowait(0x%x) called\n", block));
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +00004225
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004226 /* It's wrong to call waitpid() outside of INT_OFF region:
4227 * signal can arrive just after syscall return and handler can
4228 * longjmp away, losing stop/exit notification processing.
4229 * Thus, for "jobs" builtin, and for waiting for a fg job,
4230 * we call waitpid() (blocking or non-blocking) inside INT_OFF.
4231 *
4232 * However, for "wait" builtin it is wrong to simply call waitpid()
4233 * in INT_OFF region: "wait" needs to wait for any running job
4234 * to change state, but should exit on any trap too.
4235 * In INT_OFF region, a signal just before syscall entry can set
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004236 * pending_sig variables, but we can't check them, and we would
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004237 * either enter a sleeping waitpid() (BUG), or need to busy-loop.
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004238 *
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004239 * Because of this, we run inside INT_OFF, but use a special routine
Denys Vlasenko1ab7c2f2016-11-03 20:17:23 +01004240 * which combines waitpid() and sigsuspend().
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004241 * This is the reason why we need to have a handler for SIGCHLD:
Denys Vlasenko1ab7c2f2016-11-03 20:17:23 +01004242 * SIG_DFL handler does not wake sigsuspend().
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004243 */
4244 INT_OFF;
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004245 if (block == DOWAIT_BLOCK_OR_SIG) {
4246 pid = wait_block_or_sig(&status);
4247 } else {
4248 int wait_flags = 0;
4249 if (block == DOWAIT_NONBLOCK)
4250 wait_flags = WNOHANG;
4251 /* if job control is active, accept stopped processes too */
4252 if (doing_jobctl)
4253 wait_flags |= WUNTRACED;
4254 /* NB: _not_ safe_waitpid, we need to detect EINTR */
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004255 pid = waitpid(-1, &status, wait_flags);
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004256 }
Denis Vlasenkob21f3792009-03-19 23:09:58 +00004257 TRACE(("wait returns pid=%d, status=0x%x, errno=%d(%s)\n",
4258 pid, status, errno, strerror(errno)));
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004259 if (pid <= 0)
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004260 goto out;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004261
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004262 thisjob = NULL;
4263 for (jp = curjob; jp; jp = jp->prev_job) {
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004264 int jobstate;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004265 struct procstat *ps;
4266 struct procstat *psend;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004267 if (jp->state == JOBDONE)
4268 continue;
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004269 jobstate = JOBDONE;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004270 ps = jp->ps;
4271 psend = ps + jp->nprocs;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004272 do {
Denys Vlasenko285ad152009-12-04 23:02:27 +01004273 if (ps->ps_pid == pid) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004274 TRACE(("Job %d: changing status of proc %d "
4275 "from 0x%x to 0x%x\n",
Denys Vlasenko285ad152009-12-04 23:02:27 +01004276 jobno(jp), pid, ps->ps_status, status));
4277 ps->ps_status = status;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004278 thisjob = jp;
4279 }
Denys Vlasenko285ad152009-12-04 23:02:27 +01004280 if (ps->ps_status == -1)
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004281 jobstate = JOBRUNNING;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004282#if JOBS
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004283 if (jobstate == JOBRUNNING)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004284 continue;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004285 if (WIFSTOPPED(ps->ps_status)) {
4286 jp->stopstatus = ps->ps_status;
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004287 jobstate = JOBSTOPPED;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004288 }
4289#endif
Denys Vlasenko285ad152009-12-04 23:02:27 +01004290 } while (++ps < psend);
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004291 if (!thisjob)
4292 continue;
4293
4294 /* Found the job where one of its processes changed its state.
4295 * Is there at least one live and running process in this job? */
4296 if (jobstate != JOBRUNNING) {
4297 /* No. All live processes in the job are stopped
4298 * (JOBSTOPPED) or there are no live processes (JOBDONE)
4299 */
4300 thisjob->changed = 1;
4301 if (thisjob->state != jobstate) {
4302 TRACE(("Job %d: changing state from %d to %d\n",
4303 jobno(thisjob), thisjob->state, jobstate));
4304 thisjob->state = jobstate;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004305#if JOBS
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004306 if (jobstate == JOBSTOPPED)
4307 set_curjob(thisjob, CUR_STOPPED);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004308#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004309 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004310 }
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004311 goto out;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004312 }
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004313 /* The process wasn't found in job list */
Johannes Schindelin9d4dc842017-07-14 22:25:58 +02004314#if JOBS
4315 if (!WIFSTOPPED(status))
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004316 jobless--;
Johannes Schindelin9d4dc842017-07-14 22:25:58 +02004317#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004318 out:
4319 INT_ON;
4320
4321 if (thisjob && thisjob == job) {
4322 char s[48 + 1];
4323 int len;
4324
Denys Vlasenko9c541002015-10-07 15:44:36 +02004325 len = sprint_status48(s, status, 1);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004326 if (len) {
4327 s[len] = '\n';
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004328 s[len + 1] = '\0';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004329 out2str(s);
4330 }
4331 }
4332 return pid;
4333}
4334
4335#if JOBS
4336static void
Denys Vlasenko9c541002015-10-07 15:44:36 +02004337showjob(struct job *jp, int mode)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004338{
4339 struct procstat *ps;
4340 struct procstat *psend;
4341 int col;
Denis Vlasenko40ba9982007-07-14 00:48:29 +00004342 int indent_col;
Denys Vlasenko9c541002015-10-07 15:44:36 +02004343 char s[16 + 16 + 48];
4344 FILE *out = (mode & SHOW_STDERR ? stderr : stdout);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004345
4346 ps = jp->ps;
4347
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004348 if (mode & SHOW_ONLY_PGID) { /* jobs -p */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004349 /* just output process (group) id of pipeline */
Denys Vlasenko285ad152009-12-04 23:02:27 +01004350 fprintf(out, "%d\n", ps->ps_pid);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004351 return;
4352 }
4353
4354 col = fmtstr(s, 16, "[%d] ", jobno(jp));
Denis Vlasenko40ba9982007-07-14 00:48:29 +00004355 indent_col = col;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004356
4357 if (jp == curjob)
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004358 s[col - 3] = '+';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004359 else if (curjob && jp == curjob->prev_job)
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004360 s[col - 3] = '-';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004361
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004362 if (mode & SHOW_PIDS)
Denys Vlasenko285ad152009-12-04 23:02:27 +01004363 col += fmtstr(s + col, 16, "%d ", ps->ps_pid);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004364
4365 psend = ps + jp->nprocs;
4366
4367 if (jp->state == JOBRUNNING) {
4368 strcpy(s + col, "Running");
4369 col += sizeof("Running") - 1;
4370 } else {
Denys Vlasenko285ad152009-12-04 23:02:27 +01004371 int status = psend[-1].ps_status;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004372 if (jp->state == JOBSTOPPED)
4373 status = jp->stopstatus;
Denys Vlasenko9c541002015-10-07 15:44:36 +02004374 col += sprint_status48(s + col, status, 0);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004375 }
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004376 /* By now, "[JOBID]* [maybe PID] STATUS" is printed */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004377
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004378 /* This loop either prints "<cmd1> | <cmd2> | <cmd3>" line
4379 * or prints several "PID | <cmdN>" lines,
4380 * depending on SHOW_PIDS bit.
4381 * We do not print status of individual processes
4382 * between PID and <cmdN>. bash does it, but not very well:
4383 * first line shows overall job status, not process status,
4384 * making it impossible to know 1st process status.
4385 */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004386 goto start;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004387 do {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004388 /* for each process */
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004389 s[0] = '\0';
4390 col = 33;
4391 if (mode & SHOW_PIDS)
Denys Vlasenko285ad152009-12-04 23:02:27 +01004392 col = fmtstr(s, 48, "\n%*c%d ", indent_col, ' ', ps->ps_pid) - 1;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004393 start:
Denys Vlasenko285ad152009-12-04 23:02:27 +01004394 fprintf(out, "%s%*c%s%s",
4395 s,
4396 33 - col >= 0 ? 33 - col : 0, ' ',
4397 ps == jp->ps ? "" : "| ",
4398 ps->ps_cmd
4399 );
4400 } while (++ps != psend);
Denys Vlasenko9c541002015-10-07 15:44:36 +02004401 newline_and_flush(out);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004402
4403 jp->changed = 0;
4404
4405 if (jp->state == JOBDONE) {
4406 TRACE(("showjob: freeing job %d\n", jobno(jp)));
4407 freejob(jp);
4408 }
4409}
4410
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004411/*
4412 * Print a list of jobs. If "change" is nonzero, only print jobs whose
4413 * statuses have changed since the last call to showjobs.
4414 */
4415static void
Denys Vlasenko9c541002015-10-07 15:44:36 +02004416showjobs(int mode)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004417{
4418 struct job *jp;
4419
Denys Vlasenko883cea42009-07-11 15:31:59 +02004420 TRACE(("showjobs(0x%x) called\n", mode));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004421
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004422 /* Handle all finished jobs */
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004423 while (dowait(DOWAIT_NONBLOCK, NULL) > 0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004424 continue;
4425
4426 for (jp = curjob; jp; jp = jp->prev_job) {
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004427 if (!(mode & SHOW_CHANGED) || jp->changed) {
Denys Vlasenko9c541002015-10-07 15:44:36 +02004428 showjob(jp, mode);
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004429 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004430 }
4431}
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004432
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02004433static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00004434jobscmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004435{
4436 int mode, m;
4437
4438 mode = 0;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02004439 while ((m = nextopt("lp")) != '\0') {
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004440 if (m == 'l')
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004441 mode |= SHOW_PIDS;
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004442 else
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004443 mode |= SHOW_ONLY_PGID;
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004444 }
4445
4446 argv = argptr;
4447 if (*argv) {
4448 do
Denys Vlasenko9c541002015-10-07 15:44:36 +02004449 showjob(getjob(*argv, 0), mode);
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004450 while (*++argv);
Denys Vlasenko285ad152009-12-04 23:02:27 +01004451 } else {
Denys Vlasenko9c541002015-10-07 15:44:36 +02004452 showjobs(mode);
Denys Vlasenko285ad152009-12-04 23:02:27 +01004453 }
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004454
4455 return 0;
4456}
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004457#endif /* JOBS */
4458
Michael Abbott359da5e2009-12-04 23:03:29 +01004459/* Called only on finished or stopped jobs (no members are running) */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004460static int
4461getstatus(struct job *job)
4462{
4463 int status;
4464 int retval;
Michael Abbott359da5e2009-12-04 23:03:29 +01004465 struct procstat *ps;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004466
Michael Abbott359da5e2009-12-04 23:03:29 +01004467 /* Fetch last member's status */
4468 ps = job->ps + job->nprocs - 1;
4469 status = ps->ps_status;
4470 if (pipefail) {
4471 /* "set -o pipefail" mode: use last _nonzero_ status */
4472 while (status == 0 && --ps >= job->ps)
4473 status = ps->ps_status;
4474 }
4475
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004476 retval = WEXITSTATUS(status);
4477 if (!WIFEXITED(status)) {
4478#if JOBS
4479 retval = WSTOPSIG(status);
4480 if (!WIFSTOPPED(status))
4481#endif
4482 {
4483 /* XXX: limits number of signals */
4484 retval = WTERMSIG(status);
4485#if JOBS
4486 if (retval == SIGINT)
4487 job->sigint = 1;
4488#endif
4489 }
4490 retval += 128;
4491 }
Denys Vlasenko883cea42009-07-11 15:31:59 +02004492 TRACE(("getstatus: job %d, nproc %d, status 0x%x, retval 0x%x\n",
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004493 jobno(job), job->nprocs, status, retval));
4494 return retval;
4495}
4496
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02004497static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00004498waitcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004499{
4500 struct job *job;
4501 int retval;
4502 struct job *jp;
4503
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004504 nextopt(nullstr);
4505 retval = 0;
4506
4507 argv = argptr;
4508 if (!*argv) {
4509 /* wait for all jobs */
4510 for (;;) {
4511 jp = curjob;
4512 while (1) {
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004513 if (!jp) /* no running procs */
4514 goto ret;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004515 if (jp->state == JOBRUNNING)
4516 break;
4517 jp->waited = 1;
4518 jp = jp->prev_job;
4519 }
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004520 /* man bash:
4521 * "When bash is waiting for an asynchronous command via
4522 * the wait builtin, the reception of a signal for which a trap
4523 * has been set will cause the wait builtin to return immediately
4524 * with an exit status greater than 128, immediately after which
4525 * the trap is executed."
Denys Vlasenko69188112016-10-27 20:18:18 +02004526 */
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004527 dowait(DOWAIT_BLOCK_OR_SIG, NULL);
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02004528 /* if child sends us a signal *and immediately exits*,
4529 * dowait() returns pid > 0. Check this case,
4530 * not "if (dowait() < 0)"!
4531 */
Denys Vlasenko7c1ed9f2010-05-17 04:42:40 +02004532 if (pending_sig)
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02004533 goto sigout;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004534 }
4535 }
4536
4537 retval = 127;
4538 do {
4539 if (**argv != '%') {
4540 pid_t pid = number(*argv);
4541 job = curjob;
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004542 while (1) {
4543 if (!job)
4544 goto repeat;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004545 if (job->ps[job->nprocs - 1].ps_pid == pid)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004546 break;
4547 job = job->prev_job;
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004548 }
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004549 } else {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004550 job = getjob(*argv, 0);
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004551 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004552 /* loop until process terminated or stopped */
Denys Vlasenko69188112016-10-27 20:18:18 +02004553 while (job->state == JOBRUNNING) {
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004554 dowait(DOWAIT_BLOCK_OR_SIG, NULL);
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02004555 if (pending_sig)
4556 goto sigout;
Denys Vlasenko69188112016-10-27 20:18:18 +02004557 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004558 job->waited = 1;
4559 retval = getstatus(job);
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004560 repeat: ;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004561 } while (*++argv);
4562
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004563 ret:
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004564 return retval;
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02004565 sigout:
4566 retval = 128 + pending_sig;
4567 return retval;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004568}
4569
4570static struct job *
4571growjobtab(void)
4572{
4573 size_t len;
4574 ptrdiff_t offset;
4575 struct job *jp, *jq;
4576
4577 len = njobs * sizeof(*jp);
4578 jq = jobtab;
4579 jp = ckrealloc(jq, len + 4 * sizeof(*jp));
4580
4581 offset = (char *)jp - (char *)jq;
4582 if (offset) {
4583 /* Relocate pointers */
4584 size_t l = len;
4585
4586 jq = (struct job *)((char *)jq + l);
4587 while (l) {
4588 l -= sizeof(*jp);
4589 jq--;
4590#define joff(p) ((struct job *)((char *)(p) + l))
4591#define jmove(p) (p) = (void *)((char *)(p) + offset)
4592 if (joff(jp)->ps == &jq->ps0)
4593 jmove(joff(jp)->ps);
4594 if (joff(jp)->prev_job)
4595 jmove(joff(jp)->prev_job);
4596 }
4597 if (curjob)
4598 jmove(curjob);
4599#undef joff
4600#undef jmove
4601 }
4602
4603 njobs += 4;
4604 jobtab = jp;
4605 jp = (struct job *)((char *)jp + len);
4606 jq = jp + 3;
4607 do {
4608 jq->used = 0;
4609 } while (--jq >= jp);
4610 return jp;
4611}
4612
4613/*
4614 * Return a new job structure.
4615 * Called with interrupts off.
4616 */
4617static struct job *
Denis Vlasenko68404f12008-03-17 09:00:54 +00004618makejob(/*union node *node,*/ int nprocs)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004619{
4620 int i;
4621 struct job *jp;
4622
4623 for (i = njobs, jp = jobtab; ; jp++) {
4624 if (--i < 0) {
4625 jp = growjobtab();
4626 break;
4627 }
4628 if (jp->used == 0)
4629 break;
4630 if (jp->state != JOBDONE || !jp->waited)
4631 continue;
4632#if JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +00004633 if (doing_jobctl)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004634 continue;
4635#endif
4636 freejob(jp);
4637 break;
4638 }
4639 memset(jp, 0, sizeof(*jp));
4640#if JOBS
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004641 /* jp->jobctl is a bitfield.
Denys Vlasenko098b7132017-01-11 19:59:03 +01004642 * "jp->jobctl |= doing_jobctl" likely to give awful code */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00004643 if (doing_jobctl)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004644 jp->jobctl = 1;
4645#endif
4646 jp->prev_job = curjob;
4647 curjob = jp;
4648 jp->used = 1;
4649 jp->ps = &jp->ps0;
4650 if (nprocs > 1) {
4651 jp->ps = ckmalloc(nprocs * sizeof(struct procstat));
4652 }
Denis Vlasenko68404f12008-03-17 09:00:54 +00004653 TRACE(("makejob(%d) returns %%%d\n", nprocs,
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004654 jobno(jp)));
4655 return jp;
4656}
4657
4658#if JOBS
4659/*
4660 * Return a string identifying a command (to be printed by the
4661 * jobs command).
4662 */
4663static char *cmdnextc;
4664
4665static void
4666cmdputs(const char *s)
4667{
Denis Vlasenko92e13c22008-03-25 01:17:40 +00004668 static const char vstype[VSTYPE + 1][3] = {
4669 "", "}", "-", "+", "?", "=",
4670 "%", "%%", "#", "##"
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01004671 IF_BASH_SUBSTR(, ":")
4672 IF_BASH_PATTERN_SUBST(, "/", "//")
Denis Vlasenko92e13c22008-03-25 01:17:40 +00004673 };
4674
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004675 const char *p, *str;
Denys Vlasenko46a14772009-12-10 21:27:13 +01004676 char cc[2];
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004677 char *nextc;
Denys Vlasenkocd716832009-11-28 22:14:02 +01004678 unsigned char c;
4679 unsigned char subtype = 0;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004680 int quoted = 0;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004681
Denys Vlasenko46a14772009-12-10 21:27:13 +01004682 cc[1] = '\0';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004683 nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
4684 p = s;
Denys Vlasenko46a14772009-12-10 21:27:13 +01004685 while ((c = *p++) != '\0') {
Denis Vlasenkoef527f52008-06-23 01:52:30 +00004686 str = NULL;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004687 switch (c) {
4688 case CTLESC:
4689 c = *p++;
4690 break;
4691 case CTLVAR:
4692 subtype = *p++;
4693 if ((subtype & VSTYPE) == VSLENGTH)
4694 str = "${#";
4695 else
4696 str = "${";
Ron Yorston549deab2015-05-18 09:57:51 +02004697 goto dostr;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004698 case CTLENDVAR:
4699 str = "\"}" + !(quoted & 1);
4700 quoted >>= 1;
4701 subtype = 0;
4702 goto dostr;
4703 case CTLBACKQ:
4704 str = "$(...)";
4705 goto dostr;
Denys Vlasenko0b883582016-12-23 16:49:07 +01004706#if ENABLE_FEATURE_SH_MATH
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004707 case CTLARI:
4708 str = "$((";
4709 goto dostr;
4710 case CTLENDARI:
4711 str = "))";
4712 goto dostr;
4713#endif
4714 case CTLQUOTEMARK:
4715 quoted ^= 1;
4716 c = '"';
4717 break;
4718 case '=':
4719 if (subtype == 0)
4720 break;
4721 if ((subtype & VSTYPE) != VSNORMAL)
4722 quoted <<= 1;
4723 str = vstype[subtype & VSTYPE];
4724 if (subtype & VSNUL)
4725 c = ':';
4726 else
4727 goto checkstr;
4728 break;
4729 case '\'':
4730 case '\\':
4731 case '"':
4732 case '$':
4733 /* These can only happen inside quotes */
4734 cc[0] = c;
4735 str = cc;
Denys Vlasenkod0fff912017-07-31 14:32:18 +02004736//FIXME:
4737// $ true $$ &
4738// $ <cr>
4739// [1]+ Done true ${\$} <<=== BUG: ${\$} is not a valid way to write $$ (${$} would be ok)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004740 c = '\\';
4741 break;
4742 default:
4743 break;
4744 }
4745 USTPUTC(c, nextc);
4746 checkstr:
4747 if (!str)
4748 continue;
4749 dostr:
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02004750 while ((c = *str++) != '\0') {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004751 USTPUTC(c, nextc);
4752 }
Denys Vlasenko46a14772009-12-10 21:27:13 +01004753 } /* while *p++ not NUL */
4754
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004755 if (quoted & 1) {
4756 USTPUTC('"', nextc);
4757 }
4758 *nextc = 0;
4759 cmdnextc = nextc;
4760}
4761
4762/* cmdtxt() and cmdlist() call each other */
4763static void cmdtxt(union node *n);
4764
4765static void
4766cmdlist(union node *np, int sep)
4767{
4768 for (; np; np = np->narg.next) {
4769 if (!sep)
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00004770 cmdputs(" ");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004771 cmdtxt(np);
4772 if (sep && np->narg.next)
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00004773 cmdputs(" ");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004774 }
4775}
4776
4777static void
4778cmdtxt(union node *n)
4779{
4780 union node *np;
4781 struct nodelist *lp;
4782 const char *p;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004783
4784 if (!n)
4785 return;
4786 switch (n->type) {
4787 default:
4788#if DEBUG
4789 abort();
4790#endif
4791 case NPIPE:
4792 lp = n->npipe.cmdlist;
4793 for (;;) {
4794 cmdtxt(lp->n);
4795 lp = lp->next;
4796 if (!lp)
4797 break;
4798 cmdputs(" | ");
4799 }
4800 break;
4801 case NSEMI:
4802 p = "; ";
4803 goto binop;
4804 case NAND:
4805 p = " && ";
4806 goto binop;
4807 case NOR:
4808 p = " || ";
4809 binop:
4810 cmdtxt(n->nbinary.ch1);
4811 cmdputs(p);
4812 n = n->nbinary.ch2;
4813 goto donode;
4814 case NREDIR:
4815 case NBACKGND:
4816 n = n->nredir.n;
4817 goto donode;
4818 case NNOT:
4819 cmdputs("!");
4820 n = n->nnot.com;
4821 donode:
4822 cmdtxt(n);
4823 break;
4824 case NIF:
4825 cmdputs("if ");
4826 cmdtxt(n->nif.test);
4827 cmdputs("; then ");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004828 if (n->nif.elsepart) {
Denys Vlasenko7cee00e2009-07-24 01:08:03 +02004829 cmdtxt(n->nif.ifpart);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004830 cmdputs("; else ");
4831 n = n->nif.elsepart;
Denys Vlasenko7cee00e2009-07-24 01:08:03 +02004832 } else {
4833 n = n->nif.ifpart;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004834 }
4835 p = "; fi";
4836 goto dotail;
4837 case NSUBSHELL:
4838 cmdputs("(");
4839 n = n->nredir.n;
4840 p = ")";
4841 goto dotail;
4842 case NWHILE:
4843 p = "while ";
4844 goto until;
4845 case NUNTIL:
4846 p = "until ";
4847 until:
4848 cmdputs(p);
4849 cmdtxt(n->nbinary.ch1);
4850 n = n->nbinary.ch2;
4851 p = "; done";
4852 dodo:
4853 cmdputs("; do ");
4854 dotail:
4855 cmdtxt(n);
4856 goto dotail2;
4857 case NFOR:
4858 cmdputs("for ");
4859 cmdputs(n->nfor.var);
4860 cmdputs(" in ");
4861 cmdlist(n->nfor.args, 1);
4862 n = n->nfor.body;
4863 p = "; done";
4864 goto dodo;
4865 case NDEFUN:
Denys Vlasenko675d24a2018-01-27 22:02:05 +01004866 cmdputs(n->ndefun.text);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004867 p = "() { ... }";
4868 goto dotail2;
4869 case NCMD:
4870 cmdlist(n->ncmd.args, 1);
4871 cmdlist(n->ncmd.redirect, 0);
4872 break;
4873 case NARG:
4874 p = n->narg.text;
4875 dotail2:
4876 cmdputs(p);
4877 break;
4878 case NHERE:
4879 case NXHERE:
4880 p = "<<...";
4881 goto dotail2;
4882 case NCASE:
4883 cmdputs("case ");
4884 cmdputs(n->ncase.expr->narg.text);
4885 cmdputs(" in ");
4886 for (np = n->ncase.cases; np; np = np->nclist.next) {
4887 cmdtxt(np->nclist.pattern);
4888 cmdputs(") ");
4889 cmdtxt(np->nclist.body);
4890 cmdputs(";; ");
4891 }
4892 p = "esac";
4893 goto dotail2;
4894 case NTO:
4895 p = ">";
4896 goto redir;
4897 case NCLOBBER:
4898 p = ">|";
4899 goto redir;
4900 case NAPPEND:
4901 p = ">>";
4902 goto redir;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01004903#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00004904 case NTO2:
4905#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004906 case NTOFD:
4907 p = ">&";
4908 goto redir;
4909 case NFROM:
4910 p = "<";
4911 goto redir;
4912 case NFROMFD:
4913 p = "<&";
4914 goto redir;
4915 case NFROMTO:
4916 p = "<>";
4917 redir:
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00004918 cmdputs(utoa(n->nfile.fd));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004919 cmdputs(p);
4920 if (n->type == NTOFD || n->type == NFROMFD) {
Denys Vlasenkod0fff912017-07-31 14:32:18 +02004921 if (n->ndup.dupfd >= 0)
4922 cmdputs(utoa(n->ndup.dupfd));
4923 else
4924 cmdputs("-");
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00004925 break;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004926 }
4927 n = n->nfile.fname;
4928 goto donode;
4929 }
4930}
4931
4932static char *
4933commandtext(union node *n)
4934{
4935 char *name;
4936
4937 STARTSTACKSTR(cmdnextc);
4938 cmdtxt(n);
4939 name = stackblock();
Denys Vlasenko6a94cee2016-10-25 17:40:25 +02004940 TRACE(("commandtext: name %p, end %p\n", name, cmdnextc));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004941 return ckstrdup(name);
4942}
4943#endif /* JOBS */
4944
4945/*
4946 * Fork off a subshell. If we are doing job control, give the subshell its
4947 * own process group. Jp is a job structure that the job is to be added to.
4948 * N is the command that will be evaluated by the child. Both jp and n may
4949 * be NULL. The mode parameter can be one of the following:
4950 * FORK_FG - Fork off a foreground process.
4951 * FORK_BG - Fork off a background process.
4952 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
4953 * process group even if job control is on.
4954 *
4955 * When job control is turned off, background processes have their standard
4956 * input redirected to /dev/null (except for the second and later processes
4957 * in a pipeline).
4958 *
4959 * Called with interrupts off.
4960 */
4961/*
4962 * Clear traps on a fork.
4963 */
4964static void
4965clear_traps(void)
4966{
4967 char **tp;
4968
Denys Vlasenkob4f51d32016-10-27 12:55:09 +02004969 INT_OFF;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004970 for (tp = trap; tp < &trap[NSIG]; tp++) {
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004971 if (*tp && **tp) { /* trap not NULL or "" (SIG_IGN) */
Denys Vlasenkoe305c282009-09-25 02:12:27 +02004972 if (trap_ptr == trap)
4973 free(*tp);
4974 /* else: it "belongs" to trap_ptr vector, don't free */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004975 *tp = NULL;
Denys Vlasenko0800e3a2009-09-24 03:09:26 +02004976 if ((tp - trap) != 0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004977 setsignal(tp - trap);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004978 }
4979 }
Alexander Shishkinccb97712010-07-25 13:07:39 +02004980 may_have_traps = 0;
Denys Vlasenkob4f51d32016-10-27 12:55:09 +02004981 INT_ON;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004982}
Denis Vlasenkobdc406d2007-07-15 01:13:25 +00004983
4984/* Lives far away from here, needed for forkchild */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004985static void closescript(void);
Denis Vlasenko41770222007-10-07 18:02:52 +00004986
Denis Vlasenkobdc406d2007-07-15 01:13:25 +00004987/* Called after fork(), in child */
Denys Vlasenko70392332016-10-27 02:31:55 +02004988/* jp and n are NULL when called by openhere() for heredoc support */
Denys Vlasenko21d87d42009-09-25 00:06:51 +02004989static NOINLINE void
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02004990forkchild(struct job *jp, union node *n, int mode)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004991{
4992 int oldlvl;
4993
4994 TRACE(("Child shell %d\n", getpid()));
4995 oldlvl = shlvl;
4996 shlvl++;
4997
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004998 /* man bash: "Non-builtin commands run by bash have signal handlers
4999 * set to the values inherited by the shell from its parent".
5000 * Do we do it correctly? */
5001
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005002 closescript();
Denys Vlasenko844f9902009-09-23 03:25:52 +02005003
5004 if (mode == FORK_NOJOB /* is it `xxx` ? */
5005 && n && n->type == NCMD /* is it single cmd? */
5006 /* && n->ncmd.args->type == NARG - always true? */
Denys Vlasenko74269202010-02-21 01:26:42 +01005007 && n->ncmd.args && strcmp(n->ncmd.args->narg.text, "trap") == 0
Denys Vlasenko844f9902009-09-23 03:25:52 +02005008 && n->ncmd.args->narg.next == NULL /* "trap" with no arguments */
5009 /* && n->ncmd.args->narg.backquote == NULL - do we need to check this? */
5010 ) {
5011 TRACE(("Trap hack\n"));
5012 /* Awful hack for `trap` or $(trap).
5013 *
5014 * http://www.opengroup.org/onlinepubs/009695399/utilities/trap.html
5015 * contains an example where "trap" is executed in a subshell:
5016 *
5017 * save_traps=$(trap)
5018 * ...
5019 * eval "$save_traps"
5020 *
5021 * Standard does not say that "trap" in subshell shall print
5022 * parent shell's traps. It only says that its output
5023 * must have suitable form, but then, in the above example
5024 * (which is not supposed to be normative), it implies that.
5025 *
5026 * bash (and probably other shell) does implement it
5027 * (traps are reset to defaults, but "trap" still shows them),
5028 * but as a result, "trap" logic is hopelessly messed up:
5029 *
5030 * # trap
5031 * trap -- 'echo Ho' SIGWINCH <--- we have a handler
5032 * # (trap) <--- trap is in subshell - no output (correct, traps are reset)
5033 * # true | trap <--- trap is in subshell - no output (ditto)
5034 * # echo `true | trap` <--- in subshell - output (but traps are reset!)
5035 * trap -- 'echo Ho' SIGWINCH
5036 * # echo `(trap)` <--- in subshell in subshell - output
5037 * trap -- 'echo Ho' SIGWINCH
5038 * # echo `true | (trap)` <--- in subshell in subshell in subshell - output!
5039 * trap -- 'echo Ho' SIGWINCH
5040 *
5041 * The rules when to forget and when to not forget traps
5042 * get really complex and nonsensical.
5043 *
5044 * Our solution: ONLY bare $(trap) or `trap` is special.
5045 */
Denys Vlasenko8f88d852009-09-25 12:12:53 +02005046 /* Save trap handler strings for trap builtin to print */
Ron Yorstond840c5d2015-07-19 23:05:20 +02005047 trap_ptr = xmemdup(trap, sizeof(trap));
Denys Vlasenko8f88d852009-09-25 12:12:53 +02005048 /* Fall through into clearing traps */
Denys Vlasenko844f9902009-09-23 03:25:52 +02005049 }
Denys Vlasenkoe305c282009-09-25 02:12:27 +02005050 clear_traps();
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005051#if JOBS
5052 /* do job control only in root shell */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00005053 doing_jobctl = 0;
Denys Vlasenkob12553f2011-02-21 03:22:20 +01005054 if (mode != FORK_NOJOB && jp->jobctl && oldlvl == 0) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005055 pid_t pgrp;
5056
5057 if (jp->nprocs == 0)
5058 pgrp = getpid();
5059 else
Denys Vlasenko285ad152009-12-04 23:02:27 +01005060 pgrp = jp->ps[0].ps_pid;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005061 /* this can fail because we are doing it in the parent also */
5062 setpgid(0, pgrp);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005063 if (mode == FORK_FG)
5064 xtcsetpgrp(ttyfd, pgrp);
5065 setsignal(SIGTSTP);
5066 setsignal(SIGTTOU);
5067 } else
5068#endif
5069 if (mode == FORK_BG) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005070 /* man bash: "When job control is not in effect,
5071 * asynchronous commands ignore SIGINT and SIGQUIT" */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005072 ignoresig(SIGINT);
5073 ignoresig(SIGQUIT);
5074 if (jp->nprocs == 0) {
5075 close(0);
5076 if (open(bb_dev_null, O_RDONLY) != 0)
Denys Vlasenko12ffefb2017-08-23 14:52:56 +02005077 ash_msg_and_raise_perror("can't open '%s'", bb_dev_null);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005078 }
5079 }
Denys Vlasenkob12553f2011-02-21 03:22:20 +01005080 if (oldlvl == 0) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005081 if (iflag) { /* why if iflag only? */
5082 setsignal(SIGINT);
5083 setsignal(SIGTERM);
5084 }
5085 /* man bash:
5086 * "In all cases, bash ignores SIGQUIT. Non-builtin
5087 * commands run by bash have signal handlers
5088 * set to the values inherited by the shell
5089 * from its parent".
5090 * Take care of the second rule: */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005091 setsignal(SIGQUIT);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005092 }
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02005093#if JOBS
Denys Vlasenko844f9902009-09-23 03:25:52 +02005094 if (n && n->type == NCMD
Denys Vlasenko74269202010-02-21 01:26:42 +01005095 && n->ncmd.args && strcmp(n->ncmd.args->narg.text, "jobs") == 0
Denys Vlasenko844f9902009-09-23 03:25:52 +02005096 ) {
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02005097 TRACE(("Job hack\n"));
Denys Vlasenko844f9902009-09-23 03:25:52 +02005098 /* "jobs": we do not want to clear job list for it,
5099 * instead we remove only _its_ own_ job from job list.
5100 * This makes "jobs .... | cat" more useful.
5101 */
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02005102 freejob(curjob);
5103 return;
5104 }
5105#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005106 for (jp = curjob; jp; jp = jp->prev_job)
5107 freejob(jp);
5108 jobless = 0;
5109}
5110
Denis Vlasenkobdc406d2007-07-15 01:13:25 +00005111/* Called after fork(), in parent */
Denis Vlasenko85c24712008-03-17 09:04:04 +00005112#if !JOBS
5113#define forkparent(jp, n, mode, pid) forkparent(jp, mode, pid)
5114#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005115static void
5116forkparent(struct job *jp, union node *n, int mode, pid_t pid)
5117{
5118 TRACE(("In parent shell: child = %d\n", pid));
5119 if (!jp) {
Denys Vlasenko70392332016-10-27 02:31:55 +02005120 /* jp is NULL when called by openhere() for heredoc support */
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00005121 while (jobless && dowait(DOWAIT_NONBLOCK, NULL) > 0)
5122 continue;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005123 jobless++;
5124 return;
5125 }
5126#if JOBS
5127 if (mode != FORK_NOJOB && jp->jobctl) {
5128 int pgrp;
5129
5130 if (jp->nprocs == 0)
5131 pgrp = pid;
5132 else
Denys Vlasenko285ad152009-12-04 23:02:27 +01005133 pgrp = jp->ps[0].ps_pid;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005134 /* This can fail because we are doing it in the child also */
5135 setpgid(pid, pgrp);
5136 }
5137#endif
5138 if (mode == FORK_BG) {
5139 backgndpid = pid; /* set $! */
5140 set_curjob(jp, CUR_RUNNING);
5141 }
5142 if (jp) {
5143 struct procstat *ps = &jp->ps[jp->nprocs++];
Denys Vlasenko285ad152009-12-04 23:02:27 +01005144 ps->ps_pid = pid;
5145 ps->ps_status = -1;
5146 ps->ps_cmd = nullstr;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005147#if JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +00005148 if (doing_jobctl && n)
Denys Vlasenko285ad152009-12-04 23:02:27 +01005149 ps->ps_cmd = commandtext(n);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005150#endif
5151 }
5152}
5153
Denys Vlasenko70392332016-10-27 02:31:55 +02005154/* jp and n are NULL when called by openhere() for heredoc support */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005155static int
5156forkshell(struct job *jp, union node *n, int mode)
5157{
5158 int pid;
5159
5160 TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
5161 pid = fork();
5162 if (pid < 0) {
5163 TRACE(("Fork failed, errno=%d", errno));
5164 if (jp)
5165 freejob(jp);
Denys Vlasenko12ffefb2017-08-23 14:52:56 +02005166 ash_msg_and_raise_perror("can't fork");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005167 }
Denys Vlasenko76ace252009-10-12 15:25:01 +02005168 if (pid == 0) {
5169 CLEAR_RANDOM_T(&random_gen); /* or else $RANDOM repeats in child */
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02005170 forkchild(jp, n, mode);
Denys Vlasenko76ace252009-10-12 15:25:01 +02005171 } else {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005172 forkparent(jp, n, mode, pid);
Denys Vlasenko76ace252009-10-12 15:25:01 +02005173 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005174 return pid;
5175}
5176
5177/*
5178 * Wait for job to finish.
5179 *
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005180 * Under job control we have the problem that while a child process
5181 * is running interrupts generated by the user are sent to the child
5182 * but not to the shell. This means that an infinite loop started by
5183 * an interactive user may be hard to kill. With job control turned off,
5184 * an interactive user may place an interactive program inside a loop.
5185 * If the interactive program catches interrupts, the user doesn't want
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005186 * these interrupts to also abort the loop. The approach we take here
5187 * is to have the shell ignore interrupt signals while waiting for a
5188 * foreground process to terminate, and then send itself an interrupt
5189 * signal if the child process was terminated by an interrupt signal.
5190 * Unfortunately, some programs want to do a bit of cleanup and then
5191 * exit on interrupt; unless these processes terminate themselves by
5192 * sending a signal to themselves (instead of calling exit) they will
5193 * confuse this approach.
5194 *
5195 * Called with interrupts off.
5196 */
5197static int
5198waitforjob(struct job *jp)
5199{
5200 int st;
5201
5202 TRACE(("waitforjob(%%%d) called\n", jobno(jp)));
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005203
5204 INT_OFF;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005205 while (jp->state == JOBRUNNING) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005206 /* In non-interactive shells, we _can_ get
5207 * a keyboard signal here and be EINTRed,
5208 * but we just loop back, waiting for command to complete.
5209 *
5210 * man bash:
5211 * "If bash is waiting for a command to complete and receives
5212 * a signal for which a trap has been set, the trap
5213 * will not be executed until the command completes."
5214 *
5215 * Reality is that even if trap is not set, bash
5216 * will not act on the signal until command completes.
5217 * Try this. sleep5intoff.c:
5218 * #include <signal.h>
5219 * #include <unistd.h>
5220 * int main() {
5221 * sigset_t set;
5222 * sigemptyset(&set);
5223 * sigaddset(&set, SIGINT);
5224 * sigaddset(&set, SIGQUIT);
5225 * sigprocmask(SIG_BLOCK, &set, NULL);
5226 * sleep(5);
5227 * return 0;
5228 * }
5229 * $ bash -c './sleep5intoff; echo hi'
5230 * ^C^C^C^C <--- pressing ^C once a second
5231 * $ _
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005232 * $ bash -c './sleep5intoff; echo hi'
5233 * ^\^\^\^\hi <--- pressing ^\ (SIGQUIT)
5234 * $ _
5235 */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005236 dowait(DOWAIT_BLOCK, jp);
5237 }
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005238 INT_ON;
5239
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005240 st = getstatus(jp);
5241#if JOBS
5242 if (jp->jobctl) {
5243 xtcsetpgrp(ttyfd, rootpid);
Denys Vlasenko098b7132017-01-11 19:59:03 +01005244 restore_tty_if_stopped_or_signaled(jp);
5245
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005246 /*
5247 * This is truly gross.
5248 * If we're doing job control, then we did a TIOCSPGRP which
5249 * caused us (the shell) to no longer be in the controlling
5250 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
5251 * intuit from the subprocess exit status whether a SIGINT
5252 * occurred, and if so interrupt ourselves. Yuck. - mycroft
5253 */
Denis Vlasenko991a1da2008-02-10 19:02:53 +00005254 if (jp->sigint) /* TODO: do the same with all signals */
5255 raise(SIGINT); /* ... by raise(jp->sig) instead? */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005256 }
5257 if (jp->state == JOBDONE)
5258#endif
5259 freejob(jp);
5260 return st;
5261}
5262
5263/*
5264 * return 1 if there are stopped jobs, otherwise 0
5265 */
5266static int
5267stoppedjobs(void)
5268{
5269 struct job *jp;
5270 int retval;
5271
5272 retval = 0;
5273 if (job_warning)
5274 goto out;
5275 jp = curjob;
5276 if (jp && jp->state == JOBSTOPPED) {
5277 out2str("You have stopped jobs.\n");
5278 job_warning = 2;
5279 retval++;
5280 }
5281 out:
5282 return retval;
5283}
5284
5285
Denys Vlasenko70392332016-10-27 02:31:55 +02005286/*
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005287 * Code for dealing with input/output redirection.
5288 */
5289
Denys Vlasenko8d0e0cd2011-01-25 23:21:46 +01005290#undef EMPTY
5291#undef CLOSED
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005292#define EMPTY -2 /* marks an unused slot in redirtab */
Denys Vlasenko035486c2017-07-31 04:09:19 +02005293#define CLOSED -1 /* marks a slot of previously-closed fd */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005294
5295/*
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005296 * Handle here documents. Normally we fork off a process to write the
5297 * data to a pipe. If the document is short, we can stuff the data in
5298 * the pipe without forking.
5299 */
5300/* openhere needs this forward reference */
5301static void expandhere(union node *arg, int fd);
5302static int
5303openhere(union node *redir)
5304{
5305 int pip[2];
5306 size_t len = 0;
5307
5308 if (pipe(pip) < 0)
Denys Vlasenko12ffefb2017-08-23 14:52:56 +02005309 ash_msg_and_raise_perror("can't create pipe");
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005310 if (redir->type == NHERE) {
5311 len = strlen(redir->nhere.doc->narg.text);
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005312 if (len <= PIPE_BUF) {
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005313 full_write(pip[1], redir->nhere.doc->narg.text, len);
5314 goto out;
5315 }
5316 }
5317 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
Denis Vlasenko0b769642008-07-24 07:54:57 +00005318 /* child */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005319 close(pip[0]);
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005320 ignoresig(SIGINT); //signal(SIGINT, SIG_IGN);
5321 ignoresig(SIGQUIT); //signal(SIGQUIT, SIG_IGN);
5322 ignoresig(SIGHUP); //signal(SIGHUP, SIG_IGN);
5323 ignoresig(SIGTSTP); //signal(SIGTSTP, SIG_IGN);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005324 signal(SIGPIPE, SIG_DFL);
5325 if (redir->type == NHERE)
5326 full_write(pip[1], redir->nhere.doc->narg.text, len);
Denis Vlasenko0b769642008-07-24 07:54:57 +00005327 else /* NXHERE */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005328 expandhere(redir->nhere.doc, pip[1]);
Bernhard Reutner-Fischer636a1f82008-05-19 09:29:47 +00005329 _exit(EXIT_SUCCESS);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005330 }
5331 out:
5332 close(pip[1]);
5333 return pip[0];
5334}
5335
5336static int
5337openredirect(union node *redir)
5338{
Denys Vlasenkof1a5cb02017-07-25 17:47:48 +02005339 struct stat sb;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005340 char *fname;
5341 int f;
5342
5343 switch (redir->nfile.type) {
Denys Vlasenko557482c2016-09-25 21:24:04 +02005344/* Can't happen, our single caller does this itself */
5345// case NTOFD:
5346// case NFROMFD:
5347// return -1;
5348 case NHERE:
5349 case NXHERE:
5350 return openhere(redir);
5351 }
5352
5353 /* For N[X]HERE, reading redir->nfile.expfname would touch beyond
5354 * allocated space. Do it only when we know it is safe.
5355 */
5356 fname = redir->nfile.expfname;
5357
5358 switch (redir->nfile.type) {
5359 default:
5360#if DEBUG
5361 abort();
5362#endif
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005363 case NFROM:
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005364 f = open(fname, O_RDONLY);
5365 if (f < 0)
5366 goto eopen;
5367 break;
5368 case NFROMTO:
Andreas Bühmannda75f442010-06-24 04:32:37 +02005369 f = open(fname, O_RDWR|O_CREAT, 0666);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005370 if (f < 0)
5371 goto ecreate;
5372 break;
5373 case NTO:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01005374#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00005375 case NTO2:
5376#endif
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005377 /* Take care of noclobber mode. */
5378 if (Cflag) {
Denys Vlasenkof1a5cb02017-07-25 17:47:48 +02005379 if (stat(fname, &sb) < 0) {
5380 f = open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
5381 if (f < 0)
5382 goto ecreate;
5383 } else if (!S_ISREG(sb.st_mode)) {
5384 f = open(fname, O_WRONLY, 0666);
5385 if (f < 0)
5386 goto ecreate;
5387 if (fstat(f, &sb) < 0 && S_ISREG(sb.st_mode)) {
5388 close(f);
5389 errno = EEXIST;
5390 goto ecreate;
5391 }
5392 } else {
5393 errno = EEXIST;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005394 goto ecreate;
Denys Vlasenkof1a5cb02017-07-25 17:47:48 +02005395 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005396 break;
5397 }
5398 /* FALLTHROUGH */
5399 case NCLOBBER:
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005400 f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666);
5401 if (f < 0)
5402 goto ecreate;
5403 break;
5404 case NAPPEND:
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005405 f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666);
5406 if (f < 0)
5407 goto ecreate;
5408 break;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005409 }
5410
5411 return f;
5412 ecreate:
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +00005413 ash_msg_and_raise_error("can't create %s: %s", fname, errmsg(errno, "nonexistent directory"));
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005414 eopen:
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +00005415 ash_msg_and_raise_error("can't open %s: %s", fname, errmsg(errno, "no such file"));
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005416}
5417
5418/*
Denys Vlasenko64774602016-10-26 15:24:30 +02005419 * Copy a file descriptor to be >= 10. Throws exception on error.
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005420 */
5421static int
Denys Vlasenko64774602016-10-26 15:24:30 +02005422savefd(int from)
5423{
5424 int newfd;
5425 int err;
5426
5427 newfd = fcntl(from, F_DUPFD, 10);
5428 err = newfd < 0 ? errno : 0;
5429 if (err != EBADF) {
5430 if (err)
Ron Yorstonbe366e52017-07-27 13:53:39 +01005431 ash_msg_and_raise_perror("%d", from);
Denys Vlasenko64774602016-10-26 15:24:30 +02005432 close(from);
5433 fcntl(newfd, F_SETFD, FD_CLOEXEC);
5434 }
5435
5436 return newfd;
5437}
5438static int
5439dup2_or_raise(int from, int to)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005440{
5441 int newfd;
5442
Denys Vlasenko64774602016-10-26 15:24:30 +02005443 newfd = (from != to) ? dup2(from, to) : to;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005444 if (newfd < 0) {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005445 /* Happens when source fd is not open: try "echo >&99" */
Ron Yorstonbe366e52017-07-27 13:53:39 +01005446 ash_msg_and_raise_perror("%d", from);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005447 }
5448 return newfd;
5449}
Denys Vlasenko035486c2017-07-31 04:09:19 +02005450static int
5451fcntl_F_DUPFD(int fd, int avoid_fd)
5452{
5453 int newfd;
5454 repeat:
5455 newfd = fcntl(fd, F_DUPFD, avoid_fd + 1);
5456 if (newfd < 0) {
5457 if (errno == EBUSY)
5458 goto repeat;
5459 if (errno == EINTR)
5460 goto repeat;
5461 }
5462 return newfd;
5463}
5464static int
5465xdup_CLOEXEC_and_close(int fd, int avoid_fd)
5466{
5467 int newfd;
5468 repeat:
5469 newfd = fcntl(fd, F_DUPFD, avoid_fd + 1);
5470 if (newfd < 0) {
5471 if (errno == EBUSY)
5472 goto repeat;
5473 if (errno == EINTR)
5474 goto repeat;
5475 /* fd was not open? */
5476 if (errno == EBADF)
5477 return fd;
5478 ash_msg_and_raise_perror("%d", newfd);
5479 }
5480 fcntl(newfd, F_SETFD, FD_CLOEXEC);
5481 close(fd);
5482 return newfd;
5483}
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005484
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005485/* Struct def and variable are moved down to the first usage site */
Denys Vlasenko035486c2017-07-31 04:09:19 +02005486struct squirrel {
5487 int orig_fd;
5488 int moved_to;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005489};
Denis Vlasenko0b769642008-07-24 07:54:57 +00005490struct redirtab {
5491 struct redirtab *next;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005492 int pair_count;
Denys Vlasenko035486c2017-07-31 04:09:19 +02005493 struct squirrel two_fd[];
Denis Vlasenko0b769642008-07-24 07:54:57 +00005494};
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005495#define redirlist (G_var.redirlist)
Denis Vlasenko0b769642008-07-24 07:54:57 +00005496
Denys Vlasenko035486c2017-07-31 04:09:19 +02005497static void
5498add_squirrel_closed(struct redirtab *sq, int fd)
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005499{
5500 int i;
5501
Denys Vlasenko035486c2017-07-31 04:09:19 +02005502 if (!sq)
5503 return;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005504
Denys Vlasenko035486c2017-07-31 04:09:19 +02005505 for (i = 0; sq->two_fd[i].orig_fd != EMPTY; i++) {
5506 /* If we collide with an already moved fd... */
5507 if (fd == sq->two_fd[i].orig_fd) {
5508 /* Examples:
5509 * "echo 3>FILE 3>&- 3>FILE"
5510 * "echo 3>&- 3>FILE"
5511 * No need for last redirect to insert
5512 * another "need to close 3" indicator.
5513 */
5514 TRACE(("redirect_fd %d: already moved or closed\n", fd));
5515 return;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005516 }
5517 }
Denys Vlasenko035486c2017-07-31 04:09:19 +02005518 TRACE(("redirect_fd %d: previous fd was closed\n", fd));
5519 sq->two_fd[i].orig_fd = fd;
5520 sq->two_fd[i].moved_to = CLOSED;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005521}
5522
Denys Vlasenko37dc08b2016-10-02 04:38:07 +02005523static int
Denys Vlasenko035486c2017-07-31 04:09:19 +02005524save_fd_on_redirect(int fd, int avoid_fd, struct redirtab *sq)
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005525{
Denys Vlasenko035486c2017-07-31 04:09:19 +02005526 int i, new_fd;
Denis Vlasenko34c73c42008-08-16 11:48:02 +00005527
Denys Vlasenko035486c2017-07-31 04:09:19 +02005528 if (avoid_fd < 9) /* the important case here is that it can be -1 */
5529 avoid_fd = 9;
5530
5531#if JOBS
5532 if (fd == ttyfd) {
5533 /* Testcase: "ls -l /proc/$$/fd 10>&-" should work */
5534 ttyfd = xdup_CLOEXEC_and_close(ttyfd, avoid_fd);
5535 TRACE(("redirect_fd %d: matches ttyfd, moving it to %d\n", fd, ttyfd));
5536 return 1; /* "we closed fd" */
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005537 }
Denys Vlasenko035486c2017-07-31 04:09:19 +02005538#endif
5539 /* Are we called from redirect(0)? E.g. redirect
5540 * in a forked child. No need to save fds,
5541 * we aren't going to use them anymore, ok to trash.
5542 */
5543 if (!sq)
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005544 return 0;
Denys Vlasenko035486c2017-07-31 04:09:19 +02005545
5546 /* If this one of script's fds? */
5547 if (fd != 0) {
5548 struct parsefile *pf = g_parsefile;
5549 while (pf) {
5550 /* We skip fd == 0 case because of the following:
5551 * $ ash # running ash interactively
5552 * $ . ./script.sh
5553 * and in script.sh: "exec 9>&0".
5554 * Even though top-level pf_fd _is_ 0,
5555 * it's still ok to use it: "read" builtin uses it,
5556 * why should we cripple "exec" builtin?
5557 */
5558 if (fd == pf->pf_fd) {
5559 pf->pf_fd = xdup_CLOEXEC_and_close(fd, avoid_fd);
5560 return 1; /* "we closed fd" */
5561 }
5562 pf = pf->prev;
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005563 }
5564 }
Denys Vlasenko035486c2017-07-31 04:09:19 +02005565
5566 /* Check whether it collides with any open fds (e.g. stdio), save fds as needed */
5567
5568 /* First: do we collide with some already moved fds? */
5569 for (i = 0; sq->two_fd[i].orig_fd != EMPTY; i++) {
5570 /* If we collide with an already moved fd... */
5571 if (fd == sq->two_fd[i].moved_to) {
5572 new_fd = fcntl_F_DUPFD(fd, avoid_fd);
5573 sq->two_fd[i].moved_to = new_fd;
5574 TRACE(("redirect_fd %d: already busy, moving to %d\n", fd, new_fd));
5575 if (new_fd < 0) /* what? */
5576 xfunc_die();
5577 return 0; /* "we did not close fd" */
5578 }
5579 if (fd == sq->two_fd[i].orig_fd) {
5580 /* Example: echo Hello >/dev/null 1>&2 */
5581 TRACE(("redirect_fd %d: already moved\n", fd));
5582 return 0; /* "we did not close fd" */
5583 }
5584 }
5585
5586 /* If this fd is open, we move and remember it; if it's closed, new_fd = CLOSED (-1) */
5587 new_fd = fcntl_F_DUPFD(fd, avoid_fd);
5588 TRACE(("redirect_fd %d: previous fd is moved to %d (-1 if it was closed)\n", fd, new_fd));
5589 if (new_fd < 0) {
5590 if (errno != EBADF)
5591 xfunc_die();
5592 /* new_fd = CLOSED; - already is -1 */
5593 }
5594 sq->two_fd[i].moved_to = new_fd;
5595 sq->two_fd[i].orig_fd = fd;
5596
5597 /* if we move stderr, let "set -x" code know */
5598 if (fd == preverrout_fd)
5599 preverrout_fd = new_fd;
5600
5601 return 0; /* "we did not close fd" */
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005602}
5603
Denys Vlasenko32fdf2f2017-07-31 04:32:06 +02005604static int
5605internally_opened_fd(int fd, struct redirtab *sq)
5606{
5607 int i;
5608#if JOBS
5609 if (fd == ttyfd)
5610 return 1;
5611#endif
5612 /* If this one of script's fds? */
5613 if (fd != 0) {
5614 struct parsefile *pf = g_parsefile;
5615 while (pf) {
5616 if (fd == pf->pf_fd)
5617 return 1;
5618 pf = pf->prev;
5619 }
5620 }
5621
5622 if (sq) for (i = 0; i < sq->pair_count && sq->two_fd[i].orig_fd != EMPTY; i++) {
5623 if (fd == sq->two_fd[i].moved_to)
5624 return 1;
5625 }
5626 return 0;
5627}
5628
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005629/*
5630 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
5631 * old file descriptors are stashed away so that the redirection can be
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005632 * undone by calling popredir.
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005633 */
5634/* flags passed to redirect */
5635#define REDIR_PUSH 01 /* save previous values of file descriptors */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005636static void
5637redirect(union node *redir, int flags)
5638{
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005639 struct redirtab *sv;
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005640
Denys Vlasenko1c79aeb2017-07-29 22:51:52 +02005641 if (!redir)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005642 return;
Denys Vlasenko035486c2017-07-31 04:09:19 +02005643
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005644 sv = NULL;
5645 INT_OFF;
Denys Vlasenko1c79aeb2017-07-29 22:51:52 +02005646 if (flags & REDIR_PUSH)
5647 sv = redirlist;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005648 do {
Denys Vlasenko035486c2017-07-31 04:09:19 +02005649 int fd;
5650 int newfd;
5651 int close_fd;
5652 int closed;
5653
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00005654 fd = redir->nfile.fd;
Denis Vlasenko0b769642008-07-24 07:54:57 +00005655 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
Denys Vlasenko035486c2017-07-31 04:09:19 +02005656 //bb_error_msg("doing %d > %d", fd, newfd);
5657 newfd = redir->ndup.dupfd;
5658 close_fd = -1;
Denis Vlasenko0b769642008-07-24 07:54:57 +00005659 } else {
5660 newfd = openredirect(redir); /* always >= 0 */
5661 if (fd == newfd) {
Denys Vlasenko035486c2017-07-31 04:09:19 +02005662 /* open() gave us precisely the fd we wanted.
5663 * This means that this fd was not busy
5664 * (not opened to anywhere).
5665 * Remember to close it on restore:
5666 */
5667 add_squirrel_closed(sv, fd);
Denis Vlasenko0b769642008-07-24 07:54:57 +00005668 continue;
5669 }
Denys Vlasenko035486c2017-07-31 04:09:19 +02005670 close_fd = newfd;
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005671 }
Denys Vlasenko035486c2017-07-31 04:09:19 +02005672
5673 if (fd == newfd)
5674 continue;
5675
5676 /* if "N>FILE": move newfd to fd */
5677 /* if "N>&M": dup newfd to fd */
5678 /* if "N>&-": close fd (newfd is -1) */
5679
5680 IF_BASH_REDIR_OUTPUT(redirect_more:)
5681
5682 closed = save_fd_on_redirect(fd, /*avoid:*/ newfd, sv);
5683 if (newfd == -1) {
5684 /* "N>&-" means "close me" */
5685 if (!closed) {
5686 /* ^^^ optimization: saving may already
5687 * have closed it. If not... */
5688 close(fd);
Denis Vlasenko22f74142008-07-24 22:34:43 +00005689 }
Denys Vlasenko035486c2017-07-31 04:09:19 +02005690 } else {
Denys Vlasenko32fdf2f2017-07-31 04:32:06 +02005691 /* if newfd is a script fd or saved fd, simulate EBADF */
5692 if (internally_opened_fd(newfd, sv)) {
5693 errno = EBADF;
5694 ash_msg_and_raise_perror("%d", newfd);
5695 }
Denys Vlasenko64774602016-10-26 15:24:30 +02005696 dup2_or_raise(newfd, fd);
Denys Vlasenko035486c2017-07-31 04:09:19 +02005697 if (close_fd >= 0) /* "N>FILE" or ">&FILE" or heredoc? */
5698 close(close_fd);
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01005699#if BASH_REDIR_OUTPUT
Denys Vlasenko035486c2017-07-31 04:09:19 +02005700 if (redir->nfile.type == NTO2 && fd == 1) {
5701 /* ">&FILE". we already redirected to 1, now copy 1 to 2 */
5702 fd = 2;
5703 newfd = 1;
5704 close_fd = -1;
5705 goto redirect_more;
5706 }
Denis Vlasenko559691a2008-10-05 18:39:31 +00005707#endif
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005708 }
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00005709 } while ((redir = redir->nfile.next) != NULL);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005710 INT_ON;
Denys Vlasenkod07a15b2017-07-30 16:51:05 +02005711
5712//dash:#define REDIR_SAVEFD2 03 /* set preverrout */
5713#define REDIR_SAVEFD2 0
5714 // dash has a bug: since REDIR_SAVEFD2=3 and REDIR_PUSH=1, this test
5715 // triggers for pure REDIR_PUSH too. Thus, this is done almost always,
5716 // not only for calls with flags containing REDIR_SAVEFD2.
Denys Vlasenko035486c2017-07-31 04:09:19 +02005717 // We do this unconditionally (see save_fd_on_redirect()).
Denys Vlasenkod07a15b2017-07-30 16:51:05 +02005718 //if ((flags & REDIR_SAVEFD2) && copied_fd2 >= 0)
5719 // preverrout_fd = copied_fd2;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005720}
5721
Denys Vlasenko170f93e2017-07-29 18:54:53 +02005722static int
5723redirectsafe(union node *redir, int flags)
5724{
5725 int err;
5726 volatile int saveint;
5727 struct jmploc *volatile savehandler = exception_handler;
5728 struct jmploc jmploc;
5729
5730 SAVE_INT(saveint);
5731 /* "echo 9>/dev/null; echo >&9; echo result: $?" - result should be 1, not 2! */
Denys Vlasenko035486c2017-07-31 04:09:19 +02005732 err = setjmp(jmploc.loc); /* was = setjmp(jmploc.loc) * 2; */
Denys Vlasenko170f93e2017-07-29 18:54:53 +02005733 if (!err) {
5734 exception_handler = &jmploc;
5735 redirect(redir, flags);
5736 }
5737 exception_handler = savehandler;
5738 if (err && exception_type != EXERROR)
5739 longjmp(exception_handler->loc, 1);
5740 RESTORE_INT(saveint);
5741 return err;
5742}
5743
Denys Vlasenko1c79aeb2017-07-29 22:51:52 +02005744static struct redirtab*
5745pushredir(union node *redir)
5746{
5747 struct redirtab *sv;
5748 int i;
5749
5750 if (!redir)
5751 return redirlist;
5752
5753 i = 0;
5754 do {
5755 i++;
5756#if BASH_REDIR_OUTPUT
5757 if (redir->nfile.type == NTO2)
5758 i++;
5759#endif
5760 redir = redir->nfile.next;
5761 } while (redir);
5762
5763 sv = ckzalloc(sizeof(*sv) + i * sizeof(sv->two_fd[0]));
5764 sv->pair_count = i;
5765 while (--i >= 0)
Denys Vlasenko035486c2017-07-31 04:09:19 +02005766 sv->two_fd[i].orig_fd = sv->two_fd[i].moved_to = EMPTY;
Denys Vlasenko1c79aeb2017-07-29 22:51:52 +02005767 sv->next = redirlist;
5768 redirlist = sv;
5769 return sv->next;
5770}
5771
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005772/*
5773 * Undo the effects of the last redirection.
5774 */
5775static void
Denys Vlasenko035486c2017-07-31 04:09:19 +02005776popredir(int drop)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005777{
5778 struct redirtab *rp;
5779 int i;
5780
Denys Vlasenkoeaf94362016-10-25 21:46:03 +02005781 if (redirlist == NULL)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005782 return;
5783 INT_OFF;
5784 rp = redirlist;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005785 for (i = 0; i < rp->pair_count; i++) {
Denys Vlasenko035486c2017-07-31 04:09:19 +02005786 int fd = rp->two_fd[i].orig_fd;
5787 int copy = rp->two_fd[i].moved_to;
Denis Vlasenko22f74142008-07-24 22:34:43 +00005788 if (copy == CLOSED) {
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005789 if (!drop)
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005790 close(fd);
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005791 continue;
5792 }
Denis Vlasenko22f74142008-07-24 22:34:43 +00005793 if (copy != EMPTY) {
Denys Vlasenko035486c2017-07-31 04:09:19 +02005794 if (!drop) {
Denis Vlasenko5a867312008-07-24 19:46:38 +00005795 /*close(fd);*/
Denys Vlasenko64774602016-10-26 15:24:30 +02005796 dup2_or_raise(copy, fd);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005797 }
Denys Vlasenko035486c2017-07-31 04:09:19 +02005798 close(copy);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005799 }
5800 }
5801 redirlist = rp->next;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005802 free(rp);
5803 INT_ON;
5804}
5805
Denys Vlasenko1c79aeb2017-07-29 22:51:52 +02005806static void
5807unwindredir(struct redirtab *stop)
5808{
5809 while (redirlist != stop)
Denys Vlasenko035486c2017-07-31 04:09:19 +02005810 popredir(/*drop:*/ 0);
Denys Vlasenko1c79aeb2017-07-29 22:51:52 +02005811}
5812
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005813
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005814/* ============ Routines to expand arguments to commands
5815 *
5816 * We have to deal with backquotes, shell variables, and file metacharacters.
5817 */
5818
Denys Vlasenko0b883582016-12-23 16:49:07 +01005819#if ENABLE_FEATURE_SH_MATH
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005820static arith_t
5821ash_arith(const char *s)
5822{
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005823 arith_state_t math_state;
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005824 arith_t result;
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005825
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005826 math_state.lookupvar = lookupvar;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02005827 math_state.setvar = setvar0;
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005828 //math_state.endofname = endofname;
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005829
5830 INT_OFF;
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005831 result = arith(&math_state, s);
Denys Vlasenko063847d2010-09-15 13:33:02 +02005832 if (math_state.errmsg)
5833 ash_msg_and_raise_error(math_state.errmsg);
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005834 INT_ON;
5835
5836 return result;
5837}
Denis Vlasenko448d30e2008-06-27 00:24:11 +00005838#endif
Denys Vlasenkobaa41c72018-01-10 13:22:25 +01005839#if BASH_SUBSTR
5840# if ENABLE_FEATURE_SH_MATH
5841static int substr_atoi(const char *s)
5842{
5843 arith_t t = ash_arith(s);
5844 if (sizeof(t) > sizeof(int)) {
5845 /* clamp very large or very large negative nums for ${v:N:M}:
5846 * else "${v:0:0x100000001}" would work as "${v:0:1}"
5847 */
5848 if (t > INT_MAX)
5849 t = INT_MAX;
5850 if (t < INT_MIN)
5851 t = INT_MIN;
5852 }
5853 return t;
5854}
5855# else
5856# define substr_atoi(s) number(s)
5857# endif
5858#endif
Denis Vlasenko448d30e2008-06-27 00:24:11 +00005859
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005860/*
5861 * expandarg flags
5862 */
5863#define EXP_FULL 0x1 /* perform word splitting & file globbing */
5864#define EXP_TILDE 0x2 /* do normal tilde expansion */
5865#define EXP_VARTILDE 0x4 /* expand tildes in an assignment */
5866#define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */
Denys Vlasenkodb74c6c2016-10-24 21:12:33 +02005867/* ^^^^^^^^^^^^^^ this is meant to support constructs such as "cmd >file*.txt"
5868 * POSIX says for this case:
5869 * Pathname expansion shall not be performed on the word by a
5870 * non-interactive shell; an interactive shell may perform it, but shall
5871 * do so only when the expansion would result in one word.
5872 * Currently, our code complies to the above rule by never globbing
5873 * redirection filenames.
5874 * Bash performs globbing, unless it is non-interactive and in POSIX mode.
5875 * (this means that on a typical Linux distro, bash almost always
5876 * performs globbing, and thus diverges from what we do).
5877 */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005878#define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */
Ron Yorston549deab2015-05-18 09:57:51 +02005879#define EXP_QPAT 0x20 /* pattern in quoted parameter expansion */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005880#define EXP_VARTILDE2 0x40 /* expand tildes after colons only */
5881#define EXP_WORD 0x80 /* expand word in parameter expansion */
Ron Yorston3df47f92015-05-18 09:53:26 +02005882#define EXP_QUOTED 0x100 /* expand word in double quotes */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005883/*
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005884 * rmescape() flags
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005885 */
5886#define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
5887#define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005888#define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */
5889#define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */
5890
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005891/* Add CTLESC when necessary. */
Denys Vlasenko2990aa42017-07-25 17:37:57 +02005892#define QUOTES_ESC (EXP_FULL | EXP_CASE | EXP_QPAT)
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005893/* Do not skip NUL characters. */
5894#define QUOTES_KEEPNUL EXP_TILDE
5895
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005896/*
5897 * Structure specifying which parts of the string should be searched
5898 * for IFS characters.
5899 */
5900struct ifsregion {
5901 struct ifsregion *next; /* next region in list */
5902 int begoff; /* offset of start of region */
5903 int endoff; /* offset of end of region */
5904 int nulonly; /* search for nul bytes only */
5905};
5906
5907struct arglist {
5908 struct strlist *list;
5909 struct strlist **lastp;
5910};
5911
5912/* output of current string */
5913static char *expdest;
5914/* list of back quote expressions */
5915static struct nodelist *argbackq;
5916/* first struct in list of ifs regions */
5917static struct ifsregion ifsfirst;
5918/* last struct in list */
5919static struct ifsregion *ifslastp;
5920/* holds expanded arg list */
5921static struct arglist exparg;
5922
5923/*
5924 * Our own itoa().
Denys Vlasenkocf3a7962017-07-26 14:38:19 +02005925 * cvtnum() is used even if math support is off (to prepare $? values and such).
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005926 */
5927static int
5928cvtnum(arith_t num)
5929{
5930 int len;
5931
Denys Vlasenkocf3a7962017-07-26 14:38:19 +02005932 /* 32-bit and wider ints require buffer size of bytes*3 (or less) */
5933 len = sizeof(arith_t) * 3;
5934 /* If narrower: worst case, 1-byte ints: need 5 bytes: "-127<NUL>" */
5935 if (sizeof(arith_t) < 4) len += 2;
5936
5937 expdest = makestrspace(len, expdest);
5938 len = fmtstr(expdest, len, ARITH_FMT, num);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005939 STADJUST(len, expdest);
5940 return len;
5941}
5942
Denys Vlasenko455e4222016-10-27 14:45:13 +02005943/*
5944 * Break the argument string into pieces based upon IFS and add the
5945 * strings to the argument list. The regions of the string to be
5946 * searched for IFS characters have been stored by recordregion.
5947 */
5948static void
5949ifsbreakup(char *string, struct arglist *arglist)
5950{
5951 struct ifsregion *ifsp;
5952 struct strlist *sp;
5953 char *start;
5954 char *p;
5955 char *q;
5956 const char *ifs, *realifs;
5957 int ifsspc;
5958 int nulonly;
5959
5960 start = string;
5961 if (ifslastp != NULL) {
5962 ifsspc = 0;
5963 nulonly = 0;
5964 realifs = ifsset() ? ifsval() : defifs;
5965 ifsp = &ifsfirst;
5966 do {
5967 p = string + ifsp->begoff;
5968 nulonly = ifsp->nulonly;
5969 ifs = nulonly ? nullstr : realifs;
5970 ifsspc = 0;
5971 while (p < string + ifsp->endoff) {
5972 q = p;
5973 if ((unsigned char)*p == CTLESC)
5974 p++;
5975 if (!strchr(ifs, *p)) {
5976 p++;
5977 continue;
5978 }
5979 if (!nulonly)
5980 ifsspc = (strchr(defifs, *p) != NULL);
5981 /* Ignore IFS whitespace at start */
5982 if (q == start && ifsspc) {
5983 p++;
5984 start = p;
5985 continue;
5986 }
5987 *q = '\0';
5988 sp = stzalloc(sizeof(*sp));
5989 sp->text = start;
5990 *arglist->lastp = sp;
5991 arglist->lastp = &sp->next;
5992 p++;
5993 if (!nulonly) {
5994 for (;;) {
5995 if (p >= string + ifsp->endoff) {
5996 break;
5997 }
5998 q = p;
5999 if ((unsigned char)*p == CTLESC)
6000 p++;
6001 if (strchr(ifs, *p) == NULL) {
6002 p = q;
6003 break;
6004 }
6005 if (strchr(defifs, *p) == NULL) {
6006 if (ifsspc) {
6007 p++;
6008 ifsspc = 0;
6009 } else {
6010 p = q;
6011 break;
6012 }
6013 } else
6014 p++;
6015 }
6016 }
6017 start = p;
6018 } /* while */
6019 ifsp = ifsp->next;
6020 } while (ifsp != NULL);
6021 if (nulonly)
6022 goto add;
6023 }
6024
6025 if (!*start)
6026 return;
6027
6028 add:
6029 sp = stzalloc(sizeof(*sp));
6030 sp->text = start;
6031 *arglist->lastp = sp;
6032 arglist->lastp = &sp->next;
6033}
6034
6035static void
6036ifsfree(void)
6037{
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02006038 struct ifsregion *p = ifsfirst.next;
6039
6040 if (!p)
6041 goto out;
Denys Vlasenko455e4222016-10-27 14:45:13 +02006042
6043 INT_OFF;
Denys Vlasenko455e4222016-10-27 14:45:13 +02006044 do {
6045 struct ifsregion *ifsp;
6046 ifsp = p->next;
6047 free(p);
6048 p = ifsp;
6049 } while (p);
Denys Vlasenko455e4222016-10-27 14:45:13 +02006050 ifsfirst.next = NULL;
6051 INT_ON;
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02006052 out:
6053 ifslastp = NULL;
Denys Vlasenko455e4222016-10-27 14:45:13 +02006054}
6055
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006056static size_t
6057esclen(const char *start, const char *p)
6058{
6059 size_t esc = 0;
6060
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006061 while (p > start && (unsigned char)*--p == CTLESC) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006062 esc++;
6063 }
6064 return esc;
6065}
6066
6067/*
6068 * Remove any CTLESC characters from a string.
6069 */
Denys Vlasenko740058b2018-01-09 17:01:00 +01006070#if !BASH_PATTERN_SUBST
6071#define rmescapes(str, flag, slash_position) \
6072 rmescapes(str, flag)
6073#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006074static char *
Denys Vlasenko740058b2018-01-09 17:01:00 +01006075rmescapes(char *str, int flag, int *slash_position)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006076{
Ron Yorston417622c2015-05-18 09:59:14 +02006077 static const char qchars[] ALIGN1 = {
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006078 IF_BASH_PATTERN_SUBST('/',) CTLESC, CTLQUOTEMARK, '\0' };
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00006079
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006080 char *p, *q, *r;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006081 unsigned inquotes;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006082 unsigned protect_against_glob;
6083 unsigned globbing;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006084
Denys Vlasenko740058b2018-01-09 17:01:00 +01006085 p = strpbrk(str, qchars IF_BASH_PATTERN_SUBST(+ !slash_position));
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006086 if (!p)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006087 return str;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006088
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006089 q = p;
6090 r = str;
6091 if (flag & RMESCAPE_ALLOC) {
6092 size_t len = p - str;
6093 size_t fulllen = len + strlen(p) + 1;
6094
6095 if (flag & RMESCAPE_GROW) {
Colin Watson3963d942010-04-26 14:21:27 +02006096 int strloc = str - (char *)stackblock();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006097 r = makestrspace(fulllen, expdest);
Colin Watson3963d942010-04-26 14:21:27 +02006098 /* p and str may be invalidated by makestrspace */
6099 str = (char *)stackblock() + strloc;
6100 p = str + len;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006101 } else if (flag & RMESCAPE_HEAP) {
6102 r = ckmalloc(fulllen);
6103 } else {
6104 r = stalloc(fulllen);
6105 }
6106 q = r;
6107 if (len > 0) {
Denys Vlasenko5ace96a2017-07-23 21:46:02 +02006108 q = (char *)mempcpy(q, str, len);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006109 }
6110 }
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006111
Ron Yorston549deab2015-05-18 09:57:51 +02006112 inquotes = 0;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006113 globbing = flag & RMESCAPE_GLOB;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006114 protect_against_glob = globbing;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006115 while (*p) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006116 if ((unsigned char)*p == CTLQUOTEMARK) {
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006117// Note: both inquotes and protect_against_glob only affect whether
Denys Vlasenkofda9faf2017-07-05 19:10:21 +02006118// CTLESC,<ch> gets converted to <ch> or to \<ch>
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006119 inquotes = ~inquotes;
6120 p++;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006121 protect_against_glob = globbing;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006122 continue;
6123 }
Ron Yorston549deab2015-05-18 09:57:51 +02006124 if ((unsigned char)*p == CTLESC) {
6125 p++;
Denys Vlasenko13f20912016-09-25 20:54:25 +02006126#if DEBUG
6127 if (*p == '\0')
6128 ash_msg_and_raise_error("CTLESC at EOL (shouldn't happen)");
6129#endif
Ron Yorston549deab2015-05-18 09:57:51 +02006130 if (protect_against_glob) {
Denys Vlasenkofda9faf2017-07-05 19:10:21 +02006131 /*
6132 * We used to trust glob() and fnmatch() to eat
6133 * superfluous escapes (\z where z has no
6134 * special meaning anyway). But this causes
6135 * bugs such as string of one greek letter rho
Denys Vlasenkoed79a632017-07-05 19:20:43 +02006136 * (unicode-encoded as two bytes "cf,81")
Denys Vlasenkofda9faf2017-07-05 19:10:21 +02006137 * getting encoded as "cf,CTLESC,81"
6138 * and here, converted to "cf,\,81" -
6139 * which does not go well with some flavors
Denys Vlasenko92b8d9c2017-07-05 19:13:44 +02006140 * of fnmatch() in unicode locales
6141 * (for example, glibc <= 2.22).
Denys Vlasenkofda9faf2017-07-05 19:10:21 +02006142 *
6143 * Lets add "\" only on the chars which need it.
Denys Vlasenko4142f012017-07-05 22:19:28 +02006144 * Testcases for less obvious chars are shown.
Denys Vlasenkofda9faf2017-07-05 19:10:21 +02006145 */
6146 if (*p == '*'
6147 || *p == '?'
6148 || *p == '['
Denys Vlasenko4142f012017-07-05 22:19:28 +02006149 || *p == '\\' /* case '\' in \\ ) echo ok;; *) echo WRONG;; esac */
6150 || *p == ']' /* case ']' in [a\]] ) echo ok;; *) echo WRONG;; esac */
6151 || *p == '-' /* case '-' in [a\-c]) echo ok;; *) echo WRONG;; esac */
6152 || *p == '!' /* case '!' in [\!] ) echo ok;; *) echo WRONG;; esac */
6153 /* Some libc support [^negate], that's why "^" also needs love */
6154 || *p == '^' /* case '^' in [\^] ) echo ok;; *) echo WRONG;; esac */
Denys Vlasenkofda9faf2017-07-05 19:10:21 +02006155 ) {
6156 *q++ = '\\';
6157 }
Ron Yorston549deab2015-05-18 09:57:51 +02006158 }
6159 } else if (*p == '\\' && !inquotes) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006160 /* naked back slash */
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006161 protect_against_glob = 0;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006162 goto copy;
6163 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006164#if BASH_PATTERN_SUBST
Denys Vlasenko740058b2018-01-09 17:01:00 +01006165 else if (slash_position && p == str + *slash_position) {
6166 /* stop handling globbing */
6167 globbing = 0;
6168 *slash_position = q - r;
6169 slash_position = NULL;
Ron Yorston417622c2015-05-18 09:59:14 +02006170 }
6171#endif
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006172 protect_against_glob = globbing;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006173 copy:
6174 *q++ = *p++;
6175 }
6176 *q = '\0';
6177 if (flag & RMESCAPE_GROW) {
6178 expdest = r;
6179 STADJUST(q - r + 1, expdest);
6180 }
6181 return r;
6182}
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006183#define pmatch(a, b) !fnmatch((a), (b), 0)
6184
6185/*
6186 * Prepare a pattern for a expmeta (internal glob(3)) call.
6187 *
6188 * Returns an stalloced string.
6189 */
6190static char *
Ron Yorston549deab2015-05-18 09:57:51 +02006191preglob(const char *pattern, int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006192{
Denys Vlasenko740058b2018-01-09 17:01:00 +01006193 return rmescapes((char *)pattern, flag | RMESCAPE_GLOB, NULL);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006194}
6195
6196/*
6197 * Put a string on the stack.
6198 */
6199static void
6200memtodest(const char *p, size_t len, int syntax, int quotes)
6201{
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006202 char *q;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006203
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006204 if (!len)
6205 return;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006206
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006207 q = makestrspace((quotes & QUOTES_ESC) ? len * 2 : len, expdest);
6208
6209 do {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006210 unsigned char c = *p++;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006211 if (c) {
Denys Vlasenko2fe66b12016-12-12 17:39:12 +01006212 if (quotes & QUOTES_ESC) {
6213 int n = SIT(c, syntax);
6214 if (n == CCTL
6215 || (((quotes & EXP_FULL) || syntax != BASESYNTAX)
6216 && n == CBACK
6217 )
6218 ) {
6219 USTPUTC(CTLESC, q);
6220 }
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02006221 }
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006222 } else if (!(quotes & QUOTES_KEEPNUL))
6223 continue;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006224 USTPUTC(c, q);
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006225 } while (--len);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006226
6227 expdest = q;
6228}
6229
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006230static size_t
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006231strtodest(const char *p, int syntax, int quotes)
6232{
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006233 size_t len = strlen(p);
6234 memtodest(p, len, syntax, quotes);
6235 return len;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006236}
6237
6238/*
6239 * Record the fact that we have to scan this region of the
6240 * string for IFS characters.
6241 */
6242static void
6243recordregion(int start, int end, int nulonly)
6244{
6245 struct ifsregion *ifsp;
6246
6247 if (ifslastp == NULL) {
6248 ifsp = &ifsfirst;
6249 } else {
6250 INT_OFF;
Denis Vlasenko597906c2008-02-20 16:38:54 +00006251 ifsp = ckzalloc(sizeof(*ifsp));
6252 /*ifsp->next = NULL; - ckzalloc did it */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006253 ifslastp->next = ifsp;
6254 INT_ON;
6255 }
6256 ifslastp = ifsp;
6257 ifslastp->begoff = start;
6258 ifslastp->endoff = end;
6259 ifslastp->nulonly = nulonly;
6260}
6261
6262static void
6263removerecordregions(int endoff)
6264{
6265 if (ifslastp == NULL)
6266 return;
6267
6268 if (ifsfirst.endoff > endoff) {
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006269 while (ifsfirst.next) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006270 struct ifsregion *ifsp;
6271 INT_OFF;
6272 ifsp = ifsfirst.next->next;
6273 free(ifsfirst.next);
6274 ifsfirst.next = ifsp;
6275 INT_ON;
6276 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006277 if (ifsfirst.begoff > endoff) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006278 ifslastp = NULL;
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006279 } else {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006280 ifslastp = &ifsfirst;
6281 ifsfirst.endoff = endoff;
6282 }
6283 return;
6284 }
6285
6286 ifslastp = &ifsfirst;
6287 while (ifslastp->next && ifslastp->next->begoff < endoff)
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006288 ifslastp = ifslastp->next;
6289 while (ifslastp->next) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006290 struct ifsregion *ifsp;
6291 INT_OFF;
6292 ifsp = ifslastp->next->next;
6293 free(ifslastp->next);
6294 ifslastp->next = ifsp;
6295 INT_ON;
6296 }
6297 if (ifslastp->endoff > endoff)
6298 ifslastp->endoff = endoff;
6299}
6300
6301static char *
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006302exptilde(char *startp, char *p, int flags)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006303{
Denys Vlasenkocd716832009-11-28 22:14:02 +01006304 unsigned char c;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006305 char *name;
6306 struct passwd *pw;
6307 const char *home;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006308 int quotes = flags & QUOTES_ESC;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006309
6310 name = p + 1;
6311
6312 while ((c = *++p) != '\0') {
6313 switch (c) {
6314 case CTLESC:
6315 return startp;
6316 case CTLQUOTEMARK:
6317 return startp;
6318 case ':':
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006319 if (flags & EXP_VARTILDE)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006320 goto done;
6321 break;
6322 case '/':
6323 case CTLENDVAR:
6324 goto done;
6325 }
6326 }
6327 done:
6328 *p = '\0';
6329 if (*name == '\0') {
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02006330 home = lookupvar("HOME");
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006331 } else {
6332 pw = getpwnam(name);
6333 if (pw == NULL)
6334 goto lose;
6335 home = pw->pw_dir;
6336 }
6337 if (!home || !*home)
6338 goto lose;
6339 *p = c;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006340 strtodest(home, SQSYNTAX, quotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006341 return p;
6342 lose:
6343 *p = c;
6344 return startp;
6345}
6346
6347/*
6348 * Execute a command inside back quotes. If it's a builtin command, we
6349 * want to save its output in a block obtained from malloc. Otherwise
6350 * we fork off a subprocess and get the output of the command via a pipe.
6351 * Should be called with interrupts off.
6352 */
6353struct backcmd { /* result of evalbackcmd */
6354 int fd; /* file descriptor to read from */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006355 int nleft; /* number of chars in buffer */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00006356 char *buf; /* buffer */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006357 struct job *jp; /* job structure for command */
6358};
6359
6360/* These forward decls are needed to use "eval" code for backticks handling: */
Denys Vlasenko1e3e2cc2017-07-25 20:31:14 +02006361/* flags in argument to evaltree */
6362#define EV_EXIT 01 /* exit after evaluating tree */
6363#define EV_TESTED 02 /* exit status is checked; ignore -e flag */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02006364static int evaltree(union node *, int);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006365
Denys Vlasenko619d9b52017-07-28 15:28:33 +02006366/* An evaltree() which is known to never return.
6367 * Used to use an alias:
6368 * static int evaltreenr(union node *, int) __attribute__((alias("evaltree"),__noreturn__));
6369 * but clang was reported to "transfer" noreturn-ness to evaltree() as well.
6370 */
6371static ALWAYS_INLINE NORETURN void
6372evaltreenr(union node *n, int flags)
6373{
6374 evaltree(n, flags);
6375 bb_unreachable(abort());
6376 /* NOTREACHED */
6377}
6378
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02006379static void FAST_FUNC
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006380evalbackcmd(union node *n, struct backcmd *result)
6381{
Denys Vlasenko579ad102016-10-25 21:10:20 +02006382 int pip[2];
6383 struct job *jp;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006384
6385 result->fd = -1;
6386 result->buf = NULL;
6387 result->nleft = 0;
6388 result->jp = NULL;
Denys Vlasenko579ad102016-10-25 21:10:20 +02006389 if (n == NULL) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006390 goto out;
Denys Vlasenko579ad102016-10-25 21:10:20 +02006391 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006392
Denys Vlasenko579ad102016-10-25 21:10:20 +02006393 if (pipe(pip) < 0)
Denys Vlasenko12ffefb2017-08-23 14:52:56 +02006394 ash_msg_and_raise_perror("can't create pipe");
Denys Vlasenko579ad102016-10-25 21:10:20 +02006395 jp = makejob(/*n,*/ 1);
6396 if (forkshell(jp, n, FORK_NOJOB) == 0) {
Denys Vlasenko70392332016-10-27 02:31:55 +02006397 /* child */
Denys Vlasenko579ad102016-10-25 21:10:20 +02006398 FORCE_INT_ON;
6399 close(pip[0]);
6400 if (pip[1] != 1) {
6401 /*close(1);*/
Denys Vlasenko64774602016-10-26 15:24:30 +02006402 dup2_or_raise(pip[1], 1);
Denys Vlasenko579ad102016-10-25 21:10:20 +02006403 close(pip[1]);
6404 }
Denys Vlasenko960ca382016-10-25 18:12:15 +02006405/* TODO: eflag clearing makes the following not abort:
6406 * ash -c 'set -e; z=$(false;echo foo); echo $z'
6407 * which is what bash does (unless it is in POSIX mode).
6408 * dash deleted "eflag = 0" line in the commit
6409 * Date: Mon, 28 Jun 2010 17:11:58 +1000
6410 * [EVAL] Don't clear eflag in evalbackcmd
6411 * For now, preserve bash-like behavior, it seems to be somewhat more useful:
6412 */
Denys Vlasenko579ad102016-10-25 21:10:20 +02006413 eflag = 0;
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02006414 ifsfree();
Denys Vlasenko619d9b52017-07-28 15:28:33 +02006415 evaltreenr(n, EV_EXIT);
Denys Vlasenko579ad102016-10-25 21:10:20 +02006416 /* NOTREACHED */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006417 }
Denys Vlasenko70392332016-10-27 02:31:55 +02006418 /* parent */
Denys Vlasenko579ad102016-10-25 21:10:20 +02006419 close(pip[1]);
6420 result->fd = pip[0];
6421 result->jp = jp;
6422
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006423 out:
6424 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
6425 result->fd, result->buf, result->nleft, result->jp));
6426}
6427
6428/*
6429 * Expand stuff in backwards quotes.
6430 */
6431static void
Ron Yorston549deab2015-05-18 09:57:51 +02006432expbackq(union node *cmd, int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006433{
6434 struct backcmd in;
6435 int i;
6436 char buf[128];
6437 char *p;
6438 char *dest;
6439 int startloc;
Ron Yorston549deab2015-05-18 09:57:51 +02006440 int syntax = flag & EXP_QUOTED ? DQSYNTAX : BASESYNTAX;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006441 struct stackmark smark;
6442
6443 INT_OFF;
Denys Vlasenko60ca8342016-09-30 11:21:21 +02006444 startloc = expdest - (char *)stackblock();
6445 pushstackmark(&smark, startloc);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006446 evalbackcmd(cmd, &in);
6447 popstackmark(&smark);
6448
6449 p = in.buf;
6450 i = in.nleft;
6451 if (i == 0)
6452 goto read;
6453 for (;;) {
Ron Yorston549deab2015-05-18 09:57:51 +02006454 memtodest(p, i, syntax, flag & QUOTES_ESC);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006455 read:
6456 if (in.fd < 0)
6457 break;
Ron Yorston61d6ae22015-04-19 10:50:25 +01006458 i = nonblock_immune_read(in.fd, buf, sizeof(buf));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006459 TRACE(("expbackq: read returns %d\n", i));
6460 if (i <= 0)
6461 break;
6462 p = buf;
6463 }
6464
Denis Vlasenko60818682007-09-28 22:07:23 +00006465 free(in.buf);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006466 if (in.fd >= 0) {
6467 close(in.fd);
6468 back_exitstatus = waitforjob(in.jp);
6469 }
6470 INT_ON;
6471
6472 /* Eat all trailing newlines */
6473 dest = expdest;
6474 for (; dest > (char *)stackblock() && dest[-1] == '\n';)
6475 STUNPUTC(dest);
6476 expdest = dest;
6477
Ron Yorston549deab2015-05-18 09:57:51 +02006478 if (!(flag & EXP_QUOTED))
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006479 recordregion(startloc, dest - (char *)stackblock(), 0);
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006480 TRACE(("evalbackq: size:%d:'%.*s'\n",
6481 (int)((dest - (char *)stackblock()) - startloc),
6482 (int)((dest - (char *)stackblock()) - startloc),
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006483 stackblock() + startloc));
6484}
6485
Denys Vlasenko0b883582016-12-23 16:49:07 +01006486#if ENABLE_FEATURE_SH_MATH
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006487/*
6488 * Expand arithmetic expression. Backup to start of expression,
6489 * evaluate, place result in (backed up) result, adjust string position.
6490 */
6491static void
Ron Yorston549deab2015-05-18 09:57:51 +02006492expari(int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006493{
6494 char *p, *start;
6495 int begoff;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006496 int len;
6497
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006498 /* ifsfree(); */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006499
6500 /*
6501 * This routine is slightly over-complicated for
6502 * efficiency. Next we scan backwards looking for the
6503 * start of arithmetic.
6504 */
6505 start = stackblock();
6506 p = expdest - 1;
6507 *p = '\0';
6508 p--;
Denys Vlasenko940c7202011-03-02 04:07:14 +01006509 while (1) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006510 int esc;
6511
Denys Vlasenkocd716832009-11-28 22:14:02 +01006512 while ((unsigned char)*p != CTLARI) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006513 p--;
6514#if DEBUG
6515 if (p < start) {
6516 ash_msg_and_raise_error("missing CTLARI (shouldn't happen)");
6517 }
6518#endif
6519 }
6520
6521 esc = esclen(start, p);
6522 if (!(esc % 2)) {
6523 break;
6524 }
6525
6526 p -= esc + 1;
Denys Vlasenko940c7202011-03-02 04:07:14 +01006527 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006528
6529 begoff = p - start;
6530
6531 removerecordregions(begoff);
6532
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006533 expdest = p;
6534
Ron Yorston549deab2015-05-18 09:57:51 +02006535 if (flag & QUOTES_ESC)
Denys Vlasenko740058b2018-01-09 17:01:00 +01006536 rmescapes(p + 1, 0, NULL);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006537
Ron Yorston549deab2015-05-18 09:57:51 +02006538 len = cvtnum(ash_arith(p + 1));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006539
Ron Yorston549deab2015-05-18 09:57:51 +02006540 if (!(flag & EXP_QUOTED))
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006541 recordregion(begoff, begoff + len, 0);
6542}
6543#endif
6544
6545/* argstr needs it */
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02006546static char *evalvar(char *p, int flags);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006547
6548/*
6549 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
6550 * characters to allow for further processing. Otherwise treat
6551 * $@ like $* since no splitting will be performed.
6552 */
6553static void
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02006554argstr(char *p, int flags)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006555{
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00006556 static const char spclchars[] ALIGN1 = {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006557 '=',
6558 ':',
6559 CTLQUOTEMARK,
6560 CTLENDVAR,
6561 CTLESC,
6562 CTLVAR,
6563 CTLBACKQ,
Denys Vlasenko0b883582016-12-23 16:49:07 +01006564#if ENABLE_FEATURE_SH_MATH
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006565 CTLENDARI,
6566#endif
Denys Vlasenkocd716832009-11-28 22:14:02 +01006567 '\0'
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006568 };
6569 const char *reject = spclchars;
Ron Yorston3df47f92015-05-18 09:53:26 +02006570 int breakall = (flags & (EXP_WORD | EXP_QUOTED)) == EXP_WORD;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006571 int inquotes;
6572 size_t length;
6573 int startloc;
6574
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006575 if (!(flags & EXP_VARTILDE)) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006576 reject += 2;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006577 } else if (flags & EXP_VARTILDE2) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006578 reject++;
6579 }
6580 inquotes = 0;
6581 length = 0;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006582 if (flags & EXP_TILDE) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006583 char *q;
6584
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006585 flags &= ~EXP_TILDE;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006586 tilde:
6587 q = p;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006588 if (*q == '~')
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006589 p = exptilde(p, q, flags);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006590 }
6591 start:
6592 startloc = expdest - (char *)stackblock();
6593 for (;;) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006594 unsigned char c;
6595
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006596 length += strcspn(p + length, reject);
Denys Vlasenkocd716832009-11-28 22:14:02 +01006597 c = p[length];
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006598 if (c) {
6599 if (!(c & 0x80)
Denys Vlasenko0b883582016-12-23 16:49:07 +01006600 IF_FEATURE_SH_MATH(|| c == CTLENDARI)
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006601 ) {
6602 /* c == '=' || c == ':' || c == CTLENDARI */
6603 length++;
6604 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006605 }
6606 if (length > 0) {
6607 int newloc;
6608 expdest = stack_nputstr(p, length, expdest);
6609 newloc = expdest - (char *)stackblock();
6610 if (breakall && !inquotes && newloc > startloc) {
6611 recordregion(startloc, newloc, 0);
6612 }
6613 startloc = newloc;
6614 }
6615 p += length + 1;
6616 length = 0;
6617
6618 switch (c) {
6619 case '\0':
6620 goto breakloop;
6621 case '=':
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006622 if (flags & EXP_VARTILDE2) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006623 p--;
6624 continue;
6625 }
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006626 flags |= EXP_VARTILDE2;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006627 reject++;
6628 /* fall through */
6629 case ':':
6630 /*
6631 * sort of a hack - expand tildes in variable
6632 * assignments (after the first '=' and after ':'s).
6633 */
6634 if (*--p == '~') {
6635 goto tilde;
6636 }
6637 continue;
6638 }
6639
6640 switch (c) {
6641 case CTLENDVAR: /* ??? */
6642 goto breakloop;
6643 case CTLQUOTEMARK:
Ron Yorston549deab2015-05-18 09:57:51 +02006644 inquotes ^= EXP_QUOTED;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006645 /* "$@" syntax adherence hack */
Ron Yorston549deab2015-05-18 09:57:51 +02006646 if (inquotes && !memcmp(p, dolatstr + 1, DOLATSTRLEN - 1)) {
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02006647 p = evalvar(p + 1, flags | inquotes) + 1;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006648 goto start;
6649 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006650 addquote:
Ron Yorston549deab2015-05-18 09:57:51 +02006651 if (flags & QUOTES_ESC) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006652 p--;
6653 length++;
6654 startloc++;
6655 }
6656 break;
6657 case CTLESC:
6658 startloc++;
6659 length++;
Ron Yorston549deab2015-05-18 09:57:51 +02006660
6661 /*
6662 * Quoted parameter expansion pattern: remove quote
6663 * unless inside inner quotes or we have a literal
6664 * backslash.
6665 */
6666 if (((flags | inquotes) & (EXP_QPAT | EXP_QUOTED)) ==
6667 EXP_QPAT && *p != '\\')
6668 break;
6669
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006670 goto addquote;
6671 case CTLVAR:
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02006672 TRACE(("argstr: evalvar('%s')\n", p));
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02006673 p = evalvar(p, flags | inquotes);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02006674 TRACE(("argstr: evalvar:'%s'\n", (char *)stackblock()));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006675 goto start;
6676 case CTLBACKQ:
Ron Yorston549deab2015-05-18 09:57:51 +02006677 expbackq(argbackq->n, flags | inquotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006678 argbackq = argbackq->next;
6679 goto start;
Denys Vlasenko0b883582016-12-23 16:49:07 +01006680#if ENABLE_FEATURE_SH_MATH
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006681 case CTLENDARI:
6682 p--;
Ron Yorston549deab2015-05-18 09:57:51 +02006683 expari(flags | inquotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006684 goto start;
6685#endif
6686 }
6687 }
Denys Vlasenko958581a2010-09-12 15:04:27 +02006688 breakloop: ;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006689}
6690
6691static char *
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006692scanleft(char *startp, char *rmesc, char *rmescend UNUSED_PARAM,
6693 char *pattern, int quotes, int zero)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006694{
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006695 char *loc, *loc2;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006696 char c;
6697
6698 loc = startp;
6699 loc2 = rmesc;
6700 do {
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006701 int match;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006702 const char *s = loc2;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006703
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006704 c = *loc2;
6705 if (zero) {
6706 *loc2 = '\0';
6707 s = rmesc;
6708 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006709 match = pmatch(pattern, s);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006710
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006711 *loc2 = c;
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006712 if (match)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006713 return loc;
Denys Vlasenkocd716832009-11-28 22:14:02 +01006714 if (quotes && (unsigned char)*loc == CTLESC)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006715 loc++;
6716 loc++;
6717 loc2++;
6718 } while (c);
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006719 return NULL;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006720}
6721
6722static char *
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006723scanright(char *startp, char *rmesc, char *rmescend,
6724 char *pattern, int quotes, int match_at_start)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006725{
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006726#if !ENABLE_ASH_OPTIMIZE_FOR_SIZE
6727 int try2optimize = match_at_start;
6728#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006729 int esc = 0;
6730 char *loc;
6731 char *loc2;
6732
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006733 /* If we called by "${v/pattern/repl}" or "${v//pattern/repl}":
6734 * startp="escaped_value_of_v" rmesc="raw_value_of_v"
6735 * rmescend=""(ptr to NUL in rmesc) pattern="pattern" quotes=match_at_start=1
6736 * Logic:
6737 * loc starts at NUL at the end of startp, loc2 starts at the end of rmesc,
6738 * and on each iteration they go back two/one char until they reach the beginning.
6739 * We try to find a match in "raw_value_of_v", "raw_value_of_", "raw_value_of" etc.
6740 */
6741 /* TODO: document in what other circumstances we are called. */
6742
6743 for (loc = pattern - 1, loc2 = rmescend; loc >= startp; loc2--) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006744 int match;
6745 char c = *loc2;
6746 const char *s = loc2;
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006747 if (match_at_start) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006748 *loc2 = '\0';
6749 s = rmesc;
6750 }
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006751 match = pmatch(pattern, s);
6752 //bb_error_msg("pmatch(pattern:'%s',s:'%s'):%d", pattern, s, match);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006753 *loc2 = c;
6754 if (match)
6755 return loc;
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006756#if !ENABLE_ASH_OPTIMIZE_FOR_SIZE
6757 if (try2optimize) {
6758 /* Maybe we can optimize this:
6759 * if pattern ends with unescaped *, we can avoid checking
Denys Vlasenko10ad6222017-04-17 16:13:32 +02006760 * shorter strings: if "foo*" doesn't match "raw_value_of_v",
6761 * it won't match truncated "raw_value_of_" strings too.
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006762 */
6763 unsigned plen = strlen(pattern);
6764 /* Does it end with "*"? */
6765 if (plen != 0 && pattern[--plen] == '*') {
6766 /* "xxxx*" is not escaped */
6767 /* "xxx\*" is escaped */
6768 /* "xx\\*" is not escaped */
6769 /* "x\\\*" is escaped */
6770 int slashes = 0;
6771 while (plen != 0 && pattern[--plen] == '\\')
6772 slashes++;
6773 if (!(slashes & 1))
6774 break; /* ends with unescaped "*" */
6775 }
6776 try2optimize = 0;
6777 }
6778#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006779 loc--;
6780 if (quotes) {
6781 if (--esc < 0) {
6782 esc = esclen(startp, loc);
6783 }
6784 if (esc % 2) {
6785 esc--;
6786 loc--;
6787 }
6788 }
6789 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006790 return NULL;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006791}
6792
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00006793static void varunset(const char *, const char *, const char *, int) NORETURN;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006794static void
6795varunset(const char *end, const char *var, const char *umsg, int varflags)
6796{
6797 const char *msg;
6798 const char *tail;
6799
6800 tail = nullstr;
6801 msg = "parameter not set";
6802 if (umsg) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006803 if ((unsigned char)*end == CTLENDVAR) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006804 if (varflags & VSNUL)
6805 tail = " or null";
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006806 } else {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006807 msg = umsg;
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006808 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006809 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006810 ash_msg_and_raise_error("%.*s: %s%s", (int)(end - var - 1), var, msg, tail);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006811}
6812
6813static const char *
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006814subevalvar(char *p, char *varname, int strloc, int subtype,
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02006815 int startloc, int varflags, int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006816{
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006817 struct nodelist *saveargbackq = argbackq;
Ron Yorston549deab2015-05-18 09:57:51 +02006818 int quotes = flag & QUOTES_ESC;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006819 char *startp;
6820 char *loc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006821 char *rmesc, *rmescend;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006822 char *str;
Denys Vlasenko0b4980c2012-09-25 12:49:29 +02006823 int amount, resetloc;
Denys Vlasenko740058b2018-01-09 17:01:00 +01006824 int argstr_flags;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006825 IF_BASH_PATTERN_SUBST(int workloc;)
Denys Vlasenko740058b2018-01-09 17:01:00 +01006826 IF_BASH_PATTERN_SUBST(int slash_pos;)
6827 IF_BASH_PATTERN_SUBST(char *repl;)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006828 int zero;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006829 char *(*scan)(char*, char*, char*, char*, int, int);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006830
Denys Vlasenko6040fe82010-09-12 15:03:16 +02006831 //bb_error_msg("subevalvar(p:'%s',varname:'%s',strloc:%d,subtype:%d,startloc:%d,varflags:%x,quotes:%d)",
6832 // p, varname, strloc, subtype, startloc, varflags, quotes);
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006833
Denys Vlasenko740058b2018-01-09 17:01:00 +01006834#if BASH_PATTERN_SUBST
Denys Vlasenkod1df1a72018-01-09 17:25:58 +01006835 /* For "${v/pattern/repl}", we must find the delimiter _before_
6836 * argstr() call expands possible variable references in pattern:
6837 * think about "v=a; a=a/; echo ${v/$a/r}" case.
6838 */
Denys Vlasenko740058b2018-01-09 17:01:00 +01006839 repl = NULL;
6840 if (subtype == VSREPLACE || subtype == VSREPLACEALL) {
6841 /* Find '/' and replace with NUL */
6842 repl = p;
6843 for (;;) {
6844 /* Handle escaped slashes, e.g. "${v/\//_}" (they are CTLESC'ed by this point) */
6845 if (*repl == '\0') {
6846 repl = NULL;
6847 break;
6848 }
6849 if (*repl == '/') {
6850 *repl = '\0';
6851 break;
6852 }
Denys Vlasenkod1df1a72018-01-09 17:25:58 +01006853 if ((unsigned char)*repl == CTLESC && repl[1])
Denys Vlasenko740058b2018-01-09 17:01:00 +01006854 repl++;
Denys Vlasenko740058b2018-01-09 17:01:00 +01006855 repl++;
6856 }
6857 }
6858#endif
6859 argstr_flags = EXP_TILDE;
6860 if (subtype != VSASSIGN && subtype != VSQUESTION)
6861 argstr_flags |= (flag & (EXP_QUOTED | EXP_QPAT) ? EXP_QPAT : EXP_CASE);
6862 argstr(p, argstr_flags);
6863#if BASH_PATTERN_SUBST
6864 slash_pos = -1;
6865 if (repl) {
6866 slash_pos = expdest - ((char *)stackblock() + strloc);
6867 STPUTC('/', expdest);
6868 argstr(repl + 1, argstr_flags);
6869 *repl = '/';
6870 }
6871#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006872 STPUTC('\0', expdest);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006873 argbackq = saveargbackq;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006874 startp = (char *)stackblock() + startloc;
Denys Vlasenko740058b2018-01-09 17:01:00 +01006875 //bb_error_msg("str1:'%s'", (char *)stackblock() + strloc);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006876
6877 switch (subtype) {
6878 case VSASSIGN:
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02006879 setvar0(varname, startp);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006880 amount = startp - expdest;
6881 STADJUST(amount, expdest);
6882 return startp;
6883
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006884 case VSQUESTION:
6885 varunset(p, varname, startp, varflags);
6886 /* NOTREACHED */
6887
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006888#if BASH_SUBSTR
Denys Vlasenko826360f2017-07-17 17:49:11 +02006889 case VSSUBSTR: {
6890 int pos, len, orig_len;
6891 char *colon;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006892
Denys Vlasenko826360f2017-07-17 17:49:11 +02006893 loc = str = stackblock() + strloc;
6894
Denys Vlasenko826360f2017-07-17 17:49:11 +02006895 /* Read POS in ${var:POS:LEN} */
6896 colon = strchr(loc, ':');
6897 if (colon) *colon = '\0';
Denys Vlasenkobaa41c72018-01-10 13:22:25 +01006898 pos = substr_atoi(loc);
Denys Vlasenko826360f2017-07-17 17:49:11 +02006899 if (colon) *colon = ':';
6900
6901 /* Read LEN in ${var:POS:LEN} */
6902 len = str - startp - 1;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006903 /* *loc != '\0', guaranteed by parser */
6904 if (quotes) {
6905 char *ptr;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006906 /* Adjust the length by the number of escapes */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006907 for (ptr = startp; ptr < (str - 1); ptr++) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006908 if ((unsigned char)*ptr == CTLESC) {
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006909 len--;
6910 ptr++;
6911 }
6912 }
6913 }
6914 orig_len = len;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006915 if (*loc++ == ':') {
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006916 /* ${var::LEN} */
Denys Vlasenkobaa41c72018-01-10 13:22:25 +01006917 len = substr_atoi(loc);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006918 } else {
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006919 /* Skip POS in ${var:POS:LEN} */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006920 len = orig_len;
Denys Vlasenkobaa41c72018-01-10 13:22:25 +01006921 while (*loc && *loc != ':')
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006922 loc++;
Denys Vlasenkobaa41c72018-01-10 13:22:25 +01006923 if (*loc++ == ':')
6924 len = substr_atoi(loc);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006925 }
Denys Vlasenko08a5dab2014-11-17 20:27:18 +01006926 if (pos < 0) {
6927 /* ${VAR:$((-n)):l} starts n chars from the end */
6928 pos = orig_len + pos;
6929 }
6930 if ((unsigned)pos >= orig_len) {
6931 /* apart from obvious ${VAR:999999:l},
6932 * covers ${VAR:$((-9999999)):l} - result is ""
Denys Vlasenko826360f2017-07-17 17:49:11 +02006933 * (bash compat)
Denys Vlasenko08a5dab2014-11-17 20:27:18 +01006934 */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006935 pos = 0;
6936 len = 0;
6937 }
Denys Vlasenko826360f2017-07-17 17:49:11 +02006938 if (len < 0) {
6939 /* ${VAR:N:-M} sets LEN to strlen()-M */
6940 len = (orig_len - pos) + len;
6941 }
6942 if ((unsigned)len > (orig_len - pos))
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006943 len = orig_len - pos;
6944
6945 for (str = startp; pos; str++, pos--) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006946 if (quotes && (unsigned char)*str == CTLESC)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006947 str++;
6948 }
6949 for (loc = startp; len; len--) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006950 if (quotes && (unsigned char)*str == CTLESC)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006951 *loc++ = *str++;
6952 *loc++ = *str++;
6953 }
6954 *loc = '\0';
6955 amount = loc - expdest;
6956 STADJUST(amount, expdest);
6957 return loc;
Denys Vlasenko826360f2017-07-17 17:49:11 +02006958 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006959#endif /* BASH_SUBSTR */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006960 }
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006961
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006962 resetloc = expdest - (char *)stackblock();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006963
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006964#if BASH_PATTERN_SUBST
Denys Vlasenko740058b2018-01-09 17:01:00 +01006965 repl = NULL;
6966
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006967 /* We'll comeback here if we grow the stack while handling
6968 * a VSREPLACE or VSREPLACEALL, since our pointers into the
6969 * stack will need rebasing, and we'll need to remove our work
6970 * areas each time
6971 */
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006972 restart:
6973#endif
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006974
6975 amount = expdest - ((char *)stackblock() + resetloc);
6976 STADJUST(-amount, expdest);
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006977 startp = (char *)stackblock() + startloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006978
6979 rmesc = startp;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006980 rmescend = (char *)stackblock() + strloc;
Denys Vlasenko740058b2018-01-09 17:01:00 +01006981 //bb_error_msg("str7:'%s'", rmescend);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006982 if (quotes) {
Denys Vlasenko740058b2018-01-09 17:01:00 +01006983//TODO: how to handle slash_pos here if string changes (shortens?)
6984 rmesc = rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW, NULL);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006985 if (rmesc != startp) {
6986 rmescend = expdest;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006987 startp = (char *)stackblock() + startloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006988 }
6989 }
6990 rmescend--;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006991 str = (char *)stackblock() + strloc;
Ron Yorston417622c2015-05-18 09:59:14 +02006992 /*
6993 * Example: v='a\bc'; echo ${v/\\b/_\\_\z_}
6994 * The result is a_\_z_c (not a\_\_z_c)!
6995 *
6996 * The search pattern and replace string treat backslashes differently!
Denys Vlasenko740058b2018-01-09 17:01:00 +01006997 * "&slash_pos" causes rmescapes() to work differently on the pattern
Ron Yorston417622c2015-05-18 09:59:14 +02006998 * and string. It's only used on the first call.
6999 */
Denys Vlasenko740058b2018-01-09 17:01:00 +01007000 //bb_error_msg("str8:'%s' slash_pos:%d", str, slash_pos);
7001 rmescapes(str, RMESCAPE_GLOB,
7002 repl ? NULL : (slash_pos < 0 ? NULL : &slash_pos)
7003 );
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007004
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01007005#if BASH_PATTERN_SUBST
Denys Vlasenko0b4980c2012-09-25 12:49:29 +02007006 workloc = expdest - (char *)stackblock();
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007007 if (subtype == VSREPLACE || subtype == VSREPLACEALL) {
Denys Vlasenko826360f2017-07-17 17:49:11 +02007008 int len;
Denys Vlasenkob76356b2010-03-13 16:19:04 +01007009 char *idx, *end;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007010
Denis Vlasenkod6855d12008-09-27 14:03:25 +00007011 if (!repl) {
Denys Vlasenko740058b2018-01-09 17:01:00 +01007012 //bb_error_msg("str9:'%s' slash_pos:%d", str, slash_pos);
Denys Vlasenkod1df1a72018-01-09 17:25:58 +01007013 repl = nullstr;
Denys Vlasenko740058b2018-01-09 17:01:00 +01007014 if (slash_pos >= 0) {
7015 repl = str + slash_pos;
Ron Yorston417622c2015-05-18 09:59:14 +02007016 *repl++ = '\0';
Denys Vlasenko740058b2018-01-09 17:01:00 +01007017 }
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007018 }
Ron Yorston417622c2015-05-18 09:59:14 +02007019 //bb_error_msg("str:'%s' repl:'%s'", str, repl);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007020
7021 /* If there's no pattern to match, return the expansion unmolested */
Denys Vlasenkob76356b2010-03-13 16:19:04 +01007022 if (str[0] == '\0')
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02007023 return NULL;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007024
7025 len = 0;
7026 idx = startp;
7027 end = str - 1;
7028 while (idx < end) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01007029 try_to_match:
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007030 loc = scanright(idx, rmesc, rmescend, str, quotes, 1);
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02007031 //bb_error_msg("scanright('%s'):'%s'", str, loc);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007032 if (!loc) {
7033 /* No match, advance */
Denys Vlasenkob76356b2010-03-13 16:19:04 +01007034 char *restart_detect = stackblock();
7035 skip_matching:
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007036 STPUTC(*idx, expdest);
Denys Vlasenkocd716832009-11-28 22:14:02 +01007037 if (quotes && (unsigned char)*idx == CTLESC) {
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007038 idx++;
7039 len++;
7040 STPUTC(*idx, expdest);
7041 }
7042 if (stackblock() != restart_detect)
7043 goto restart;
7044 idx++;
7045 len++;
7046 rmesc++;
Denys Vlasenkob76356b2010-03-13 16:19:04 +01007047 /* continue; - prone to quadratic behavior, smarter code: */
7048 if (idx >= end)
7049 break;
7050 if (str[0] == '*') {
7051 /* Pattern is "*foo". If "*foo" does not match "long_string",
7052 * it would never match "ong_string" etc, no point in trying.
7053 */
7054 goto skip_matching;
7055 }
7056 goto try_to_match;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007057 }
7058
7059 if (subtype == VSREPLACEALL) {
7060 while (idx < loc) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01007061 if (quotes && (unsigned char)*idx == CTLESC)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007062 idx++;
7063 idx++;
7064 rmesc++;
7065 }
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00007066 } else {
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007067 idx = loc;
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00007068 }
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007069
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02007070 //bb_error_msg("repl:'%s'", repl);
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007071 for (loc = (char*)repl; *loc; loc++) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01007072 char *restart_detect = stackblock();
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007073 if (quotes && *loc == '\\') {
7074 STPUTC(CTLESC, expdest);
7075 len++;
7076 }
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007077 STPUTC(*loc, expdest);
7078 if (stackblock() != restart_detect)
7079 goto restart;
7080 len++;
7081 }
7082
7083 if (subtype == VSREPLACE) {
Denys Vlasenkof02c82f2010-08-06 19:14:47 +02007084 //bb_error_msg("tail:'%s', quotes:%x", idx, quotes);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007085 while (*idx) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01007086 char *restart_detect = stackblock();
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007087 STPUTC(*idx, expdest);
7088 if (stackblock() != restart_detect)
7089 goto restart;
7090 len++;
7091 idx++;
7092 }
7093 break;
7094 }
7095 }
7096
7097 /* We've put the replaced text into a buffer at workloc, now
7098 * move it to the right place and adjust the stack.
7099 */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007100 STPUTC('\0', expdest);
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007101 startp = (char *)stackblock() + startloc;
7102 memmove(startp, (char *)stackblock() + workloc, len + 1);
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02007103 //bb_error_msg("startp:'%s'", startp);
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007104 amount = expdest - (startp + len);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007105 STADJUST(-amount, expdest);
7106 return startp;
7107 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01007108#endif /* BASH_PATTERN_SUBST */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007109
7110 subtype -= VSTRIMRIGHT;
7111#if DEBUG
7112 if (subtype < 0 || subtype > 7)
7113 abort();
7114#endif
Denys Vlasenkob76356b2010-03-13 16:19:04 +01007115 /* zero = (subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX) */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007116 zero = subtype >> 1;
7117 /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */
7118 scan = (subtype & 1) ^ zero ? scanleft : scanright;
7119
7120 loc = scan(startp, rmesc, rmescend, str, quotes, zero);
7121 if (loc) {
7122 if (zero) {
7123 memmove(startp, loc, str - loc);
7124 loc = startp + (str - loc) - 1;
7125 }
7126 *loc = '\0';
7127 amount = loc - expdest;
7128 STADJUST(amount, expdest);
7129 }
7130 return loc;
7131}
7132
7133/*
7134 * Add the value of a specialized variable to the stack string.
Denys Vlasenko4d8873f2009-10-04 03:14:41 +02007135 * name parameter (examples):
7136 * ash -c 'echo $1' name:'1='
7137 * ash -c 'echo $qwe' name:'qwe='
7138 * ash -c 'echo $$' name:'$='
7139 * ash -c 'echo ${$}' name:'$='
7140 * ash -c 'echo ${$##q}' name:'$=q'
7141 * ash -c 'echo ${#$}' name:'$='
7142 * note: examples with bad shell syntax:
7143 * ash -c 'echo ${#$1}' name:'$=1'
7144 * ash -c 'echo ${#1#}' name:'1=#'
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007145 */
Denys Vlasenkoadf922e2009-10-08 14:35:37 +02007146static NOINLINE ssize_t
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02007147varvalue(char *name, int varflags, int flags, int *quotedp)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007148{
Mike Frysinger98c52642009-04-02 10:02:37 +00007149 const char *p;
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01007150 int num;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007151 int i;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007152 ssize_t len = 0;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007153 int sep;
Denys Vlasenko0dd8e452016-10-01 21:02:06 +02007154 int quoted = *quotedp;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007155 int subtype = varflags & VSTYPE;
7156 int discard = subtype == VSPLUS || subtype == VSLENGTH;
7157 int quotes = (discard ? 0 : (flags & QUOTES_ESC)) | QUOTES_KEEPNUL;
Denys Vlasenko0aaaa502016-10-02 02:46:56 +02007158 int syntax;
7159
7160 sep = (flags & EXP_FULL) << CHAR_BIT;
7161 syntax = quoted ? DQSYNTAX : BASESYNTAX;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007162
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007163 switch (*name) {
7164 case '$':
7165 num = rootpid;
7166 goto numvar;
7167 case '?':
7168 num = exitstatus;
7169 goto numvar;
7170 case '#':
7171 num = shellparam.nparam;
7172 goto numvar;
7173 case '!':
7174 num = backgndpid;
7175 if (num == 0)
7176 return -1;
7177 numvar:
7178 len = cvtnum(num);
Denys Vlasenko4d8873f2009-10-04 03:14:41 +02007179 goto check_1char_name;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007180 case '-':
Mike Frysinger98c52642009-04-02 10:02:37 +00007181 expdest = makestrspace(NOPTS, expdest);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007182 for (i = NOPTS - 1; i >= 0; i--) {
7183 if (optlist[i]) {
Mike Frysinger98c52642009-04-02 10:02:37 +00007184 USTPUTC(optletters(i), expdest);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007185 len++;
7186 }
7187 }
Denys Vlasenko4d8873f2009-10-04 03:14:41 +02007188 check_1char_name:
7189#if 0
7190 /* handles cases similar to ${#$1} */
7191 if (name[2] != '\0')
7192 raise_error_syntax("bad substitution");
7193#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007194 break;
Denys Vlasenko0aaaa502016-10-02 02:46:56 +02007195 case '@':
7196 if (quoted && sep)
7197 goto param;
7198 /* fall through */
7199 case '*': {
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01007200 char **ap;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007201 char sepc;
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01007202
Denys Vlasenko0aaaa502016-10-02 02:46:56 +02007203 if (quoted)
7204 sep = 0;
7205 sep |= ifsset() ? ifsval()[0] : ' ';
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007206 param:
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007207 sepc = sep;
Denys Vlasenko0dd8e452016-10-01 21:02:06 +02007208 *quotedp = !sepc;
7209 ap = shellparam.p;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007210 if (!ap)
7211 return -1;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02007212 while ((p = *ap++) != NULL) {
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007213 len += strtodest(p, syntax, quotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007214
7215 if (*ap && sep) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007216 len++;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007217 memtodest(&sepc, 1, syntax, quotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007218 }
7219 }
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007220 break;
Denys Vlasenko0aaaa502016-10-02 02:46:56 +02007221 } /* case '*' */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007222 case '0':
7223 case '1':
7224 case '2':
7225 case '3':
7226 case '4':
7227 case '5':
7228 case '6':
7229 case '7':
7230 case '8':
7231 case '9':
Denys Vlasenkoa00329c2009-08-30 20:05:10 +02007232 num = atoi(name); /* number(name) fails on ${N#str} etc */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007233 if (num < 0 || num > shellparam.nparam)
7234 return -1;
7235 p = num ? shellparam.p[num - 1] : arg0;
7236 goto value;
7237 default:
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00007238 /* NB: name has form "VAR=..." */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007239 p = lookupvar(name);
7240 value:
7241 if (!p)
7242 return -1;
7243
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007244 len = strtodest(p, syntax, quotes);
Denys Vlasenkoc76236f2014-12-29 00:04:18 +01007245#if ENABLE_UNICODE_SUPPORT
7246 if (subtype == VSLENGTH && len > 0) {
7247 reinit_unicode_for_ash();
7248 if (unicode_status == UNICODE_ON) {
Ron Yorston3e3bfb82016-03-18 11:29:19 +00007249 STADJUST(-len, expdest);
7250 discard = 0;
Denys Vlasenkoc76236f2014-12-29 00:04:18 +01007251 len = unicode_strlen(p);
7252 }
7253 }
7254#endif
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007255 break;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007256 }
7257
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007258 if (discard)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007259 STADJUST(-len, expdest);
7260 return len;
7261}
7262
7263/*
7264 * Expand a variable, and return a pointer to the next character in the
7265 * input string.
7266 */
7267static char *
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02007268evalvar(char *p, int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007269{
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00007270 char varflags;
7271 char subtype;
Ron Yorston549deab2015-05-18 09:57:51 +02007272 int quoted;
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00007273 char easy;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007274 char *var;
7275 int patloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007276 int startloc;
7277 ssize_t varlen;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007278
Denys Vlasenkob0d63382009-09-16 16:18:32 +02007279 varflags = (unsigned char) *p++;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007280 subtype = varflags & VSTYPE;
Denys Vlasenko88e15702016-10-26 01:55:56 +02007281
7282 if (!subtype)
7283 raise_error_syntax("bad substitution");
7284
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007285 quoted = flag & EXP_QUOTED;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007286 var = p;
7287 easy = (!quoted || (*var == '@' && shellparam.nparam));
7288 startloc = expdest - (char *)stackblock();
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02007289 p = strchr(p, '=') + 1; //TODO: use var_end(p)?
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007290
7291 again:
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02007292 varlen = varvalue(var, varflags, flag, &quoted);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007293 if (varflags & VSNUL)
7294 varlen--;
7295
7296 if (subtype == VSPLUS) {
7297 varlen = -1 - varlen;
7298 goto vsplus;
7299 }
7300
7301 if (subtype == VSMINUS) {
7302 vsplus:
7303 if (varlen < 0) {
7304 argstr(
Denys Vlasenko6040fe82010-09-12 15:03:16 +02007305 p,
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02007306 flag | EXP_TILDE | EXP_WORD
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007307 );
7308 goto end;
7309 }
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007310 goto record;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007311 }
7312
7313 if (subtype == VSASSIGN || subtype == VSQUESTION) {
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007314 if (varlen >= 0)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007315 goto record;
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007316
7317 subevalvar(p, var, 0, subtype, startloc, varflags,
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02007318 flag & ~QUOTES_ESC);
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007319 varflags &= ~VSNUL;
7320 /*
7321 * Remove any recorded regions beyond
7322 * start of variable
7323 */
7324 removerecordregions(startloc);
7325 goto again;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007326 }
7327
7328 if (varlen < 0 && uflag)
7329 varunset(p, var, 0, 0);
7330
7331 if (subtype == VSLENGTH) {
Denys Vlasenkoc76236f2014-12-29 00:04:18 +01007332 cvtnum(varlen > 0 ? varlen : 0);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007333 goto record;
7334 }
7335
7336 if (subtype == VSNORMAL) {
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007337 record:
7338 if (!easy)
7339 goto end;
Denys Vlasenko0dd8e452016-10-01 21:02:06 +02007340 recordregion(startloc, expdest - (char *)stackblock(), quoted);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007341 goto end;
7342 }
7343
7344#if DEBUG
7345 switch (subtype) {
7346 case VSTRIMLEFT:
7347 case VSTRIMLEFTMAX:
7348 case VSTRIMRIGHT:
7349 case VSTRIMRIGHTMAX:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01007350#if BASH_SUBSTR
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007351 case VSSUBSTR:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01007352#endif
7353#if BASH_PATTERN_SUBST
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007354 case VSREPLACE:
7355 case VSREPLACEALL:
7356#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007357 break;
7358 default:
7359 abort();
7360 }
7361#endif
7362
7363 if (varlen >= 0) {
7364 /*
7365 * Terminate the string and start recording the pattern
7366 * right after it
7367 */
7368 STPUTC('\0', expdest);
7369 patloc = expdest - (char *)stackblock();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02007370 if (NULL == subevalvar(p, /* varname: */ NULL, patloc, subtype,
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02007371 startloc, varflags, flag)) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007372 int amount = expdest - (
7373 (char *)stackblock() + patloc - 1
7374 );
7375 STADJUST(-amount, expdest);
7376 }
7377 /* Remove any recorded regions beyond start of variable */
7378 removerecordregions(startloc);
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007379 goto record;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007380 }
7381
7382 end:
7383 if (subtype != VSNORMAL) { /* skip to end of alternative */
7384 int nesting = 1;
7385 for (;;) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01007386 unsigned char c = *p++;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007387 if (c == CTLESC)
7388 p++;
Ron Yorston549deab2015-05-18 09:57:51 +02007389 else if (c == CTLBACKQ) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007390 if (varlen >= 0)
7391 argbackq = argbackq->next;
7392 } else if (c == CTLVAR) {
7393 if ((*p++ & VSTYPE) != VSNORMAL)
7394 nesting++;
7395 } else if (c == CTLENDVAR) {
7396 if (--nesting == 0)
7397 break;
7398 }
7399 }
7400 }
7401 return p;
7402}
7403
7404/*
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007405 * Add a file name to the list.
7406 */
7407static void
7408addfname(const char *name)
7409{
7410 struct strlist *sp;
7411
Denis Vlasenko597906c2008-02-20 16:38:54 +00007412 sp = stzalloc(sizeof(*sp));
Denys Vlasenko8e2bc472016-09-28 23:02:57 +02007413 sp->text = sstrdup(name);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007414 *exparg.lastp = sp;
7415 exparg.lastp = &sp->next;
7416}
7417
Felix Fietkaub5b21122017-01-31 21:58:55 +01007418/* Avoid glob() (and thus, stat() et al) for words like "echo" */
7419static int
7420hasmeta(const char *p)
7421{
7422 static const char chars[] ALIGN1 = {
7423 '*', '?', '[', '\\', CTLQUOTEMARK, CTLESC, 0
7424 };
7425
7426 for (;;) {
7427 p = strpbrk(p, chars);
7428 if (!p)
7429 break;
7430 switch ((unsigned char) *p) {
7431 case CTLQUOTEMARK:
7432 for (;;) {
7433 p++;
7434 if (*p == CTLQUOTEMARK)
7435 break;
7436 if (*p == CTLESC)
7437 p++;
7438 if (*p == '\0') /* huh? */
7439 return 0;
7440 }
7441 break;
7442 case '\\':
7443 case CTLESC:
7444 p++;
7445 if (*p == '\0')
7446 return 0;
7447 break;
7448 case '[':
7449 if (!strchr(p + 1, ']')) {
7450 /* It's not a properly closed [] pattern,
7451 * but other metas may follow. Continue checking.
7452 * my[file* _is_ globbed by bash
7453 * and matches filenames like "my[file1".
7454 */
7455 break;
7456 }
7457 /* fallthrough */
7458 default:
7459 /* case '*': */
7460 /* case '?': */
7461 return 1;
7462 }
7463 p++;
7464 }
7465
7466 return 0;
7467}
7468
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007469/* If we want to use glob() from libc... */
Denys Vlasenko514b51d2016-10-01 14:33:08 +02007470#if !ENABLE_ASH_INTERNAL_GLOB
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007471
7472/* Add the result of glob() to the list */
7473static void
7474addglob(const glob_t *pglob)
7475{
7476 char **p = pglob->gl_pathv;
7477
7478 do {
7479 addfname(*p);
7480 } while (*++p);
7481}
7482static void
7483expandmeta(struct strlist *str /*, int flag*/)
7484{
7485 /* TODO - EXP_REDIR */
7486
7487 while (str) {
7488 char *p;
7489 glob_t pglob;
7490 int i;
7491
7492 if (fflag)
7493 goto nometa;
Denys Vlasenkod4f3db92016-10-30 18:41:01 +01007494
Felix Fietkaub5b21122017-01-31 21:58:55 +01007495 if (!hasmeta(str->text))
7496 goto nometa;
Denys Vlasenkod4f3db92016-10-30 18:41:01 +01007497
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007498 INT_OFF;
7499 p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP);
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007500// GLOB_NOMAGIC (GNU): if no *?[ chars in pattern, return it even if no match
7501// GLOB_NOCHECK: if no match, return unchanged pattern (sans \* escapes?)
7502//
7503// glibc 2.24.90 glob(GLOB_NOMAGIC) does not remove backslashes used for escaping:
7504// if you pass it "file\?", it returns "file\?", not "file?", if no match.
7505// Which means you need to unescape the string, right? Not so fast:
7506// if there _is_ a file named "file\?" (with backslash), it is returned
7507// as "file\?" too (whichever pattern you used to find it, say, "file*").
Denys Vlasenko10ad6222017-04-17 16:13:32 +02007508// You DON'T KNOW by looking at the result whether you need to unescape it.
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007509//
7510// Worse, globbing of "file\?" in a directory with two files, "file?" and "file\?",
7511// returns "file\?" - which is WRONG: "file\?" pattern matches "file?" file.
7512// Without GLOB_NOMAGIC, this works correctly ("file?" is returned as a match).
7513// With GLOB_NOMAGIC | GLOB_NOCHECK, this also works correctly.
7514// i = glob(p, GLOB_NOMAGIC | GLOB_NOCHECK, NULL, &pglob);
7515// i = glob(p, GLOB_NOMAGIC, NULL, &pglob);
7516 i = glob(p, 0, NULL, &pglob);
7517 //bb_error_msg("glob('%s'):%d '%s'...", p, i, pglob.gl_pathv ? pglob.gl_pathv[0] : "-");
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007518 if (p != str->text)
7519 free(p);
7520 switch (i) {
7521 case 0:
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007522#if 0 // glibc 2.24.90 bug? Patterns like "*/file", when match, don't set GLOB_MAGCHAR
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007523 /* GLOB_MAGCHAR is set if *?[ chars were seen (GNU) */
7524 if (!(pglob.gl_flags & GLOB_MAGCHAR))
7525 goto nometa2;
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007526#endif
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007527 addglob(&pglob);
7528 globfree(&pglob);
7529 INT_ON;
7530 break;
7531 case GLOB_NOMATCH:
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007532 //nometa2:
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007533 globfree(&pglob);
7534 INT_ON;
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007535 nometa:
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007536 *exparg.lastp = str;
Denys Vlasenko740058b2018-01-09 17:01:00 +01007537 rmescapes(str->text, 0, NULL);
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007538 exparg.lastp = &str->next;
7539 break;
7540 default: /* GLOB_NOSPACE */
7541 globfree(&pglob);
7542 INT_ON;
7543 ash_msg_and_raise_error(bb_msg_memory_exhausted);
7544 }
7545 str = str->next;
7546 }
7547}
7548
7549#else
Denys Vlasenko514b51d2016-10-01 14:33:08 +02007550/* ENABLE_ASH_INTERNAL_GLOB: Homegrown globbing code. (dash also has both, uses homegrown one.) */
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007551
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007552/*
7553 * Do metacharacter (i.e. *, ?, [...]) expansion.
7554 */
7555static void
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007556expmeta(char *expdir, char *enddir, char *name)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007557{
7558 char *p;
7559 const char *cp;
7560 char *start;
7561 char *endname;
7562 int metaflag;
7563 struct stat statb;
7564 DIR *dirp;
7565 struct dirent *dp;
7566 int atend;
7567 int matchdot;
Ron Yorstonca25af92015-09-04 10:32:41 +01007568 int esc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007569
7570 metaflag = 0;
7571 start = name;
Ron Yorstonca25af92015-09-04 10:32:41 +01007572 for (p = name; esc = 0, *p; p += esc + 1) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007573 if (*p == '*' || *p == '?')
7574 metaflag = 1;
7575 else if (*p == '[') {
7576 char *q = p + 1;
7577 if (*q == '!')
7578 q++;
7579 for (;;) {
7580 if (*q == '\\')
7581 q++;
7582 if (*q == '/' || *q == '\0')
7583 break;
7584 if (*++q == ']') {
7585 metaflag = 1;
7586 break;
7587 }
7588 }
Ron Yorstonca25af92015-09-04 10:32:41 +01007589 } else {
7590 if (*p == '\\')
7591 esc++;
7592 if (p[esc] == '/') {
7593 if (metaflag)
7594 break;
7595 start = p + esc + 1;
7596 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007597 }
7598 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007599 if (metaflag == 0) { /* we've reached the end of the file name */
7600 if (enddir != expdir)
7601 metaflag++;
7602 p = name;
7603 do {
7604 if (*p == '\\')
7605 p++;
7606 *enddir++ = *p;
7607 } while (*p++);
7608 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
7609 addfname(expdir);
7610 return;
7611 }
7612 endname = p;
7613 if (name < start) {
7614 p = name;
7615 do {
7616 if (*p == '\\')
7617 p++;
7618 *enddir++ = *p++;
7619 } while (p < start);
7620 }
7621 if (enddir == expdir) {
7622 cp = ".";
7623 } else if (enddir == expdir + 1 && *expdir == '/') {
7624 cp = "/";
7625 } else {
7626 cp = expdir;
7627 enddir[-1] = '\0';
7628 }
7629 dirp = opendir(cp);
7630 if (dirp == NULL)
7631 return;
7632 if (enddir != expdir)
7633 enddir[-1] = '/';
7634 if (*endname == 0) {
7635 atend = 1;
7636 } else {
7637 atend = 0;
Ron Yorstonca25af92015-09-04 10:32:41 +01007638 *endname = '\0';
7639 endname += esc + 1;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007640 }
7641 matchdot = 0;
7642 p = start;
7643 if (*p == '\\')
7644 p++;
7645 if (*p == '.')
7646 matchdot++;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02007647 while (!pending_int && (dp = readdir(dirp)) != NULL) {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00007648 if (dp->d_name[0] == '.' && !matchdot)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007649 continue;
7650 if (pmatch(start, dp->d_name)) {
7651 if (atend) {
7652 strcpy(enddir, dp->d_name);
7653 addfname(expdir);
7654 } else {
7655 for (p = enddir, cp = dp->d_name; (*p++ = *cp++) != '\0';)
7656 continue;
7657 p[-1] = '/';
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007658 expmeta(expdir, p, endname);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007659 }
7660 }
7661 }
7662 closedir(dirp);
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00007663 if (!atend)
Ron Yorstonca25af92015-09-04 10:32:41 +01007664 endname[-esc - 1] = esc ? '\\' : '/';
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007665}
7666
7667static struct strlist *
7668msort(struct strlist *list, int len)
7669{
7670 struct strlist *p, *q = NULL;
7671 struct strlist **lpp;
7672 int half;
7673 int n;
7674
7675 if (len <= 1)
7676 return list;
7677 half = len >> 1;
7678 p = list;
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +00007679 for (n = half; --n >= 0;) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007680 q = p;
7681 p = p->next;
7682 }
7683 q->next = NULL; /* terminate first half of list */
7684 q = msort(list, half); /* sort first half of list */
7685 p = msort(p, len - half); /* sort second half */
7686 lpp = &list;
7687 for (;;) {
7688#if ENABLE_LOCALE_SUPPORT
7689 if (strcoll(p->text, q->text) < 0)
7690#else
7691 if (strcmp(p->text, q->text) < 0)
7692#endif
7693 {
7694 *lpp = p;
7695 lpp = &p->next;
7696 p = *lpp;
7697 if (p == NULL) {
7698 *lpp = q;
7699 break;
7700 }
7701 } else {
7702 *lpp = q;
7703 lpp = &q->next;
7704 q = *lpp;
7705 if (q == NULL) {
7706 *lpp = p;
7707 break;
7708 }
7709 }
7710 }
7711 return list;
7712}
7713
7714/*
7715 * Sort the results of file name expansion. It calculates the number of
7716 * strings to sort and then calls msort (short for merge sort) to do the
7717 * work.
7718 */
7719static struct strlist *
7720expsort(struct strlist *str)
7721{
7722 int len;
7723 struct strlist *sp;
7724
7725 len = 0;
7726 for (sp = str; sp; sp = sp->next)
7727 len++;
7728 return msort(str, len);
7729}
7730
7731static void
Denis Vlasenko68404f12008-03-17 09:00:54 +00007732expandmeta(struct strlist *str /*, int flag*/)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007733{
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007734 /* TODO - EXP_REDIR */
7735
7736 while (str) {
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007737 char *expdir;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007738 struct strlist **savelastp;
7739 struct strlist *sp;
7740 char *p;
7741
7742 if (fflag)
7743 goto nometa;
Felix Fietkaub5b21122017-01-31 21:58:55 +01007744 if (!hasmeta(str->text))
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007745 goto nometa;
7746 savelastp = exparg.lastp;
7747
7748 INT_OFF;
Ron Yorston549deab2015-05-18 09:57:51 +02007749 p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007750 {
7751 int i = strlen(str->text);
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007752//BUGGY estimation of how long expanded name can be
7753 expdir = ckmalloc(i < 2048 ? 2048 : i+1);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007754 }
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007755 expmeta(expdir, expdir, p);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007756 free(expdir);
7757 if (p != str->text)
7758 free(p);
7759 INT_ON;
7760 if (exparg.lastp == savelastp) {
7761 /*
7762 * no matches
7763 */
7764 nometa:
7765 *exparg.lastp = str;
Denys Vlasenko740058b2018-01-09 17:01:00 +01007766 rmescapes(str->text, 0, NULL);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007767 exparg.lastp = &str->next;
7768 } else {
7769 *exparg.lastp = NULL;
7770 *savelastp = sp = expsort(*savelastp);
7771 while (sp->next != NULL)
7772 sp = sp->next;
7773 exparg.lastp = &sp->next;
7774 }
7775 str = str->next;
7776 }
7777}
Denys Vlasenko514b51d2016-10-01 14:33:08 +02007778#endif /* ENABLE_ASH_INTERNAL_GLOB */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007779
7780/*
7781 * Perform variable substitution and command substitution on an argument,
7782 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
7783 * perform splitting and file name expansion. When arglist is NULL, perform
7784 * here document expansion.
7785 */
7786static void
7787expandarg(union node *arg, struct arglist *arglist, int flag)
7788{
7789 struct strlist *sp;
7790 char *p;
7791
7792 argbackq = arg->narg.backquote;
7793 STARTSTACKSTR(expdest);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02007794 TRACE(("expandarg: argstr('%s',flags:%x)\n", arg->narg.text, flag));
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02007795 argstr(arg->narg.text, flag);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007796 p = _STPUTC('\0', expdest);
7797 expdest = p - 1;
7798 if (arglist == NULL) {
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02007799 /* here document expanded */
7800 goto out;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007801 }
7802 p = grabstackstr(p);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02007803 TRACE(("expandarg: p:'%s'\n", p));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007804 exparg.lastp = &exparg.list;
7805 /*
7806 * TODO - EXP_REDIR
7807 */
7808 if (flag & EXP_FULL) {
7809 ifsbreakup(p, &exparg);
7810 *exparg.lastp = NULL;
7811 exparg.lastp = &exparg.list;
Denis Vlasenko68404f12008-03-17 09:00:54 +00007812 expandmeta(exparg.list /*, flag*/);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007813 } else {
Denis Vlasenko597906c2008-02-20 16:38:54 +00007814 sp = stzalloc(sizeof(*sp));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007815 sp->text = p;
7816 *exparg.lastp = sp;
7817 exparg.lastp = &sp->next;
7818 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007819 *exparg.lastp = NULL;
7820 if (exparg.list) {
7821 *arglist->lastp = exparg.list;
7822 arglist->lastp = exparg.lastp;
7823 }
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02007824
7825 out:
7826 ifsfree();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007827}
7828
7829/*
7830 * Expand shell variables and backquotes inside a here document.
7831 */
7832static void
7833expandhere(union node *arg, int fd)
7834{
Ron Yorston549deab2015-05-18 09:57:51 +02007835 expandarg(arg, (struct arglist *)NULL, EXP_QUOTED);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007836 full_write(fd, stackblock(), expdest - (char *)stackblock());
7837}
7838
7839/*
7840 * Returns true if the pattern matches the string.
7841 */
7842static int
7843patmatch(char *pattern, const char *string)
7844{
Denys Vlasenkobd43c672017-07-05 23:12:15 +02007845 char *p = preglob(pattern, 0);
Denys Vlasenko4476c702017-08-15 15:27:41 +02007846 int r = pmatch(p, string);
7847 //bb_error_msg("!fnmatch(pattern:'%s',str:'%s',0):%d", p, string, r);
7848 return r;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007849}
7850
7851/*
7852 * See if a pattern matches in a case statement.
7853 */
7854static int
7855casematch(union node *pattern, char *val)
7856{
7857 struct stackmark smark;
7858 int result;
7859
7860 setstackmark(&smark);
7861 argbackq = pattern->narg.backquote;
7862 STARTSTACKSTR(expdest);
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02007863 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007864 STACKSTRNUL(expdest);
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02007865 ifsfree();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007866 result = patmatch(stackblock(), val);
7867 popstackmark(&smark);
7868 return result;
7869}
7870
7871
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007872/* ============ find_command */
7873
7874struct builtincmd {
7875 const char *name;
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02007876 int (*builtin)(int, char **) FAST_FUNC;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007877 /* unsigned flags; */
7878};
7879#define IS_BUILTIN_SPECIAL(b) ((b)->name[0] & 1)
Denis Vlasenkoe26b2782008-02-12 07:40:29 +00007880/* "regular" builtins always take precedence over commands,
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007881 * regardless of PATH=....%builtin... position */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007882#define IS_BUILTIN_REGULAR(b) ((b)->name[0] & 2)
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007883#define IS_BUILTIN_ASSIGN(b) ((b)->name[0] & 4)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007884
7885struct cmdentry {
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00007886 smallint cmdtype; /* CMDxxx */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007887 union param {
7888 int index;
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00007889 /* index >= 0 for commands without path (slashes) */
7890 /* (TODO: what exactly does the value mean? PATH position?) */
7891 /* index == -1 for commands with slashes */
7892 /* index == (-2 - applet_no) for NOFORK applets */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007893 const struct builtincmd *cmd;
7894 struct funcnode *func;
7895 } u;
7896};
7897/* values of cmdtype */
7898#define CMDUNKNOWN -1 /* no entry in table for command */
7899#define CMDNORMAL 0 /* command is an executable program */
7900#define CMDFUNCTION 1 /* command is a shell function */
7901#define CMDBUILTIN 2 /* command is a shell builtin */
7902
7903/* action to find_command() */
7904#define DO_ERR 0x01 /* prints errors */
7905#define DO_ABS 0x02 /* checks absolute paths */
7906#define DO_NOFUNC 0x04 /* don't return shell functions, for command */
7907#define DO_ALTPATH 0x08 /* using alternate path */
7908#define DO_ALTBLTIN 0x20 /* %builtin in alt. path */
7909
7910static void find_command(char *, struct cmdentry *, int, const char *);
7911
7912
7913/* ============ Hashing commands */
7914
7915/*
7916 * When commands are first encountered, they are entered in a hash table.
7917 * This ensures that a full path search will not have to be done for them
7918 * on each invocation.
7919 *
7920 * We should investigate converting to a linear search, even though that
7921 * would make the command name "hash" a misnomer.
7922 */
7923
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007924struct tblentry {
7925 struct tblentry *next; /* next entry in hash chain */
7926 union param param; /* definition of builtin function */
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00007927 smallint cmdtype; /* CMDxxx */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007928 char rehash; /* if set, cd done since entry created */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00007929 char cmdname[1]; /* name of command */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007930};
7931
Denis Vlasenko01631112007-12-16 17:20:38 +00007932static struct tblentry **cmdtable;
7933#define INIT_G_cmdtable() do { \
7934 cmdtable = xzalloc(CMDTABLESIZE * sizeof(cmdtable[0])); \
7935} while (0)
7936
7937static int builtinloc = -1; /* index in path of %builtin, or -1 */
7938
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007939
7940static void
Denys Vlasenko00a1dbd2017-07-29 01:20:53 +02007941tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) const char *cmd, char **argv, char **envp)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007942{
Denis Vlasenko80d14be2007-04-10 23:03:30 +00007943#if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007944 if (applet_no >= 0) {
Denis Vlasenkob7304742008-10-20 08:15:51 +00007945 if (APPLET_IS_NOEXEC(applet_no)) {
Denys Vlasenko7df28bb2010-06-18 14:23:47 +02007946 clearenv();
Denis Vlasenkob7304742008-10-20 08:15:51 +00007947 while (*envp)
7948 putenv(*envp++);
Denys Vlasenko035486c2017-07-31 04:09:19 +02007949 popredir(/*drop:*/ 1);
Denys Vlasenko80e8e3c2017-08-07 19:24:57 +02007950 run_noexec_applet_and_exit(applet_no, cmd, argv);
Denis Vlasenkob7304742008-10-20 08:15:51 +00007951 }
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007952 /* re-exec ourselves with the new arguments */
7953 execve(bb_busybox_exec_path, argv, envp);
7954 /* If they called chroot or otherwise made the binary no longer
7955 * executable, fall through */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007956 }
7957#endif
7958
7959 repeat:
7960#ifdef SYSV
7961 do {
7962 execve(cmd, argv, envp);
7963 } while (errno == EINTR);
7964#else
7965 execve(cmd, argv, envp);
7966#endif
Denys Vlasenko00a1dbd2017-07-29 01:20:53 +02007967 if (cmd != bb_busybox_exec_path && errno == ENOEXEC) {
Denys Vlasenkoaefe1c22011-03-07 12:02:40 +01007968 /* Run "cmd" as a shell script:
7969 * http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html
7970 * "If the execve() function fails with ENOEXEC, the shell
7971 * shall execute a command equivalent to having a shell invoked
7972 * with the command name as its first operand,
7973 * with any remaining arguments passed to the new shell"
7974 *
7975 * That is, do not use $SHELL, user's shell, or /bin/sh;
7976 * just call ourselves.
Denys Vlasenko2bef5262011-12-16 00:25:17 +01007977 *
7978 * Note that bash reads ~80 chars of the file, and if it sees
7979 * a zero byte before it sees newline, it doesn't try to
7980 * interpret it, but fails with "cannot execute binary file"
Denys Vlasenkocda6ea92011-12-16 00:44:36 +01007981 * message and exit code 126. For one, this prevents attempts
7982 * to interpret foreign ELF binaries as shell scripts.
Denys Vlasenkoaefe1c22011-03-07 12:02:40 +01007983 */
Denys Vlasenko00a1dbd2017-07-29 01:20:53 +02007984 argv[0] = (char*) cmd;
7985 cmd = bb_busybox_exec_path;
Denys Vlasenko65a8b852016-10-26 22:29:11 +02007986 /* NB: this is only possible because all callers of shellexec()
7987 * ensure that the argv[-1] slot exists!
7988 */
7989 argv--;
7990 argv[0] = (char*) "ash";
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007991 goto repeat;
7992 }
7993}
7994
7995/*
7996 * Exec a program. Never returns. If you change this routine, you may
7997 * have to change the find_command routine as well.
Denys Vlasenko65a8b852016-10-26 22:29:11 +02007998 * argv[-1] must exist and be writable! See tryexec() for why.
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007999 */
Denys Vlasenkoe139ae32017-04-12 21:02:33 +02008000static void shellexec(char *prog, char **argv, const char *path, int idx) NORETURN;
8001static void shellexec(char *prog, char **argv, const char *path, int idx)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008002{
8003 char *cmdname;
8004 int e;
8005 char **envp;
8006 int exerrno;
Denys Vlasenko83f103b2011-12-20 06:10:35 +01008007 int applet_no = -1; /* used only by FEATURE_SH_STANDALONE */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008008
Denys Vlasenkoa5060b82017-11-03 14:16:25 +01008009 envp = listvars(VEXPORT, VUNSET, /*strlist:*/ NULL, /*end:*/ NULL);
Denys Vlasenkoe139ae32017-04-12 21:02:33 +02008010 if (strchr(prog, '/') != NULL
Denis Vlasenko80d14be2007-04-10 23:03:30 +00008011#if ENABLE_FEATURE_SH_STANDALONE
Denys Vlasenkoe139ae32017-04-12 21:02:33 +02008012 || (applet_no = find_applet_by_name(prog)) >= 0
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008013#endif
8014 ) {
Denys Vlasenkoe139ae32017-04-12 21:02:33 +02008015 tryexec(IF_FEATURE_SH_STANDALONE(applet_no,) prog, argv, envp);
Denys Vlasenko83f103b2011-12-20 06:10:35 +01008016 if (applet_no >= 0) {
8017 /* We tried execing ourself, but it didn't work.
8018 * Maybe /proc/self/exe doesn't exist?
8019 * Try $PATH search.
8020 */
8021 goto try_PATH;
8022 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008023 e = errno;
8024 } else {
Denys Vlasenko83f103b2011-12-20 06:10:35 +01008025 try_PATH:
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008026 e = ENOENT;
Denys Vlasenkoe139ae32017-04-12 21:02:33 +02008027 while ((cmdname = path_advance(&path, prog)) != NULL) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008028 if (--idx < 0 && pathopt == NULL) {
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00008029 tryexec(IF_FEATURE_SH_STANDALONE(-1,) cmdname, argv, envp);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008030 if (errno != ENOENT && errno != ENOTDIR)
8031 e = errno;
8032 }
8033 stunalloc(cmdname);
8034 }
8035 }
8036
8037 /* Map to POSIX errors */
8038 switch (e) {
8039 case EACCES:
8040 exerrno = 126;
8041 break;
8042 case ENOENT:
8043 exerrno = 127;
8044 break;
8045 default:
8046 exerrno = 2;
8047 break;
8048 }
8049 exitstatus = exerrno;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02008050 TRACE(("shellexec failed for %s, errno %d, suppress_int %d\n",
Denys Vlasenkoe139ae32017-04-12 21:02:33 +02008051 prog, e, suppress_int));
8052 ash_msg_and_raise(EXEXIT, "%s: %s", prog, errmsg(e, "not found"));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008053 /* NOTREACHED */
8054}
8055
8056static void
8057printentry(struct tblentry *cmdp)
8058{
8059 int idx;
8060 const char *path;
8061 char *name;
8062
8063 idx = cmdp->param.index;
8064 path = pathval();
8065 do {
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02008066 name = path_advance(&path, cmdp->cmdname);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008067 stunalloc(name);
8068 } while (--idx >= 0);
8069 out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr));
8070}
8071
8072/*
8073 * Clear out command entries. The argument specifies the first entry in
8074 * PATH which has changed.
8075 */
8076static void
8077clearcmdentry(int firstchange)
8078{
8079 struct tblentry **tblp;
8080 struct tblentry **pp;
8081 struct tblentry *cmdp;
8082
8083 INT_OFF;
8084 for (tblp = cmdtable; tblp < &cmdtable[CMDTABLESIZE]; tblp++) {
8085 pp = tblp;
8086 while ((cmdp = *pp) != NULL) {
8087 if ((cmdp->cmdtype == CMDNORMAL &&
8088 cmdp->param.index >= firstchange)
8089 || (cmdp->cmdtype == CMDBUILTIN &&
8090 builtinloc >= firstchange)
8091 ) {
8092 *pp = cmdp->next;
8093 free(cmdp);
8094 } else {
8095 pp = &cmdp->next;
8096 }
8097 }
8098 }
8099 INT_ON;
8100}
8101
8102/*
8103 * Locate a command in the command hash table. If "add" is nonzero,
8104 * add the command to the table if it is not already present. The
8105 * variable "lastcmdentry" is set to point to the address of the link
8106 * pointing to the entry, so that delete_cmd_entry can delete the
8107 * entry.
8108 *
8109 * Interrupts must be off if called with add != 0.
8110 */
8111static struct tblentry **lastcmdentry;
8112
8113static struct tblentry *
8114cmdlookup(const char *name, int add)
8115{
8116 unsigned int hashval;
8117 const char *p;
8118 struct tblentry *cmdp;
8119 struct tblentry **pp;
8120
8121 p = name;
8122 hashval = (unsigned char)*p << 4;
8123 while (*p)
8124 hashval += (unsigned char)*p++;
8125 hashval &= 0x7FFF;
8126 pp = &cmdtable[hashval % CMDTABLESIZE];
8127 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
8128 if (strcmp(cmdp->cmdname, name) == 0)
8129 break;
8130 pp = &cmdp->next;
8131 }
8132 if (add && cmdp == NULL) {
Denis Vlasenkob07a4962008-06-22 13:16:23 +00008133 cmdp = *pp = ckzalloc(sizeof(struct tblentry)
8134 + strlen(name)
8135 /* + 1 - already done because
8136 * tblentry::cmdname is char[1] */);
Denis Vlasenko597906c2008-02-20 16:38:54 +00008137 /*cmdp->next = NULL; - ckzalloc did it */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008138 cmdp->cmdtype = CMDUNKNOWN;
8139 strcpy(cmdp->cmdname, name);
8140 }
8141 lastcmdentry = pp;
8142 return cmdp;
8143}
8144
8145/*
8146 * Delete the command entry returned on the last lookup.
8147 */
8148static void
8149delete_cmd_entry(void)
8150{
8151 struct tblentry *cmdp;
8152
8153 INT_OFF;
8154 cmdp = *lastcmdentry;
8155 *lastcmdentry = cmdp->next;
8156 if (cmdp->cmdtype == CMDFUNCTION)
8157 freefunc(cmdp->param.func);
8158 free(cmdp);
8159 INT_ON;
8160}
8161
8162/*
8163 * Add a new command entry, replacing any existing command entry for
8164 * the same name - except special builtins.
8165 */
8166static void
8167addcmdentry(char *name, struct cmdentry *entry)
8168{
8169 struct tblentry *cmdp;
8170
8171 cmdp = cmdlookup(name, 1);
8172 if (cmdp->cmdtype == CMDFUNCTION) {
8173 freefunc(cmdp->param.func);
8174 }
8175 cmdp->cmdtype = entry->cmdtype;
8176 cmdp->param = entry->u;
8177 cmdp->rehash = 0;
8178}
8179
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02008180static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00008181hashcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008182{
8183 struct tblentry **pp;
8184 struct tblentry *cmdp;
8185 int c;
8186 struct cmdentry entry;
8187 char *name;
8188
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008189 if (nextopt("r") != '\0') {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008190 clearcmdentry(0);
8191 return 0;
8192 }
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008193
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008194 if (*argptr == NULL) {
8195 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
8196 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
8197 if (cmdp->cmdtype == CMDNORMAL)
8198 printentry(cmdp);
8199 }
8200 }
8201 return 0;
8202 }
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008203
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008204 c = 0;
8205 while ((name = *argptr) != NULL) {
8206 cmdp = cmdlookup(name, 0);
8207 if (cmdp != NULL
8208 && (cmdp->cmdtype == CMDNORMAL
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008209 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))
8210 ) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008211 delete_cmd_entry();
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008212 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008213 find_command(name, &entry, DO_ERR, pathval());
8214 if (entry.cmdtype == CMDUNKNOWN)
8215 c = 1;
8216 argptr++;
8217 }
8218 return c;
8219}
8220
8221/*
8222 * Called when a cd is done. Marks all commands so the next time they
8223 * are executed they will be rehashed.
8224 */
8225static void
8226hashcd(void)
8227{
8228 struct tblentry **pp;
8229 struct tblentry *cmdp;
8230
8231 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
8232 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008233 if (cmdp->cmdtype == CMDNORMAL
8234 || (cmdp->cmdtype == CMDBUILTIN
Denys Vlasenkoe4dcba12010-10-28 18:57:19 +02008235 && !IS_BUILTIN_REGULAR(cmdp->param.cmd)
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008236 && builtinloc > 0)
8237 ) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008238 cmdp->rehash = 1;
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008239 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008240 }
8241 }
8242}
8243
8244/*
8245 * Fix command hash table when PATH changed.
8246 * Called before PATH is changed. The argument is the new value of PATH;
8247 * pathval() still returns the old value at this point.
8248 * Called with interrupts off.
8249 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02008250static void FAST_FUNC
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008251changepath(const char *new)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008252{
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008253 const char *old;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008254 int firstchange;
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008255 int idx;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008256 int idx_bltin;
8257
8258 old = pathval();
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008259 firstchange = 9999; /* assume no change */
8260 idx = 0;
8261 idx_bltin = -1;
8262 for (;;) {
8263 if (*old != *new) {
8264 firstchange = idx;
8265 if ((*old == '\0' && *new == ':')
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +02008266 || (*old == ':' && *new == '\0')
8267 ) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008268 firstchange++;
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +02008269 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008270 old = new; /* ignore subsequent differences */
8271 }
8272 if (*new == '\0')
8273 break;
8274 if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin"))
8275 idx_bltin = idx;
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008276 if (*new == ':')
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008277 idx++;
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +02008278 new++;
8279 old++;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008280 }
8281 if (builtinloc < 0 && idx_bltin >= 0)
8282 builtinloc = idx_bltin; /* zap builtins */
8283 if (builtinloc >= 0 && idx_bltin < 0)
8284 firstchange = 0;
8285 clearcmdentry(firstchange);
8286 builtinloc = idx_bltin;
8287}
Ron Yorston95ebcf72015-11-03 09:42:23 +00008288enum {
8289 TEOF,
8290 TNL,
8291 TREDIR,
8292 TWORD,
8293 TSEMI,
8294 TBACKGND,
8295 TAND,
8296 TOR,
8297 TPIPE,
8298 TLP,
8299 TRP,
8300 TENDCASE,
8301 TENDBQUOTE,
8302 TNOT,
8303 TCASE,
8304 TDO,
8305 TDONE,
8306 TELIF,
8307 TELSE,
8308 TESAC,
8309 TFI,
8310 TFOR,
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01008311#if BASH_FUNCTION
Ron Yorston95ebcf72015-11-03 09:42:23 +00008312 TFUNCTION,
8313#endif
8314 TIF,
8315 TIN,
8316 TTHEN,
8317 TUNTIL,
8318 TWHILE,
8319 TBEGIN,
8320 TEND
8321};
Denis Vlasenkob07a4962008-06-22 13:16:23 +00008322typedef smallint token_id_t;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008323
Denys Vlasenko888527c2016-10-02 16:54:17 +02008324/* Nth bit indicates if token marks the end of a list */
8325enum {
8326 tokendlist = 0
8327 /* 0 */ | (1u << TEOF)
8328 /* 1 */ | (0u << TNL)
8329 /* 2 */ | (0u << TREDIR)
8330 /* 3 */ | (0u << TWORD)
8331 /* 4 */ | (0u << TSEMI)
8332 /* 5 */ | (0u << TBACKGND)
8333 /* 6 */ | (0u << TAND)
8334 /* 7 */ | (0u << TOR)
8335 /* 8 */ | (0u << TPIPE)
8336 /* 9 */ | (0u << TLP)
8337 /* 10 */ | (1u << TRP)
8338 /* 11 */ | (1u << TENDCASE)
8339 /* 12 */ | (1u << TENDBQUOTE)
8340 /* 13 */ | (0u << TNOT)
8341 /* 14 */ | (0u << TCASE)
8342 /* 15 */ | (1u << TDO)
8343 /* 16 */ | (1u << TDONE)
8344 /* 17 */ | (1u << TELIF)
8345 /* 18 */ | (1u << TELSE)
8346 /* 19 */ | (1u << TESAC)
8347 /* 20 */ | (1u << TFI)
8348 /* 21 */ | (0u << TFOR)
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01008349#if BASH_FUNCTION
Denys Vlasenko888527c2016-10-02 16:54:17 +02008350 /* 22 */ | (0u << TFUNCTION)
Denys Vlasenko80729a42016-10-02 22:33:15 +02008351#endif
Denys Vlasenko888527c2016-10-02 16:54:17 +02008352 /* 23 */ | (0u << TIF)
8353 /* 24 */ | (0u << TIN)
8354 /* 25 */ | (1u << TTHEN)
8355 /* 26 */ | (0u << TUNTIL)
8356 /* 27 */ | (0u << TWHILE)
8357 /* 28 */ | (0u << TBEGIN)
8358 /* 29 */ | (1u << TEND)
8359 , /* thus far 29 bits used */
8360};
8361
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008362static const char *const tokname_array[] = {
Denys Vlasenko888527c2016-10-02 16:54:17 +02008363 "end of file",
8364 "newline",
8365 "redirection",
8366 "word",
8367 ";",
8368 "&",
8369 "&&",
8370 "||",
8371 "|",
8372 "(",
8373 ")",
8374 ";;",
8375 "`",
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008376#define KWDOFFSET 13
8377 /* the following are keywords */
Denys Vlasenko888527c2016-10-02 16:54:17 +02008378 "!",
8379 "case",
8380 "do",
8381 "done",
8382 "elif",
8383 "else",
8384 "esac",
8385 "fi",
8386 "for",
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01008387#if BASH_FUNCTION
Denys Vlasenko888527c2016-10-02 16:54:17 +02008388 "function",
Ron Yorston95ebcf72015-11-03 09:42:23 +00008389#endif
Denys Vlasenko888527c2016-10-02 16:54:17 +02008390 "if",
8391 "in",
8392 "then",
8393 "until",
8394 "while",
8395 "{",
8396 "}",
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008397};
8398
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008399/* Wrapper around strcmp for qsort/bsearch/... */
8400static int
8401pstrcmp(const void *a, const void *b)
8402{
Denys Vlasenko888527c2016-10-02 16:54:17 +02008403 return strcmp((char*)a, *(char**)b);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008404}
8405
8406static const char *const *
8407findkwd(const char *s)
8408{
8409 return bsearch(s, tokname_array + KWDOFFSET,
Denis Vlasenko80b8b392007-06-25 10:55:35 +00008410 ARRAY_SIZE(tokname_array) - KWDOFFSET,
8411 sizeof(tokname_array[0]), pstrcmp);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008412}
8413
8414/*
8415 * Locate and print what a word is...
8416 */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008417static int
Ron Yorston3f221112015-08-03 13:47:33 +01008418describe_command(char *command, const char *path, int describe_command_verbose)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008419{
8420 struct cmdentry entry;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008421#if ENABLE_ASH_ALIAS
8422 const struct alias *ap;
8423#endif
Ron Yorston3f221112015-08-03 13:47:33 +01008424
8425 path = path ? path : pathval();
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008426
8427 if (describe_command_verbose) {
8428 out1str(command);
8429 }
8430
8431 /* First look at the keywords */
8432 if (findkwd(command)) {
8433 out1str(describe_command_verbose ? " is a shell keyword" : command);
8434 goto out;
8435 }
8436
8437#if ENABLE_ASH_ALIAS
8438 /* Then look at the aliases */
8439 ap = lookupalias(command, 0);
8440 if (ap != NULL) {
Denis Vlasenko46846e22007-05-20 13:08:31 +00008441 if (!describe_command_verbose) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008442 out1str("alias ");
8443 printalias(ap);
8444 return 0;
8445 }
Denis Vlasenko46846e22007-05-20 13:08:31 +00008446 out1fmt(" is an alias for %s", ap->val);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008447 goto out;
8448 }
8449#endif
Youfu Zhang6683d1c2017-05-26 15:31:29 +08008450 /* Brute force */
8451 find_command(command, &entry, DO_ABS, path);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008452
8453 switch (entry.cmdtype) {
8454 case CMDNORMAL: {
8455 int j = entry.u.index;
8456 char *p;
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00008457 if (j < 0) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008458 p = command;
8459 } else {
8460 do {
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02008461 p = path_advance(&path, command);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008462 stunalloc(p);
8463 } while (--j >= 0);
8464 }
8465 if (describe_command_verbose) {
Youfu Zhang6683d1c2017-05-26 15:31:29 +08008466 out1fmt(" is %s", p);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008467 } else {
8468 out1str(p);
8469 }
8470 break;
8471 }
8472
8473 case CMDFUNCTION:
8474 if (describe_command_verbose) {
8475 out1str(" is a shell function");
8476 } else {
8477 out1str(command);
8478 }
8479 break;
8480
8481 case CMDBUILTIN:
8482 if (describe_command_verbose) {
8483 out1fmt(" is a %sshell builtin",
8484 IS_BUILTIN_SPECIAL(entry.u.cmd) ?
8485 "special " : nullstr
8486 );
8487 } else {
8488 out1str(command);
8489 }
8490 break;
8491
8492 default:
8493 if (describe_command_verbose) {
8494 out1str(": not found\n");
8495 }
8496 return 127;
8497 }
8498 out:
Denys Vlasenko285ad152009-12-04 23:02:27 +01008499 out1str("\n");
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008500 return 0;
8501}
8502
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02008503static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00008504typecmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008505{
Denis Vlasenko46846e22007-05-20 13:08:31 +00008506 int i = 1;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008507 int err = 0;
Denis Vlasenko46846e22007-05-20 13:08:31 +00008508 int verbose = 1;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008509
Denis Vlasenko46846e22007-05-20 13:08:31 +00008510 /* type -p ... ? (we don't bother checking for 'p') */
Denis Vlasenko1fc62382007-06-25 22:55:34 +00008511 if (argv[1] && argv[1][0] == '-') {
Denis Vlasenko46846e22007-05-20 13:08:31 +00008512 i++;
8513 verbose = 0;
8514 }
Denis Vlasenko68404f12008-03-17 09:00:54 +00008515 while (argv[i]) {
Ron Yorston3f221112015-08-03 13:47:33 +01008516 err |= describe_command(argv[i++], NULL, verbose);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008517 }
8518 return err;
8519}
8520
8521#if ENABLE_ASH_CMDCMD
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008522/* Is it "command [-p] PROG ARGS" bltin, no other opts? Return ptr to "PROG" if yes */
8523static char **
8524parse_command_args(char **argv, const char **path)
8525{
8526 char *cp, c;
8527
8528 for (;;) {
8529 cp = *++argv;
8530 if (!cp)
8531 return NULL;
8532 if (*cp++ != '-')
8533 break;
8534 c = *cp++;
8535 if (!c)
8536 break;
8537 if (c == '-' && !*cp) {
8538 if (!*++argv)
8539 return NULL;
8540 break;
8541 }
8542 do {
8543 switch (c) {
8544 case 'p':
8545 *path = bb_default_path;
8546 break;
8547 default:
8548 /* run 'typecmd' for other options */
8549 return NULL;
8550 }
8551 c = *cp++;
8552 } while (c);
8553 }
8554 return argv;
8555}
8556
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02008557static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00008558commandcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008559{
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008560 char *cmd;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008561 int c;
8562 enum {
8563 VERIFY_BRIEF = 1,
8564 VERIFY_VERBOSE = 2,
8565 } verify = 0;
Ron Yorston3f221112015-08-03 13:47:33 +01008566 const char *path = NULL;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008567
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008568 /* "command [-p] PROG ARGS" (that is, without -V or -v)
8569 * never reaches this function.
8570 */
8571
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008572 while ((c = nextopt("pvV")) != '\0')
8573 if (c == 'V')
8574 verify |= VERIFY_VERBOSE;
8575 else if (c == 'v')
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008576 /*verify |= VERIFY_BRIEF*/;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008577#if DEBUG
8578 else if (c != 'p')
8579 abort();
8580#endif
Ron Yorston3f221112015-08-03 13:47:33 +01008581 else
8582 path = bb_default_path;
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008583
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00008584 /* Mimic bash: just "command -v" doesn't complain, it's a nop */
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008585 cmd = *argptr;
8586 if (/*verify && */ cmd)
8587 return describe_command(cmd, path, verify /* - VERIFY_BRIEF*/);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008588
8589 return 0;
8590}
8591#endif
8592
8593
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008594/*static int funcblocksize; // size of structures in function */
8595/*static int funcstringsize; // size of strings in node */
Denis Vlasenko340299a2008-11-21 10:36:36 +00008596static void *funcblock; /* block to allocate function from */
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008597static char *funcstring_end; /* end of block to allocate strings from */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008598
Denys Vlasenko3e134eb2016-04-22 18:09:21 +02008599static const uint8_t nodesize[N_NUMBER] ALIGN1 = {
Denis Vlasenko340299a2008-11-21 10:36:36 +00008600 [NCMD ] = SHELL_ALIGN(sizeof(struct ncmd)),
8601 [NPIPE ] = SHELL_ALIGN(sizeof(struct npipe)),
8602 [NREDIR ] = SHELL_ALIGN(sizeof(struct nredir)),
8603 [NBACKGND ] = SHELL_ALIGN(sizeof(struct nredir)),
8604 [NSUBSHELL] = SHELL_ALIGN(sizeof(struct nredir)),
8605 [NAND ] = SHELL_ALIGN(sizeof(struct nbinary)),
8606 [NOR ] = SHELL_ALIGN(sizeof(struct nbinary)),
8607 [NSEMI ] = SHELL_ALIGN(sizeof(struct nbinary)),
8608 [NIF ] = SHELL_ALIGN(sizeof(struct nif)),
8609 [NWHILE ] = SHELL_ALIGN(sizeof(struct nbinary)),
8610 [NUNTIL ] = SHELL_ALIGN(sizeof(struct nbinary)),
8611 [NFOR ] = SHELL_ALIGN(sizeof(struct nfor)),
8612 [NCASE ] = SHELL_ALIGN(sizeof(struct ncase)),
8613 [NCLIST ] = SHELL_ALIGN(sizeof(struct nclist)),
8614 [NDEFUN ] = SHELL_ALIGN(sizeof(struct narg)),
8615 [NARG ] = SHELL_ALIGN(sizeof(struct narg)),
8616 [NTO ] = SHELL_ALIGN(sizeof(struct nfile)),
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01008617#if BASH_REDIR_OUTPUT
Denis Vlasenko340299a2008-11-21 10:36:36 +00008618 [NTO2 ] = SHELL_ALIGN(sizeof(struct nfile)),
Denis Vlasenkocc5feab2008-11-22 01:32:40 +00008619#endif
Denis Vlasenko340299a2008-11-21 10:36:36 +00008620 [NCLOBBER ] = SHELL_ALIGN(sizeof(struct nfile)),
8621 [NFROM ] = SHELL_ALIGN(sizeof(struct nfile)),
8622 [NFROMTO ] = SHELL_ALIGN(sizeof(struct nfile)),
8623 [NAPPEND ] = SHELL_ALIGN(sizeof(struct nfile)),
8624 [NTOFD ] = SHELL_ALIGN(sizeof(struct ndup)),
8625 [NFROMFD ] = SHELL_ALIGN(sizeof(struct ndup)),
8626 [NHERE ] = SHELL_ALIGN(sizeof(struct nhere)),
8627 [NXHERE ] = SHELL_ALIGN(sizeof(struct nhere)),
8628 [NNOT ] = SHELL_ALIGN(sizeof(struct nnot)),
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008629};
8630
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008631static int calcsize(int funcblocksize, union node *n);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008632
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008633static int
8634sizenodelist(int funcblocksize, struct nodelist *lp)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008635{
8636 while (lp) {
8637 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008638 funcblocksize = calcsize(funcblocksize, lp->n);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008639 lp = lp->next;
8640 }
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008641 return funcblocksize;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008642}
8643
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008644static int
8645calcsize(int funcblocksize, union node *n)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008646{
8647 if (n == NULL)
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008648 return funcblocksize;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008649 funcblocksize += nodesize[n->type];
8650 switch (n->type) {
8651 case NCMD:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008652 funcblocksize = calcsize(funcblocksize, n->ncmd.redirect);
8653 funcblocksize = calcsize(funcblocksize, n->ncmd.args);
8654 funcblocksize = calcsize(funcblocksize, n->ncmd.assign);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008655 break;
8656 case NPIPE:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008657 funcblocksize = sizenodelist(funcblocksize, n->npipe.cmdlist);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008658 break;
8659 case NREDIR:
8660 case NBACKGND:
8661 case NSUBSHELL:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008662 funcblocksize = calcsize(funcblocksize, n->nredir.redirect);
8663 funcblocksize = calcsize(funcblocksize, n->nredir.n);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008664 break;
8665 case NAND:
8666 case NOR:
8667 case NSEMI:
8668 case NWHILE:
8669 case NUNTIL:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008670 funcblocksize = calcsize(funcblocksize, n->nbinary.ch2);
8671 funcblocksize = calcsize(funcblocksize, n->nbinary.ch1);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008672 break;
8673 case NIF:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008674 funcblocksize = calcsize(funcblocksize, n->nif.elsepart);
8675 funcblocksize = calcsize(funcblocksize, n->nif.ifpart);
8676 funcblocksize = calcsize(funcblocksize, n->nif.test);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008677 break;
8678 case NFOR:
Denys Vlasenko561639a2016-10-07 04:28:33 +02008679 funcblocksize += SHELL_ALIGN(strlen(n->nfor.var) + 1); /* was funcstringsize += ... */
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008680 funcblocksize = calcsize(funcblocksize, n->nfor.body);
8681 funcblocksize = calcsize(funcblocksize, n->nfor.args);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008682 break;
8683 case NCASE:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008684 funcblocksize = calcsize(funcblocksize, n->ncase.cases);
8685 funcblocksize = calcsize(funcblocksize, n->ncase.expr);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008686 break;
8687 case NCLIST:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008688 funcblocksize = calcsize(funcblocksize, n->nclist.body);
8689 funcblocksize = calcsize(funcblocksize, n->nclist.pattern);
8690 funcblocksize = calcsize(funcblocksize, n->nclist.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008691 break;
8692 case NDEFUN:
Denys Vlasenko675d24a2018-01-27 22:02:05 +01008693 funcblocksize = calcsize(funcblocksize, n->ndefun.body);
8694 funcblocksize += SHELL_ALIGN(strlen(n->ndefun.text) + 1);
8695 break;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008696 case NARG:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008697 funcblocksize = sizenodelist(funcblocksize, n->narg.backquote);
Denys Vlasenko561639a2016-10-07 04:28:33 +02008698 funcblocksize += SHELL_ALIGN(strlen(n->narg.text) + 1); /* was funcstringsize += ... */
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008699 funcblocksize = calcsize(funcblocksize, n->narg.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008700 break;
8701 case NTO:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01008702#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00008703 case NTO2:
8704#endif
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008705 case NCLOBBER:
8706 case NFROM:
8707 case NFROMTO:
8708 case NAPPEND:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008709 funcblocksize = calcsize(funcblocksize, n->nfile.fname);
8710 funcblocksize = calcsize(funcblocksize, n->nfile.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008711 break;
8712 case NTOFD:
8713 case NFROMFD:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008714 funcblocksize = calcsize(funcblocksize, n->ndup.vname);
8715 funcblocksize = calcsize(funcblocksize, n->ndup.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008716 break;
8717 case NHERE:
8718 case NXHERE:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008719 funcblocksize = calcsize(funcblocksize, n->nhere.doc);
8720 funcblocksize = calcsize(funcblocksize, n->nhere.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008721 break;
8722 case NNOT:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008723 funcblocksize = calcsize(funcblocksize, n->nnot.com);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008724 break;
8725 };
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008726 return funcblocksize;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008727}
8728
8729static char *
8730nodeckstrdup(char *s)
8731{
Denys Vlasenko561639a2016-10-07 04:28:33 +02008732 funcstring_end -= SHELL_ALIGN(strlen(s) + 1);
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008733 return strcpy(funcstring_end, s);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008734}
8735
8736static union node *copynode(union node *);
8737
8738static struct nodelist *
8739copynodelist(struct nodelist *lp)
8740{
8741 struct nodelist *start;
8742 struct nodelist **lpp;
8743
8744 lpp = &start;
8745 while (lp) {
8746 *lpp = funcblock;
8747 funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist));
8748 (*lpp)->n = copynode(lp->n);
8749 lp = lp->next;
8750 lpp = &(*lpp)->next;
8751 }
8752 *lpp = NULL;
8753 return start;
8754}
8755
8756static union node *
8757copynode(union node *n)
8758{
8759 union node *new;
8760
8761 if (n == NULL)
8762 return NULL;
8763 new = funcblock;
8764 funcblock = (char *) funcblock + nodesize[n->type];
8765
8766 switch (n->type) {
8767 case NCMD:
8768 new->ncmd.redirect = copynode(n->ncmd.redirect);
8769 new->ncmd.args = copynode(n->ncmd.args);
8770 new->ncmd.assign = copynode(n->ncmd.assign);
Denys Vlasenko675d24a2018-01-27 22:02:05 +01008771 new->ncmd.linno = n->ncmd.linno;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008772 break;
8773 case NPIPE:
8774 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00008775 new->npipe.pipe_backgnd = n->npipe.pipe_backgnd;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008776 break;
8777 case NREDIR:
8778 case NBACKGND:
8779 case NSUBSHELL:
8780 new->nredir.redirect = copynode(n->nredir.redirect);
8781 new->nredir.n = copynode(n->nredir.n);
Denys Vlasenko675d24a2018-01-27 22:02:05 +01008782 new->nredir.linno = n->nredir.linno;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008783 break;
8784 case NAND:
8785 case NOR:
8786 case NSEMI:
8787 case NWHILE:
8788 case NUNTIL:
8789 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8790 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8791 break;
8792 case NIF:
8793 new->nif.elsepart = copynode(n->nif.elsepart);
8794 new->nif.ifpart = copynode(n->nif.ifpart);
8795 new->nif.test = copynode(n->nif.test);
8796 break;
8797 case NFOR:
8798 new->nfor.var = nodeckstrdup(n->nfor.var);
8799 new->nfor.body = copynode(n->nfor.body);
8800 new->nfor.args = copynode(n->nfor.args);
Denys Vlasenko675d24a2018-01-27 22:02:05 +01008801 new->nfor.linno = n->nfor.linno;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008802 break;
8803 case NCASE:
8804 new->ncase.cases = copynode(n->ncase.cases);
8805 new->ncase.expr = copynode(n->ncase.expr);
Denys Vlasenko675d24a2018-01-27 22:02:05 +01008806 new->ncase.linno = n->ncase.linno;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008807 break;
8808 case NCLIST:
8809 new->nclist.body = copynode(n->nclist.body);
8810 new->nclist.pattern = copynode(n->nclist.pattern);
8811 new->nclist.next = copynode(n->nclist.next);
8812 break;
8813 case NDEFUN:
Denys Vlasenko675d24a2018-01-27 22:02:05 +01008814 new->ndefun.body = copynode(n->ndefun.body);
8815 new->ndefun.text = nodeckstrdup(n->ndefun.text);
8816 new->ndefun.linno = n->ndefun.linno;
8817 break;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008818 case NARG:
8819 new->narg.backquote = copynodelist(n->narg.backquote);
8820 new->narg.text = nodeckstrdup(n->narg.text);
8821 new->narg.next = copynode(n->narg.next);
8822 break;
8823 case NTO:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01008824#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00008825 case NTO2:
8826#endif
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008827 case NCLOBBER:
8828 case NFROM:
8829 case NFROMTO:
8830 case NAPPEND:
8831 new->nfile.fname = copynode(n->nfile.fname);
8832 new->nfile.fd = n->nfile.fd;
8833 new->nfile.next = copynode(n->nfile.next);
8834 break;
8835 case NTOFD:
8836 case NFROMFD:
8837 new->ndup.vname = copynode(n->ndup.vname);
8838 new->ndup.dupfd = n->ndup.dupfd;
8839 new->ndup.fd = n->ndup.fd;
8840 new->ndup.next = copynode(n->ndup.next);
8841 break;
8842 case NHERE:
8843 case NXHERE:
8844 new->nhere.doc = copynode(n->nhere.doc);
8845 new->nhere.fd = n->nhere.fd;
8846 new->nhere.next = copynode(n->nhere.next);
8847 break;
8848 case NNOT:
8849 new->nnot.com = copynode(n->nnot.com);
8850 break;
8851 };
8852 new->type = n->type;
8853 return new;
8854}
8855
8856/*
8857 * Make a copy of a parse tree.
8858 */
8859static struct funcnode *
8860copyfunc(union node *n)
8861{
8862 struct funcnode *f;
8863 size_t blocksize;
8864
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008865 /*funcstringsize = 0;*/
8866 blocksize = offsetof(struct funcnode, n) + calcsize(0, n);
8867 f = ckzalloc(blocksize /* + funcstringsize */);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008868 funcblock = (char *) f + offsetof(struct funcnode, n);
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008869 funcstring_end = (char *) f + blocksize;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008870 copynode(n);
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008871 /* f->count = 0; - ckzalloc did it */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008872 return f;
8873}
8874
8875/*
8876 * Define a shell function.
8877 */
8878static void
Denys Vlasenko7aec8682016-10-25 20:26:02 +02008879defun(union node *func)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008880{
8881 struct cmdentry entry;
8882
8883 INT_OFF;
8884 entry.cmdtype = CMDFUNCTION;
8885 entry.u.func = copyfunc(func);
Denys Vlasenko675d24a2018-01-27 22:02:05 +01008886 addcmdentry(func->ndefun.text, &entry);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008887 INT_ON;
8888}
8889
Denis Vlasenko4b875702009-03-19 13:30:04 +00008890/* Reasons for skipping commands (see comment on breakcmd routine) */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008891#define SKIPBREAK (1 << 0)
8892#define SKIPCONT (1 << 1)
8893#define SKIPFUNC (1 << 2)
Denis Vlasenko4b875702009-03-19 13:30:04 +00008894static smallint evalskip; /* set to SKIPxxx if we are skipping commands */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008895static int skipcount; /* number of levels to skip */
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +00008896static int loopnest; /* current loop nesting level */
Denys Vlasenko675d24a2018-01-27 22:02:05 +01008897static int funcline; /* starting line number of current function, or 0 if not in a function */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008898
Denis Vlasenko4b875702009-03-19 13:30:04 +00008899/* Forward decl way out to parsing code - dotrap needs it */
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02008900static int evalstring(char *s, int flags);
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008901
Denis Vlasenko4b875702009-03-19 13:30:04 +00008902/* Called to execute a trap.
8903 * Single callsite - at the end of evaltree().
Denys Vlasenkob563f622010-09-25 17:15:13 +02008904 * If we return non-zero, evaltree raises EXEXIT exception.
Denis Vlasenko4b875702009-03-19 13:30:04 +00008905 *
8906 * Perhaps we should avoid entering new trap handlers
8907 * while we are executing a trap handler. [is it a TODO?]
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008908 */
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008909static void
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008910dotrap(void)
8911{
Denis Vlasenko4b875702009-03-19 13:30:04 +00008912 uint8_t *g;
8913 int sig;
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008914 uint8_t last_status;
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008915
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008916 if (!pending_sig)
8917 return;
8918
8919 last_status = exitstatus;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02008920 pending_sig = 0;
Denys Vlasenkode892052016-10-02 01:49:13 +02008921 barrier();
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008922
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008923 TRACE(("dotrap entered\n"));
Denis Vlasenko4b875702009-03-19 13:30:04 +00008924 for (sig = 1, g = gotsig; sig < NSIG; sig++, g++) {
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008925 char *p;
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008926
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008927 if (!*g)
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008928 continue;
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008929
8930 if (evalskip) {
8931 pending_sig = sig;
8932 break;
8933 }
8934
8935 p = trap[sig];
Denis Vlasenko4b875702009-03-19 13:30:04 +00008936 /* non-trapped SIGINT is handled separately by raise_interrupt,
8937 * don't upset it by resetting gotsig[SIGINT-1] */
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008938 if (sig == SIGINT && !p)
Denis Vlasenko4b875702009-03-19 13:30:04 +00008939 continue;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008940
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008941 TRACE(("sig %d is active, will run handler '%s'\n", sig, p));
Denis Vlasenko4b875702009-03-19 13:30:04 +00008942 *g = 0;
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008943 if (!p)
Denis Vlasenko4b875702009-03-19 13:30:04 +00008944 continue;
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008945 evalstring(p, 0);
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008946 }
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008947 exitstatus = last_status;
8948 TRACE(("dotrap returns\n"));
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008949}
8950
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00008951/* forward declarations - evaluation is fairly recursive business... */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008952static int evalloop(union node *, int);
8953static int evalfor(union node *, int);
8954static int evalcase(union node *, int);
8955static int evalsubshell(union node *, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008956static void expredir(union node *);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008957static int evalpipe(union node *, int);
8958static int evalcommand(union node *, int);
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02008959static int evalbltin(const struct builtincmd *, int, char **, int);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008960static void prehash(union node *);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008961
Eric Andersen62483552001-07-10 06:09:16 +00008962/*
Eric Andersenc470f442003-07-28 09:56:35 +00008963 * Evaluate a parse tree. The value is left in the global variable
8964 * exitstatus.
Eric Andersen62483552001-07-10 06:09:16 +00008965 */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008966static int
Eric Andersenc470f442003-07-28 09:56:35 +00008967evaltree(union node *n, int flags)
Eric Andersen62483552001-07-10 06:09:16 +00008968{
Eric Andersenc470f442003-07-28 09:56:35 +00008969 int checkexit = 0;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008970 int (*evalfn)(union node *, int);
8971 int status = 0;
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008972
Eric Andersenc470f442003-07-28 09:56:35 +00008973 if (n == NULL) {
8974 TRACE(("evaltree(NULL) called\n"));
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02008975 goto out;
Eric Andersen62483552001-07-10 06:09:16 +00008976 }
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008977 TRACE(("evaltree(%p: %d, %d) called\n", n, n->type, flags));
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008978
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008979 dotrap();
8980
Eric Andersenc470f442003-07-28 09:56:35 +00008981 switch (n->type) {
8982 default:
Denis Vlasenkoa7189f02006-11-17 20:29:00 +00008983#if DEBUG
Eric Andersenc470f442003-07-28 09:56:35 +00008984 out1fmt("Node type = %d\n", n->type);
Denys Vlasenko8131eea2009-11-02 14:19:51 +01008985 fflush_all();
Eric Andersenc470f442003-07-28 09:56:35 +00008986 break;
8987#endif
8988 case NNOT:
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008989 status = !evaltree(n->nnot.com, EV_TESTED);
Eric Andersenc470f442003-07-28 09:56:35 +00008990 goto setstatus;
8991 case NREDIR:
Denys Vlasenko675d24a2018-01-27 22:02:05 +01008992 errlinno = lineno = n->nredir.linno;
8993 if (funcline)
8994 lineno -= funcline - 1;
Eric Andersenc470f442003-07-28 09:56:35 +00008995 expredir(n->nredir.redirect);
Denys Vlasenko1c79aeb2017-07-29 22:51:52 +02008996 pushredir(n->nredir.redirect);
Eric Andersenc470f442003-07-28 09:56:35 +00008997 status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
8998 if (!status) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008999 status = evaltree(n->nredir.n, flags & EV_TESTED);
Eric Andersenc470f442003-07-28 09:56:35 +00009000 }
Denys Vlasenkoeaf94362016-10-25 21:46:03 +02009001 if (n->nredir.redirect)
Denys Vlasenko035486c2017-07-31 04:09:19 +02009002 popredir(/*drop:*/ 0);
Eric Andersenc470f442003-07-28 09:56:35 +00009003 goto setstatus;
9004 case NCMD:
9005 evalfn = evalcommand;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009006 checkexit:
Eric Andersenc470f442003-07-28 09:56:35 +00009007 if (eflag && !(flags & EV_TESTED))
9008 checkexit = ~0;
9009 goto calleval;
9010 case NFOR:
9011 evalfn = evalfor;
9012 goto calleval;
9013 case NWHILE:
9014 case NUNTIL:
9015 evalfn = evalloop;
9016 goto calleval;
9017 case NSUBSHELL:
9018 case NBACKGND:
9019 evalfn = evalsubshell;
Denys Vlasenkocf98b0c2016-10-25 18:19:39 +02009020 goto checkexit;
Eric Andersenc470f442003-07-28 09:56:35 +00009021 case NPIPE:
9022 evalfn = evalpipe;
9023 goto checkexit;
9024 case NCASE:
9025 evalfn = evalcase;
9026 goto calleval;
9027 case NAND:
9028 case NOR:
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00009029 case NSEMI: {
9030
Eric Andersenc470f442003-07-28 09:56:35 +00009031#if NAND + 1 != NOR
9032#error NAND + 1 != NOR
9033#endif
9034#if NOR + 1 != NSEMI
9035#error NOR + 1 != NSEMI
9036#endif
Denis Vlasenko87d5fd92008-07-26 13:48:35 +00009037 unsigned is_or = n->type - NAND;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009038 status = evaltree(
Eric Andersenc470f442003-07-28 09:56:35 +00009039 n->nbinary.ch1,
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00009040 (flags | ((is_or >> 1) - 1)) & EV_TESTED
Eric Andersenc470f442003-07-28 09:56:35 +00009041 );
Denys Vlasenkobc1a0082016-10-02 15:31:33 +02009042 if ((!status) == is_or || evalskip)
Eric Andersenc470f442003-07-28 09:56:35 +00009043 break;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009044 n = n->nbinary.ch2;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009045 evaln:
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009046 evalfn = evaltree;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009047 calleval:
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009048 status = evalfn(n, flags);
9049 goto setstatus;
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00009050 }
Eric Andersenc470f442003-07-28 09:56:35 +00009051 case NIF:
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009052 status = evaltree(n->nif.test, EV_TESTED);
Eric Andersenc470f442003-07-28 09:56:35 +00009053 if (evalskip)
9054 break;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009055 if (!status) {
Eric Andersenc470f442003-07-28 09:56:35 +00009056 n = n->nif.ifpart;
9057 goto evaln;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00009058 }
9059 if (n->nif.elsepart) {
Eric Andersenc470f442003-07-28 09:56:35 +00009060 n = n->nif.elsepart;
9061 goto evaln;
9062 }
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009063 status = 0;
9064 goto setstatus;
Eric Andersenc470f442003-07-28 09:56:35 +00009065 case NDEFUN:
Denys Vlasenko7aec8682016-10-25 20:26:02 +02009066 defun(n);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009067 /* Not necessary. To test it:
9068 * "false; f() { qwerty; }; echo $?" should print 0.
9069 */
9070 /* status = 0; */
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009071 setstatus:
Eric Andersenc470f442003-07-28 09:56:35 +00009072 exitstatus = status;
9073 break;
9074 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009075 out:
Denys Vlasenkob563f622010-09-25 17:15:13 +02009076 /* Order of checks below is important:
9077 * signal handlers trigger before exit caused by "set -e".
9078 */
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02009079 dotrap();
9080
9081 if (checkexit & status)
Denis Vlasenkob012b102007-02-19 22:43:01 +00009082 raise_exception(EXEXIT);
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02009083 if (flags & EV_EXIT)
9084 raise_exception(EXEXIT);
Denis Vlasenko653d8e72009-03-19 21:59:35 +00009085
Denis Vlasenko653d8e72009-03-19 21:59:35 +00009086 TRACE(("leaving evaltree (no interrupts)\n"));
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009087 return exitstatus;
Eric Andersen62483552001-07-10 06:09:16 +00009088}
9089
Denys Vlasenko37dc08b2016-10-02 04:38:07 +02009090static int
9091skiploop(void)
Denys Vlasenko35ec8182016-10-01 19:56:52 +02009092{
9093 int skip = evalskip;
9094
9095 switch (skip) {
9096 case 0:
9097 break;
9098 case SKIPBREAK:
9099 case SKIPCONT:
9100 if (--skipcount <= 0) {
9101 evalskip = 0;
9102 break;
9103 }
9104 skip = SKIPBREAK;
9105 break;
9106 }
9107 return skip;
9108}
9109
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009110static int
Eric Andersenc470f442003-07-28 09:56:35 +00009111evalloop(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00009112{
Denys Vlasenko35ec8182016-10-01 19:56:52 +02009113 int skip;
Eric Andersencb57d552001-06-28 07:25:16 +00009114 int status;
9115
9116 loopnest++;
9117 status = 0;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009118 flags &= EV_TESTED;
Denys Vlasenko35ec8182016-10-01 19:56:52 +02009119 do {
Eric Andersenc470f442003-07-28 09:56:35 +00009120 int i;
9121
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009122 i = evaltree(n->nbinary.ch1, EV_TESTED);
Denys Vlasenko35ec8182016-10-01 19:56:52 +02009123 skip = skiploop();
9124 if (skip == SKIPFUNC)
9125 status = i;
9126 if (skip)
9127 continue;
Eric Andersenc470f442003-07-28 09:56:35 +00009128 if (n->type != NWHILE)
9129 i = !i;
9130 if (i != 0)
9131 break;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009132 status = evaltree(n->nbinary.ch2, flags);
Denys Vlasenko35ec8182016-10-01 19:56:52 +02009133 skip = skiploop();
9134 } while (!(skip & ~SKIPCONT));
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009135 loopnest--;
9136
9137 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00009138}
9139
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009140static int
Eric Andersenc470f442003-07-28 09:56:35 +00009141evalfor(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00009142{
9143 struct arglist arglist;
9144 union node *argp;
9145 struct strlist *sp;
9146 struct stackmark smark;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009147 int status = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00009148
Denys Vlasenko675d24a2018-01-27 22:02:05 +01009149 errlinno = lineno = n->ncase.linno;
9150 if (funcline)
9151 lineno -= funcline - 1;
9152
Eric Andersencb57d552001-06-28 07:25:16 +00009153 setstackmark(&smark);
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00009154 arglist.list = NULL;
Eric Andersencb57d552001-06-28 07:25:16 +00009155 arglist.lastp = &arglist.list;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009156 for (argp = n->nfor.args; argp; argp = argp->narg.next) {
Ron Yorston549deab2015-05-18 09:57:51 +02009157 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
Eric Andersencb57d552001-06-28 07:25:16 +00009158 }
9159 *arglist.lastp = NULL;
9160
Eric Andersencb57d552001-06-28 07:25:16 +00009161 loopnest++;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009162 flags &= EV_TESTED;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009163 for (sp = arglist.list; sp; sp = sp->next) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009164 setvar0(n->nfor.var, sp->text);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009165 status = evaltree(n->nfor.body, flags);
Denys Vlasenko35ec8182016-10-01 19:56:52 +02009166 if (skiploop() & ~SKIPCONT)
Eric Andersencb57d552001-06-28 07:25:16 +00009167 break;
Eric Andersencb57d552001-06-28 07:25:16 +00009168 }
9169 loopnest--;
Eric Andersencb57d552001-06-28 07:25:16 +00009170 popstackmark(&smark);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009171
9172 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00009173}
9174
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009175static int
Eric Andersenc470f442003-07-28 09:56:35 +00009176evalcase(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00009177{
9178 union node *cp;
9179 union node *patp;
9180 struct arglist arglist;
9181 struct stackmark smark;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009182 int status = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00009183
Denys Vlasenko675d24a2018-01-27 22:02:05 +01009184 errlinno = lineno = n->ncase.linno;
9185 if (funcline)
9186 lineno -= funcline - 1;
9187
Eric Andersencb57d552001-06-28 07:25:16 +00009188 setstackmark(&smark);
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00009189 arglist.list = NULL;
Eric Andersencb57d552001-06-28 07:25:16 +00009190 arglist.lastp = &arglist.list;
Eric Andersencb57d552001-06-28 07:25:16 +00009191 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009192 for (cp = n->ncase.cases; cp && evalskip == 0; cp = cp->nclist.next) {
9193 for (patp = cp->nclist.pattern; patp; patp = patp->narg.next) {
Eric Andersencb57d552001-06-28 07:25:16 +00009194 if (casematch(patp, arglist.list->text)) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009195 /* Ensure body is non-empty as otherwise
9196 * EV_EXIT may prevent us from setting the
9197 * exit status.
9198 */
9199 if (evalskip == 0 && cp->nclist.body) {
9200 status = evaltree(cp->nclist.body, flags);
Eric Andersencb57d552001-06-28 07:25:16 +00009201 }
9202 goto out;
9203 }
9204 }
9205 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009206 out:
Eric Andersencb57d552001-06-28 07:25:16 +00009207 popstackmark(&smark);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009208
9209 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00009210}
9211
Eric Andersenc470f442003-07-28 09:56:35 +00009212/*
9213 * Kick off a subshell to evaluate a tree.
9214 */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009215static int
Eric Andersenc470f442003-07-28 09:56:35 +00009216evalsubshell(union node *n, int flags)
9217{
9218 struct job *jp;
Denys Vlasenko098b7132017-01-11 19:59:03 +01009219 int backgnd = (n->type == NBACKGND); /* FORK_BG(1) if yes, else FORK_FG(0) */
Eric Andersenc470f442003-07-28 09:56:35 +00009220 int status;
9221
Denys Vlasenko675d24a2018-01-27 22:02:05 +01009222 errlinno = lineno = n->nredir.linno;
9223 if (funcline)
9224 lineno -= funcline - 1;
9225
Eric Andersenc470f442003-07-28 09:56:35 +00009226 expredir(n->nredir.redirect);
Denys Vlasenko238bf182010-05-18 15:49:07 +02009227 if (!backgnd && (flags & EV_EXIT) && !may_have_traps)
Eric Andersenc470f442003-07-28 09:56:35 +00009228 goto nofork;
Denis Vlasenkob012b102007-02-19 22:43:01 +00009229 INT_OFF;
Denys Vlasenko098b7132017-01-11 19:59:03 +01009230 if (backgnd == FORK_FG)
9231 get_tty_state();
Denis Vlasenko68404f12008-03-17 09:00:54 +00009232 jp = makejob(/*n,*/ 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009233 if (forkshell(jp, n, backgnd) == 0) {
Denys Vlasenko238bf182010-05-18 15:49:07 +02009234 /* child */
Denis Vlasenkob012b102007-02-19 22:43:01 +00009235 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +00009236 flags |= EV_EXIT;
9237 if (backgnd)
Denys Vlasenko238bf182010-05-18 15:49:07 +02009238 flags &= ~EV_TESTED;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00009239 nofork:
Eric Andersenc470f442003-07-28 09:56:35 +00009240 redirect(n->nredir.redirect, 0);
9241 evaltreenr(n->nredir.n, flags);
9242 /* never returns */
9243 }
Denys Vlasenko70392332016-10-27 02:31:55 +02009244 /* parent */
Eric Andersenc470f442003-07-28 09:56:35 +00009245 status = 0;
Denys Vlasenko098b7132017-01-11 19:59:03 +01009246 if (backgnd == FORK_FG)
Eric Andersenc470f442003-07-28 09:56:35 +00009247 status = waitforjob(jp);
Denis Vlasenkob012b102007-02-19 22:43:01 +00009248 INT_ON;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009249 return status;
Eric Andersenc470f442003-07-28 09:56:35 +00009250}
9251
Eric Andersenc470f442003-07-28 09:56:35 +00009252/*
9253 * Compute the names of the files in a redirection list.
9254 */
Denis Vlasenko99eb8502007-02-23 21:09:49 +00009255static void fixredir(union node *, const char *, int);
Eric Andersenc470f442003-07-28 09:56:35 +00009256static void
9257expredir(union node *n)
9258{
9259 union node *redir;
9260
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009261 for (redir = n; redir; redir = redir->nfile.next) {
Eric Andersenc470f442003-07-28 09:56:35 +00009262 struct arglist fn;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009263
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00009264 fn.list = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00009265 fn.lastp = &fn.list;
9266 switch (redir->type) {
9267 case NFROMTO:
9268 case NFROM:
9269 case NTO:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01009270#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00009271 case NTO2:
9272#endif
Eric Andersenc470f442003-07-28 09:56:35 +00009273 case NCLOBBER:
9274 case NAPPEND:
9275 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02009276 TRACE(("expredir expanded to '%s'\n", fn.list->text));
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01009277#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00009278 store_expfname:
9279#endif
Denys Vlasenko7c4b13e2013-01-17 13:02:27 +01009280#if 0
9281// By the design of stack allocator, the loop of this kind:
9282// while true; do while true; do break; done </dev/null; done
9283// will look like a memory leak: ash plans to free expfname's
9284// of "/dev/null" as soon as it finishes running the loop
9285// (in this case, never).
9286// This "fix" is wrong:
Jon Tollefson4ba6c5d2012-11-13 19:26:53 +01009287 if (redir->nfile.expfname)
9288 stunalloc(redir->nfile.expfname);
Denys Vlasenko7c4b13e2013-01-17 13:02:27 +01009289// It results in corrupted state of stacked allocations.
9290#endif
Eric Andersenc470f442003-07-28 09:56:35 +00009291 redir->nfile.expfname = fn.list->text;
9292 break;
9293 case NFROMFD:
Denis Vlasenko559691a2008-10-05 18:39:31 +00009294 case NTOFD: /* >& */
Eric Andersenc470f442003-07-28 09:56:35 +00009295 if (redir->ndup.vname) {
9296 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009297 if (fn.list == NULL)
Denis Vlasenkob012b102007-02-19 22:43:01 +00009298 ash_msg_and_raise_error("redir error");
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01009299#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00009300//FIXME: we used expandarg with different args!
9301 if (!isdigit_str9(fn.list->text)) {
9302 /* >&file, not >&fd */
9303 if (redir->nfile.fd != 1) /* 123>&file - BAD */
9304 ash_msg_and_raise_error("redir error");
9305 redir->type = NTO2;
9306 goto store_expfname;
9307 }
9308#endif
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009309 fixredir(redir, fn.list->text, 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009310 }
9311 break;
9312 }
9313 }
9314}
9315
Eric Andersencb57d552001-06-28 07:25:16 +00009316/*
Eric Andersencb57d552001-06-28 07:25:16 +00009317 * Evaluate a pipeline. All the processes in the pipeline are children
9318 * of the process creating the pipeline. (This differs from some versions
9319 * of the shell, which make the last process in a pipeline the parent
9320 * of all the rest.)
9321 */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009322static int
Eric Andersenc470f442003-07-28 09:56:35 +00009323evalpipe(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00009324{
9325 struct job *jp;
9326 struct nodelist *lp;
9327 int pipelen;
9328 int prevfd;
9329 int pip[2];
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009330 int status = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00009331
Eric Andersenc470f442003-07-28 09:56:35 +00009332 TRACE(("evalpipe(0x%lx) called\n", (long)n));
Eric Andersencb57d552001-06-28 07:25:16 +00009333 pipelen = 0;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009334 for (lp = n->npipe.cmdlist; lp; lp = lp->next)
Eric Andersencb57d552001-06-28 07:25:16 +00009335 pipelen++;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009336 flags |= EV_EXIT;
Denis Vlasenkob012b102007-02-19 22:43:01 +00009337 INT_OFF;
Denys Vlasenko098b7132017-01-11 19:59:03 +01009338 if (n->npipe.pipe_backgnd == 0)
9339 get_tty_state();
Denis Vlasenko68404f12008-03-17 09:00:54 +00009340 jp = makejob(/*n,*/ pipelen);
Eric Andersencb57d552001-06-28 07:25:16 +00009341 prevfd = -1;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009342 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009343 prehash(lp->n);
Eric Andersencb57d552001-06-28 07:25:16 +00009344 pip[1] = -1;
9345 if (lp->next) {
9346 if (pipe(pip) < 0) {
9347 close(prevfd);
Denys Vlasenko12ffefb2017-08-23 14:52:56 +02009348 ash_msg_and_raise_perror("can't create pipe");
Eric Andersencb57d552001-06-28 07:25:16 +00009349 }
9350 }
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00009351 if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) {
Denys Vlasenko70392332016-10-27 02:31:55 +02009352 /* child */
Denis Vlasenkob012b102007-02-19 22:43:01 +00009353 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +00009354 if (pip[1] >= 0) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009355 close(pip[0]);
Eric Andersencb57d552001-06-28 07:25:16 +00009356 }
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009357 if (prevfd > 0) {
9358 dup2(prevfd, 0);
9359 close(prevfd);
9360 }
9361 if (pip[1] > 1) {
9362 dup2(pip[1], 1);
9363 close(pip[1]);
9364 }
Eric Andersenc470f442003-07-28 09:56:35 +00009365 evaltreenr(lp->n, flags);
9366 /* never returns */
Eric Andersencb57d552001-06-28 07:25:16 +00009367 }
Denys Vlasenko70392332016-10-27 02:31:55 +02009368 /* parent */
Eric Andersencb57d552001-06-28 07:25:16 +00009369 if (prevfd >= 0)
9370 close(prevfd);
9371 prevfd = pip[0];
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +00009372 /* Don't want to trigger debugging */
9373 if (pip[1] != -1)
9374 close(pip[1]);
Eric Andersencb57d552001-06-28 07:25:16 +00009375 }
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00009376 if (n->npipe.pipe_backgnd == 0) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009377 status = waitforjob(jp);
9378 TRACE(("evalpipe: job done exit status %d\n", status));
Eric Andersencb57d552001-06-28 07:25:16 +00009379 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00009380 INT_ON;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009381
9382 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00009383}
9384
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009385/*
9386 * Controls whether the shell is interactive or not.
9387 */
9388static void
9389setinteractive(int on)
9390{
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009391 static smallint is_interactive;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009392
9393 if (++on == is_interactive)
9394 return;
9395 is_interactive = on;
9396 setsignal(SIGINT);
9397 setsignal(SIGQUIT);
9398 setsignal(SIGTERM);
9399#if !ENABLE_FEATURE_SH_EXTRA_QUIET
9400 if (is_interactive > 1) {
9401 /* Looks like they want an interactive shell */
Denis Vlasenkoca525b42007-06-13 12:27:17 +00009402 static smallint did_banner;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009403
Denis Vlasenkoca525b42007-06-13 12:27:17 +00009404 if (!did_banner) {
Denys Vlasenkoc34c0332009-09-29 12:25:30 +02009405 /* note: ash and hush share this string */
9406 out1fmt("\n\n%s %s\n"
Denys Vlasenko2ec34962014-09-08 16:52:39 +02009407 IF_ASH_HELP("Enter 'help' for a list of built-in commands.\n")
9408 "\n",
Denys Vlasenkoc34c0332009-09-29 12:25:30 +02009409 bb_banner,
9410 "built-in shell (ash)"
9411 );
Denis Vlasenkoca525b42007-06-13 12:27:17 +00009412 did_banner = 1;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009413 }
9414 }
9415#endif
9416}
9417
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009418static void
9419optschanged(void)
9420{
9421#if DEBUG
9422 opentrace();
9423#endif
9424 setinteractive(iflag);
9425 setjobctl(mflag);
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009426#if ENABLE_FEATURE_EDITING_VI
9427 if (viflag)
9428 line_input_state->flags |= VI_MODE;
9429 else
9430 line_input_state->flags &= ~VI_MODE;
9431#else
9432 viflag = 0; /* forcibly keep the option off */
9433#endif
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009434}
9435
Denys Vlasenkob8ab27b2017-07-26 19:22:34 +02009436struct localvar_list {
9437 struct localvar_list *next;
9438 struct localvar *lv;
9439};
9440
9441static struct localvar_list *localvar_stack;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009442
9443/*
9444 * Called after a function returns.
9445 * Interrupts must be off.
9446 */
9447static void
Denys Vlasenko981a0562017-07-26 19:53:11 +02009448poplocalvars(int keep)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009449{
Denys Vlasenkob8ab27b2017-07-26 19:22:34 +02009450 struct localvar_list *ll;
9451 struct localvar *lvp, *next;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009452 struct var *vp;
9453
Denys Vlasenkob8ab27b2017-07-26 19:22:34 +02009454 INT_OFF;
9455 ll = localvar_stack;
9456 localvar_stack = ll->next;
9457
9458 next = ll->lv;
9459 free(ll);
9460
9461 while ((lvp = next) != NULL) {
9462 next = lvp->next;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009463 vp = lvp->vp;
Denys Vlasenkob563f622010-09-25 17:15:13 +02009464 TRACE(("poplocalvar %s\n", vp ? vp->var_text : "-"));
Denys Vlasenko981a0562017-07-26 19:53:11 +02009465 if (keep) {
9466 int bits = VSTRFIXED;
9467
9468 if (lvp->flags != VUNSET) {
9469 if (vp->var_text == lvp->text)
9470 bits |= VTEXTFIXED;
9471 else if (!(lvp->flags & (VTEXTFIXED|VSTACK)))
9472 free((char*)lvp->text);
9473 }
9474
9475 vp->flags &= ~bits;
9476 vp->flags |= (lvp->flags & bits);
9477
9478 if ((vp->flags &
9479 (VEXPORT|VREADONLY|VSTRFIXED|VUNSET)) == VUNSET)
9480 unsetvar(vp->var_text);
9481 } else if (vp == NULL) { /* $- saved */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009482 memcpy(optlist, lvp->text, sizeof(optlist));
9483 free((char*)lvp->text);
9484 optschanged();
Denys Vlasenkod5b500c2017-07-26 19:25:40 +02009485 } else if (lvp->flags == VUNSET) {
9486 vp->flags &= ~(VSTRFIXED|VREADONLY);
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009487 unsetvar(vp->var_text);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009488 } else {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009489 if (vp->var_func)
9490 vp->var_func(var_end(lvp->text));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009491 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009492 free((char*)vp->var_text);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009493 vp->flags = lvp->flags;
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009494 vp->var_text = lvp->text;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009495 }
9496 free(lvp);
9497 }
Denys Vlasenkob8ab27b2017-07-26 19:22:34 +02009498 INT_ON;
9499}
9500
9501/*
9502 * Create a new localvar environment.
9503 */
Denys Vlasenko484fc202017-07-26 19:55:31 +02009504static struct localvar_list *
Denys Vlasenkob8ab27b2017-07-26 19:22:34 +02009505pushlocalvars(void)
9506{
9507 struct localvar_list *ll;
9508
9509 INT_OFF;
9510 ll = ckzalloc(sizeof(*ll));
9511 /*ll->lv = NULL; - zalloc did it */
9512 ll->next = localvar_stack;
9513 localvar_stack = ll;
9514 INT_ON;
Denys Vlasenko484fc202017-07-26 19:55:31 +02009515
9516 return ll->next;
9517}
9518
9519static void
9520unwindlocalvars(struct localvar_list *stop)
9521{
9522 while (localvar_stack != stop)
9523 poplocalvars(0);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009524}
9525
9526static int
9527evalfun(struct funcnode *func, int argc, char **argv, int flags)
9528{
9529 volatile struct shparam saveparam;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009530 struct jmploc *volatile savehandler;
9531 struct jmploc jmploc;
9532 int e;
Denys Vlasenko675d24a2018-01-27 22:02:05 +01009533 int savefuncline;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009534
9535 saveparam = shellparam;
Denys Vlasenko675d24a2018-01-27 22:02:05 +01009536 savefuncline = funcline;
Denys Vlasenkoa2d121c2016-09-30 11:30:11 +02009537 savehandler = exception_handler;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009538 e = setjmp(jmploc.loc);
9539 if (e) {
9540 goto funcdone;
9541 }
9542 INT_OFF;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009543 exception_handler = &jmploc;
Denis Vlasenko01631112007-12-16 17:20:38 +00009544 shellparam.malloced = 0;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009545 func->count++;
Denys Vlasenko675d24a2018-01-27 22:02:05 +01009546 funcline = func->n.ndefun.linno;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009547 INT_ON;
9548 shellparam.nparam = argc - 1;
9549 shellparam.p = argv + 1;
9550#if ENABLE_ASH_GETOPTS
9551 shellparam.optind = 1;
9552 shellparam.optoff = -1;
9553#endif
Denys Vlasenkob8ab27b2017-07-26 19:22:34 +02009554 pushlocalvars();
Denys Vlasenko675d24a2018-01-27 22:02:05 +01009555 evaltree(func->n.ndefun.body, flags & EV_TESTED);
Denys Vlasenko981a0562017-07-26 19:53:11 +02009556 poplocalvars(0);
Denis Vlasenko01631112007-12-16 17:20:38 +00009557 funcdone:
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009558 INT_OFF;
Denys Vlasenko675d24a2018-01-27 22:02:05 +01009559 funcline = savefuncline;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009560 freefunc(func);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009561 freeparam(&shellparam);
9562 shellparam = saveparam;
9563 exception_handler = savehandler;
9564 INT_ON;
9565 evalskip &= ~SKIPFUNC;
9566 return e;
9567}
9568
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009569/*
9570 * Make a variable a local variable. When a variable is made local, it's
9571 * value and flags are saved in a localvar structure. The saved values
9572 * will be restored when the shell function returns. We handle the name
Denys Vlasenkoe0a4e102015-05-13 02:20:14 +02009573 * "-" as a special case: it makes changes to "set +-options" local
9574 * (options will be restored on return from the function).
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009575 */
9576static void
9577mklocal(char *name)
9578{
9579 struct localvar *lvp;
9580 struct var **vpp;
9581 struct var *vp;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009582 char *eq = strchr(name, '=');
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009583
9584 INT_OFF;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009585 /* Cater for duplicate "local". Examples:
9586 * x=0; f() { local x=1; echo $x; local x; echo $x; }; f; echo $x
9587 * x=0; f() { local x=1; echo $x; local x=2; echo $x; }; f; echo $x
9588 */
Denys Vlasenkob8ab27b2017-07-26 19:22:34 +02009589 lvp = localvar_stack->lv;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009590 while (lvp) {
Eugene Rudoy1285aa62015-04-26 23:32:00 +02009591 if (lvp->vp && varcmp(lvp->vp->var_text, name) == 0) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009592 if (eq)
9593 setvareq(name, 0);
9594 /* else:
9595 * it's a duplicate "local VAR" declaration, do nothing
9596 */
Denys Vlasenko06b11492016-11-04 16:43:18 +01009597 goto ret;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009598 }
9599 lvp = lvp->next;
9600 }
9601
9602 lvp = ckzalloc(sizeof(*lvp));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009603 if (LONE_DASH(name)) {
9604 char *p;
9605 p = ckmalloc(sizeof(optlist));
9606 lvp->text = memcpy(p, optlist, sizeof(optlist));
9607 vp = NULL;
9608 } else {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009609 vpp = hashvar(name);
9610 vp = *findvar(vpp, name);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009611 if (vp == NULL) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009612 /* variable did not exist yet */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009613 if (eq)
Denys Vlasenkod04fc712017-07-26 20:06:48 +02009614 vp = setvareq(name, VSTRFIXED);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009615 else
Denys Vlasenkod04fc712017-07-26 20:06:48 +02009616 vp = setvar(name, NULL, VSTRFIXED);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009617 lvp->flags = VUNSET;
9618 } else {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009619 lvp->text = vp->var_text;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009620 lvp->flags = vp->flags;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009621 /* make sure neither "struct var" nor string gets freed
9622 * during (un)setting:
9623 */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009624 vp->flags |= VSTRFIXED|VTEXTFIXED;
9625 if (eq)
9626 setvareq(name, 0);
Denys Vlasenko109ee5d2014-03-16 18:41:11 +01009627 else
9628 /* "local VAR" unsets VAR: */
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009629 setvar0(name, NULL);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009630 }
9631 }
9632 lvp->vp = vp;
Denys Vlasenkob8ab27b2017-07-26 19:22:34 +02009633 lvp->next = localvar_stack->lv;
9634 localvar_stack->lv = lvp;
Denys Vlasenko06b11492016-11-04 16:43:18 +01009635 ret:
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009636 INT_ON;
9637}
9638
9639/*
9640 * The "local" command.
9641 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009642static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009643localcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009644{
9645 char *name;
9646
Denys Vlasenkob8ab27b2017-07-26 19:22:34 +02009647 if (!localvar_stack)
Ron Yorstonef2386b2015-10-29 16:19:14 +00009648 ash_msg_and_raise_error("not in a function");
9649
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009650 argv = argptr;
9651 while ((name = *argv++) != NULL) {
9652 mklocal(name);
9653 }
9654 return 0;
9655}
9656
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009657static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009658falsecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009659{
9660 return 1;
9661}
9662
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009663static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009664truecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009665{
9666 return 0;
9667}
9668
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009669static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009670execcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009671{
Denys Vlasenko6c149f42017-04-12 21:31:32 +02009672 optionarg = NULL;
9673 while (nextopt("a:") != '\0')
9674 /* nextopt() sets optionarg to "-a ARGV0" */;
9675
9676 argv = argptr;
9677 if (argv[0]) {
9678 char *prog;
9679
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009680 iflag = 0; /* exit on error */
9681 mflag = 0;
9682 optschanged();
Denys Vlasenkoe5814a52016-07-16 18:33:55 +02009683 /* We should set up signals for "exec CMD"
9684 * the same way as for "CMD" without "exec".
9685 * But optschanged->setinteractive->setsignal
9686 * still thought we are a root shell. Therefore, for example,
9687 * SIGQUIT is still set to IGN. Fix it:
9688 */
9689 shlvl++;
9690 setsignal(SIGQUIT);
9691 /*setsignal(SIGTERM); - unnecessary because of iflag=0 */
9692 /*setsignal(SIGTSTP); - unnecessary because of mflag=0 */
9693 /*setsignal(SIGTTOU); - unnecessary because of mflag=0 */
9694
Denys Vlasenko6c149f42017-04-12 21:31:32 +02009695 prog = argv[0];
9696 if (optionarg)
9697 argv[0] = optionarg;
9698 shellexec(prog, argv, pathval(), 0);
Denys Vlasenkoe5814a52016-07-16 18:33:55 +02009699 /* NOTREACHED */
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009700 }
9701 return 0;
9702}
9703
9704/*
9705 * The return command.
9706 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009707static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009708returncmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009709{
9710 /*
9711 * If called outside a function, do what ksh does;
9712 * skip the rest of the file.
9713 */
Denys Vlasenko6a0710e2016-09-30 14:18:34 +02009714 evalskip = SKIPFUNC;
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009715 return argv[1] ? number(argv[1]) : exitstatus;
9716}
9717
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009718/* Forward declarations for builtintab[] */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009719static int breakcmd(int, char **) FAST_FUNC;
9720static int dotcmd(int, char **) FAST_FUNC;
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009721static int evalcmd(int, char **, int) FAST_FUNC;
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009722static int exitcmd(int, char **) FAST_FUNC;
9723static int exportcmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009724#if ENABLE_ASH_GETOPTS
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009725static int getoptscmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009726#endif
Denys Vlasenko2ec34962014-09-08 16:52:39 +02009727#if ENABLE_ASH_HELP
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009728static int helpcmd(int, char **) FAST_FUNC;
Denis Vlasenko52764022007-02-24 13:42:56 +00009729#endif
Flemming Madsend96ffda2013-04-07 18:47:24 +02009730#if MAX_HISTORY
9731static int historycmd(int, char **) FAST_FUNC;
9732#endif
Denys Vlasenko0b883582016-12-23 16:49:07 +01009733#if ENABLE_FEATURE_SH_MATH
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009734static int letcmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009735#endif
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009736static int readcmd(int, char **) FAST_FUNC;
9737static int setcmd(int, char **) FAST_FUNC;
9738static int shiftcmd(int, char **) FAST_FUNC;
9739static int timescmd(int, char **) FAST_FUNC;
9740static int trapcmd(int, char **) FAST_FUNC;
9741static int umaskcmd(int, char **) FAST_FUNC;
9742static int unsetcmd(int, char **) FAST_FUNC;
9743static int ulimitcmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009744
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009745#define BUILTIN_NOSPEC "0"
9746#define BUILTIN_SPECIAL "1"
9747#define BUILTIN_REGULAR "2"
9748#define BUILTIN_SPEC_REG "3"
9749#define BUILTIN_ASSIGN "4"
9750#define BUILTIN_SPEC_ASSG "5"
9751#define BUILTIN_REG_ASSG "6"
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009752#define BUILTIN_SPEC_REG_ASSG "7"
9753
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009754/* Stubs for calling non-FAST_FUNC's */
Denys Vlasenko265062d2017-01-10 15:13:30 +01009755#if ENABLE_ASH_ECHO
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009756static int FAST_FUNC echocmd(int argc, char **argv) { return echo_main(argc, argv); }
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009757#endif
Denys Vlasenko265062d2017-01-10 15:13:30 +01009758#if ENABLE_ASH_PRINTF
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009759static int FAST_FUNC printfcmd(int argc, char **argv) { return printf_main(argc, argv); }
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009760#endif
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01009761#if ENABLE_ASH_TEST || BASH_TEST2
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009762static int FAST_FUNC testcmd(int argc, char **argv) { return test_main(argc, argv); }
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009763#endif
Denis Vlasenko468aea22008-04-01 14:47:57 +00009764
Denis Vlasenkof7d56652008-03-25 05:51:41 +00009765/* Keep these in proper order since it is searched via bsearch() */
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009766static const struct builtincmd builtintab[] = {
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009767 { BUILTIN_SPEC_REG "." , dotcmd },
9768 { BUILTIN_SPEC_REG ":" , truecmd },
Denys Vlasenko265062d2017-01-10 15:13:30 +01009769#if ENABLE_ASH_TEST
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009770 { BUILTIN_REGULAR "[" , testcmd },
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01009771#endif
9772#if BASH_TEST2
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009773 { BUILTIN_REGULAR "[[" , testcmd },
Denis Vlasenko80591b02008-03-25 07:49:43 +00009774#endif
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009775#if ENABLE_ASH_ALIAS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009776 { BUILTIN_REG_ASSG "alias" , aliascmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009777#endif
9778#if JOBS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009779 { BUILTIN_REGULAR "bg" , fg_bgcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009780#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009781 { BUILTIN_SPEC_REG "break" , breakcmd },
9782 { BUILTIN_REGULAR "cd" , cdcmd },
9783 { BUILTIN_NOSPEC "chdir" , cdcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009784#if ENABLE_ASH_CMDCMD
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009785 { BUILTIN_REGULAR "command" , commandcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009786#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009787 { BUILTIN_SPEC_REG "continue", breakcmd },
Denys Vlasenko265062d2017-01-10 15:13:30 +01009788#if ENABLE_ASH_ECHO
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009789 { BUILTIN_REGULAR "echo" , echocmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009790#endif
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009791 { BUILTIN_SPEC_REG "eval" , NULL }, /*evalcmd() has a differing prototype*/
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009792 { BUILTIN_SPEC_REG "exec" , execcmd },
9793 { BUILTIN_SPEC_REG "exit" , exitcmd },
9794 { BUILTIN_SPEC_REG_ASSG "export" , exportcmd },
9795 { BUILTIN_REGULAR "false" , falsecmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009796#if JOBS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009797 { BUILTIN_REGULAR "fg" , fg_bgcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009798#endif
9799#if ENABLE_ASH_GETOPTS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009800 { BUILTIN_REGULAR "getopts" , getoptscmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009801#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009802 { BUILTIN_NOSPEC "hash" , hashcmd },
Denys Vlasenko2ec34962014-09-08 16:52:39 +02009803#if ENABLE_ASH_HELP
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009804 { BUILTIN_NOSPEC "help" , helpcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009805#endif
Flemming Madsend96ffda2013-04-07 18:47:24 +02009806#if MAX_HISTORY
9807 { BUILTIN_NOSPEC "history" , historycmd },
9808#endif
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009809#if JOBS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009810 { BUILTIN_REGULAR "jobs" , jobscmd },
9811 { BUILTIN_REGULAR "kill" , killcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009812#endif
Denys Vlasenko0b883582016-12-23 16:49:07 +01009813#if ENABLE_FEATURE_SH_MATH
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009814 { BUILTIN_NOSPEC "let" , letcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009815#endif
Denys Vlasenko85241c72017-07-26 20:00:08 +02009816 { BUILTIN_SPEC_REG_ASSG "local" , localcmd },
Denys Vlasenko265062d2017-01-10 15:13:30 +01009817#if ENABLE_ASH_PRINTF
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009818 { BUILTIN_REGULAR "printf" , printfcmd },
Denis Vlasenkocd2663f2008-06-01 22:36:39 +00009819#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009820 { BUILTIN_NOSPEC "pwd" , pwdcmd },
9821 { BUILTIN_REGULAR "read" , readcmd },
9822 { BUILTIN_SPEC_REG_ASSG "readonly", exportcmd },
9823 { BUILTIN_SPEC_REG "return" , returncmd },
9824 { BUILTIN_SPEC_REG "set" , setcmd },
9825 { BUILTIN_SPEC_REG "shift" , shiftcmd },
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01009826#if BASH_SOURCE
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009827 { BUILTIN_SPEC_REG "source" , dotcmd },
Denys Vlasenko82731b42010-05-17 17:49:52 +02009828#endif
Denys Vlasenko265062d2017-01-10 15:13:30 +01009829#if ENABLE_ASH_TEST
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009830 { BUILTIN_REGULAR "test" , testcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009831#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009832 { BUILTIN_SPEC_REG "times" , timescmd },
9833 { BUILTIN_SPEC_REG "trap" , trapcmd },
9834 { BUILTIN_REGULAR "true" , truecmd },
9835 { BUILTIN_NOSPEC "type" , typecmd },
9836 { BUILTIN_NOSPEC "ulimit" , ulimitcmd },
9837 { BUILTIN_REGULAR "umask" , umaskcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009838#if ENABLE_ASH_ALIAS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009839 { BUILTIN_REGULAR "unalias" , unaliascmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009840#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009841 { BUILTIN_SPEC_REG "unset" , unsetcmd },
9842 { BUILTIN_REGULAR "wait" , waitcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009843};
9844
Denis Vlasenko80591b02008-03-25 07:49:43 +00009845/* Should match the above table! */
9846#define COMMANDCMD (builtintab + \
Denys Vlasenko928e2a72016-09-29 00:30:31 +02009847 /* . : */ 2 + \
Denys Vlasenko265062d2017-01-10 15:13:30 +01009848 /* [ */ 1 * ENABLE_ASH_TEST + \
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01009849 /* [[ */ 1 * BASH_TEST2 + \
Denys Vlasenko928e2a72016-09-29 00:30:31 +02009850 /* alias */ 1 * ENABLE_ASH_ALIAS + \
9851 /* bg */ 1 * ENABLE_ASH_JOB_CONTROL + \
9852 /* break cd cddir */ 3)
9853#define EVALCMD (COMMANDCMD + \
9854 /* command */ 1 * ENABLE_ASH_CMDCMD + \
9855 /* continue */ 1 + \
Denys Vlasenko265062d2017-01-10 15:13:30 +01009856 /* echo */ 1 * ENABLE_ASH_ECHO + \
Denys Vlasenko928e2a72016-09-29 00:30:31 +02009857 0)
9858#define EXECCMD (EVALCMD + \
9859 /* eval */ 1)
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009860
9861/*
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009862 * Search the table of builtin commands.
9863 */
Denys Vlasenko888527c2016-10-02 16:54:17 +02009864static int
9865pstrcmp1(const void *a, const void *b)
9866{
9867 return strcmp((char*)a, *(char**)b + 1);
9868}
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009869static struct builtincmd *
9870find_builtin(const char *name)
9871{
9872 struct builtincmd *bp;
9873
9874 bp = bsearch(
Denis Vlasenko80b8b392007-06-25 10:55:35 +00009875 name, builtintab, ARRAY_SIZE(builtintab), sizeof(builtintab[0]),
Denys Vlasenko888527c2016-10-02 16:54:17 +02009876 pstrcmp1
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009877 );
9878 return bp;
9879}
9880
9881/*
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009882 * Execute a simple command.
9883 */
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009884static int
9885isassignment(const char *p)
Paul Foxc3850c82005-07-20 18:23:39 +00009886{
9887 const char *q = endofname(p);
9888 if (p == q)
9889 return 0;
9890 return *q == '=';
9891}
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009892static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009893bltincmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009894{
9895 /* Preserve exitstatus of a previous possible redirection
9896 * as POSIX mandates */
9897 return back_exitstatus;
9898}
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009899static int
Eric Andersenc470f442003-07-28 09:56:35 +00009900evalcommand(union node *cmd, int flags)
9901{
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00009902 static const struct builtincmd null_bltin = {
9903 "\0\0", bltincmd /* why three NULs? */
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009904 };
Denys Vlasenko484fc202017-07-26 19:55:31 +02009905 struct localvar_list *localvar_stop;
Denys Vlasenko1c79aeb2017-07-29 22:51:52 +02009906 struct redirtab *redir_stop;
Eric Andersenc470f442003-07-28 09:56:35 +00009907 struct stackmark smark;
9908 union node *argp;
9909 struct arglist arglist;
9910 struct arglist varlist;
9911 char **argv;
9912 int argc;
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009913 const struct strlist *sp;
Eric Andersenc470f442003-07-28 09:56:35 +00009914 struct cmdentry cmdentry;
9915 struct job *jp;
9916 char *lastarg;
9917 const char *path;
9918 int spclbltin;
Eric Andersenc470f442003-07-28 09:56:35 +00009919 int status;
9920 char **nargv;
Denis Vlasenko34c73c42008-08-16 11:48:02 +00009921 smallint cmd_is_exec;
Eric Andersenc470f442003-07-28 09:56:35 +00009922
Denys Vlasenko675d24a2018-01-27 22:02:05 +01009923 errlinno = lineno = cmd->ncmd.linno;
9924 if (funcline)
9925 lineno -= funcline - 1;
9926
Eric Andersenc470f442003-07-28 09:56:35 +00009927 /* First expand the arguments. */
9928 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
9929 setstackmark(&smark);
Denys Vlasenko484fc202017-07-26 19:55:31 +02009930 localvar_stop = pushlocalvars();
Eric Andersenc470f442003-07-28 09:56:35 +00009931 back_exitstatus = 0;
9932
9933 cmdentry.cmdtype = CMDBUILTIN;
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00009934 cmdentry.u.cmd = &null_bltin;
Eric Andersenc470f442003-07-28 09:56:35 +00009935 varlist.lastp = &varlist.list;
9936 *varlist.lastp = NULL;
9937 arglist.lastp = &arglist.list;
9938 *arglist.lastp = NULL;
9939
9940 argc = 0;
Denis Vlasenkob012b102007-02-19 22:43:01 +00009941 if (cmd->ncmd.args) {
Denys Vlasenkod07a15b2017-07-30 16:51:05 +02009942 struct builtincmd *bcmd;
9943 smallint pseudovarflag;
9944
Paul Foxc3850c82005-07-20 18:23:39 +00009945 bcmd = find_builtin(cmd->ncmd.args->narg.text);
9946 pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd);
Paul Foxc3850c82005-07-20 18:23:39 +00009947
Denys Vlasenkod07a15b2017-07-30 16:51:05 +02009948 for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) {
9949 struct strlist **spp;
Eric Andersenc470f442003-07-28 09:56:35 +00009950
Denys Vlasenkod07a15b2017-07-30 16:51:05 +02009951 spp = arglist.lastp;
9952 if (pseudovarflag && isassignment(argp->narg.text))
9953 expandarg(argp, &arglist, EXP_VARTILDE);
9954 else
9955 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
Paul Foxc3850c82005-07-20 18:23:39 +00009956
Denys Vlasenkod07a15b2017-07-30 16:51:05 +02009957 for (sp = *spp; sp; sp = sp->next)
9958 argc++;
9959 }
Eric Andersenc470f442003-07-28 09:56:35 +00009960 }
9961
Denys Vlasenko65a8b852016-10-26 22:29:11 +02009962 /* Reserve one extra spot at the front for shellexec. */
9963 nargv = stalloc(sizeof(char *) * (argc + 2));
9964 argv = ++nargv;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009965 for (sp = arglist.list; sp; sp = sp->next) {
Eric Andersenc470f442003-07-28 09:56:35 +00009966 TRACE(("evalcommand arg: %s\n", sp->text));
9967 *nargv++ = sp->text;
9968 }
9969 *nargv = NULL;
9970
9971 lastarg = NULL;
Denys Vlasenko675d24a2018-01-27 22:02:05 +01009972 if (iflag && funcline == 0 && argc > 0)
Eric Andersenc470f442003-07-28 09:56:35 +00009973 lastarg = nargv[-1];
9974
9975 expredir(cmd->ncmd.redirect);
Denys Vlasenko1c79aeb2017-07-29 22:51:52 +02009976 redir_stop = pushredir(cmd->ncmd.redirect);
Denys Vlasenkod07a15b2017-07-30 16:51:05 +02009977 preverrout_fd = 2;
Denys Vlasenkof8cdc7a2017-08-04 15:24:49 +02009978 if (BASH_XTRACEFD && xflag) {
9979 /* NB: bash closes fd == $BASH_XTRACEFD when it is changed.
9980 * we do not emulate this. We only use its value.
9981 */
9982 const char *xtracefd = lookupvar("BASH_XTRACEFD");
9983 if (xtracefd && is_number(xtracefd))
9984 preverrout_fd = atoi(xtracefd);
9985
9986 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009987 status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH | REDIR_SAVEFD2);
Eric Andersenc470f442003-07-28 09:56:35 +00009988
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009989 path = vpath.var_text;
Eric Andersenc470f442003-07-28 09:56:35 +00009990 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
9991 struct strlist **spp;
9992 char *p;
9993
9994 spp = varlist.lastp;
9995 expandarg(argp, &varlist, EXP_VARTILDE);
9996
Denys Vlasenko981a0562017-07-26 19:53:11 +02009997 mklocal((*spp)->text);
9998
Eric Andersenc470f442003-07-28 09:56:35 +00009999 /*
10000 * Modify the command lookup path, if a PATH= assignment
10001 * is present
10002 */
10003 p = (*spp)->text;
Denys Vlasenko8837c5d2010-06-02 12:56:18 +020010004 if (varcmp(p, path) == 0)
Eric Andersenc470f442003-07-28 09:56:35 +000010005 path = p;
10006 }
10007
10008 /* Print the command if xflag is set. */
10009 if (xflag) {
Denys Vlasenko42ba7572017-07-21 13:20:14 +020010010 const char *pfx = "";
Eric Andersenc470f442003-07-28 09:56:35 +000010011
Denys Vlasenko46999802017-07-29 21:12:29 +020010012 fdprintf(preverrout_fd, "%s", expandstr(ps4val(), DQSYNTAX));
Denys Vlasenko42ba7572017-07-21 13:20:14 +020010013
Glenn L McGrath7b8765c2003-08-29 07:29:30 +000010014 sp = varlist.list;
Denys Vlasenko42ba7572017-07-21 13:20:14 +020010015 while (sp) {
10016 char *varval = sp->text;
10017 char *eq = strchrnul(varval, '=');
10018 if (*eq)
10019 eq++;
10020 fdprintf(preverrout_fd, "%s%.*s%s",
10021 pfx,
10022 (int)(eq - varval), varval,
10023 maybe_single_quote(eq)
10024 );
10025 sp = sp->next;
10026 pfx = " ";
10027 }
10028
10029 sp = arglist.list;
10030 while (sp) {
10031 fdprintf(preverrout_fd, "%s%s",
10032 pfx,
10033 /* always quote if matches reserved word: */
10034 findkwd(sp->text)
10035 ? single_quote(sp->text)
10036 : maybe_single_quote(sp->text)
10037 );
10038 sp = sp->next;
10039 pfx = " ";
Glenn L McGrath7b8765c2003-08-29 07:29:30 +000010040 }
Denis Vlasenko0e6f6612008-02-15 15:02:15 +000010041 safe_write(preverrout_fd, "\n", 1);
Eric Andersenc470f442003-07-28 09:56:35 +000010042 }
10043
10044 cmd_is_exec = 0;
10045 spclbltin = -1;
10046
10047 /* Now locate the command. */
10048 if (argc) {
Eric Andersenc470f442003-07-28 09:56:35 +000010049 int cmd_flag = DO_ERR;
Denys Vlasenko0b4980c2012-09-25 12:49:29 +020010050#if ENABLE_ASH_CMDCMD
10051 const char *oldpath = path + 5;
10052#endif
Eric Andersenc470f442003-07-28 09:56:35 +000010053 path += 5;
Eric Andersenc470f442003-07-28 09:56:35 +000010054 for (;;) {
10055 find_command(argv[0], &cmdentry, cmd_flag, path);
10056 if (cmdentry.cmdtype == CMDUNKNOWN) {
Denys Vlasenko8131eea2009-11-02 14:19:51 +010010057 flush_stdout_stderr();
Denis Vlasenko6514c5e2008-07-24 13:41:37 +000010058 status = 127;
Eric Andersenc470f442003-07-28 09:56:35 +000010059 goto bail;
10060 }
10061
10062 /* implement bltin and command here */
10063 if (cmdentry.cmdtype != CMDBUILTIN)
10064 break;
10065 if (spclbltin < 0)
10066 spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd);
10067 if (cmdentry.u.cmd == EXECCMD)
Denis Vlasenko34c73c42008-08-16 11:48:02 +000010068 cmd_is_exec = 1;
Denis Vlasenko131ae172007-02-18 13:00:19 +000010069#if ENABLE_ASH_CMDCMD
Eric Andersenc470f442003-07-28 09:56:35 +000010070 if (cmdentry.u.cmd == COMMANDCMD) {
Eric Andersenc470f442003-07-28 09:56:35 +000010071 path = oldpath;
10072 nargv = parse_command_args(argv, &path);
10073 if (!nargv)
10074 break;
Denys Vlasenkocac4d002016-10-01 03:02:25 +020010075 /* It's "command [-p] PROG ARGS" (that is, no -Vv).
10076 * nargv => "PROG". path is updated if -p.
10077 */
Eric Andersenc470f442003-07-28 09:56:35 +000010078 argc -= nargv - argv;
10079 argv = nargv;
10080 cmd_flag |= DO_NOFUNC;
10081 } else
10082#endif
10083 break;
10084 }
10085 }
10086
10087 if (status) {
Ron Yorstonea7d2f62017-01-03 11:18:23 +010010088 bail:
10089 exitstatus = status;
10090
Eric Andersenc470f442003-07-28 09:56:35 +000010091 /* We have a redirection error. */
10092 if (spclbltin > 0)
Denis Vlasenkob012b102007-02-19 22:43:01 +000010093 raise_exception(EXERROR);
Ron Yorstonea7d2f62017-01-03 11:18:23 +010010094
Eric Andersenc470f442003-07-28 09:56:35 +000010095 goto out;
10096 }
10097
10098 /* Execute the command. */
10099 switch (cmdentry.cmdtype) {
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +020010100 default: {
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +000010101
Denys Vlasenko1750d3a2018-01-15 00:41:04 +010010102#if ENABLE_FEATURE_SH_STANDALONE \
10103 && ENABLE_FEATURE_SH_NOFORK \
10104 && NUM_APPLETS > 1
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +020010105/* (1) BUG: if variables are set, we need to fork, or save/restore them
10106 * around run_nofork_applet() call.
10107 * (2) Should this check also be done in forkshell()?
10108 * (perhaps it should, so that "VAR=VAL nofork" at least avoids exec...)
10109 */
Denis Vlasenko7465dbc2008-04-13 02:25:53 +000010110 /* find_command() encodes applet_no as (-2 - applet_no) */
10111 int applet_no = (- cmdentry.u.index - 2);
Denis Vlasenko9bc80d72008-04-12 20:07:53 +000010112 if (applet_no >= 0 && APPLET_IS_NOFORK(applet_no)) {
Denys Vlasenkoa5060b82017-11-03 14:16:25 +010010113 char **sv_environ;
10114
10115 INT_OFF;
10116 sv_environ = environ;
10117 environ = listvars(VEXPORT, VUNSET, varlist.list, /*end:*/ NULL);
Denys Vlasenkod329e342017-08-04 14:50:03 +020010118 /*
10119 * Run <applet>_main().
10120 * Signals (^C) can't interrupt here.
10121 * Otherwise we can mangle stdio or malloc internal state.
10122 * This makes applets which can run for a long time
10123 * and/or wait for user input ineligible for NOFORK:
10124 * for example, "yes" or "rm" (rm -i waits for input).
10125 */
Ron Yorston5ccb0e92016-10-20 12:24:02 +010010126 status = run_nofork_applet(applet_no, argv);
Denys Vlasenkoa5060b82017-11-03 14:16:25 +010010127 environ = sv_environ;
Denys Vlasenkod329e342017-08-04 14:50:03 +020010128 /*
10129 * Try enabling NOFORK for "yes" applet.
10130 * ^C _will_ stop it (write returns EINTR),
10131 * but this causes stdout FILE to be stuck
10132 * and needing clearerr(). What if other applets
10133 * also can get EINTRs? Do we need to switch
10134 * our signals to SA_RESTART?
10135 */
10136 /*clearerr(stdout);*/
10137 INT_ON;
Denis Vlasenko9bc80d72008-04-12 20:07:53 +000010138 break;
10139 }
Denis Vlasenko9bc80d72008-04-12 20:07:53 +000010140#endif
Denys Vlasenkocfd392b2017-08-03 19:56:29 +020010141 /* Can we avoid forking? For example, very last command
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +020010142 * in a script or a subshell does not need forking,
10143 * we can just exec it.
10144 */
Denys Vlasenko238bf182010-05-18 15:49:07 +020010145 if (!(flags & EV_EXIT) || may_have_traps) {
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +020010146 /* No, forking off a child is necessary */
Denis Vlasenkob012b102007-02-19 22:43:01 +000010147 INT_OFF;
Denys Vlasenko098b7132017-01-11 19:59:03 +010010148 get_tty_state();
Denis Vlasenko68404f12008-03-17 09:00:54 +000010149 jp = makejob(/*cmd,*/ 1);
Eric Andersenc470f442003-07-28 09:56:35 +000010150 if (forkshell(jp, cmd, FORK_FG) != 0) {
Denys Vlasenko238bf182010-05-18 15:49:07 +020010151 /* parent */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020010152 status = waitforjob(jp);
Denis Vlasenkob012b102007-02-19 22:43:01 +000010153 INT_ON;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020010154 TRACE(("forked child exited with %d\n", status));
Eric Andersenc470f442003-07-28 09:56:35 +000010155 break;
10156 }
Denys Vlasenko238bf182010-05-18 15:49:07 +020010157 /* child */
Denis Vlasenkob012b102007-02-19 22:43:01 +000010158 FORCE_INT_ON;
Denys Vlasenkoc7f95d22010-05-18 15:52:23 +020010159 /* fall through to exec'ing external program */
Eric Andersenc470f442003-07-28 09:56:35 +000010160 }
10161 listsetvar(varlist.list, VEXPORT|VSTACK);
Denys Vlasenkoe139ae32017-04-12 21:02:33 +020010162 shellexec(argv[0], argv, path, cmdentry.u.index);
Eric Andersenc470f442003-07-28 09:56:35 +000010163 /* NOTREACHED */
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +020010164 } /* default */
Eric Andersenc470f442003-07-28 09:56:35 +000010165 case CMDBUILTIN:
Denys Vlasenko85241c72017-07-26 20:00:08 +020010166 if (spclbltin > 0 || argc == 0) {
10167 poplocalvars(1);
10168 if (cmd_is_exec && argc > 1)
10169 listsetvar(varlist.list, VEXPORT);
10170 }
Denys Vlasenko981a0562017-07-26 19:53:11 +020010171
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +000010172 /* Tight loop with builtins only:
10173 * "while kill -0 $child; do true; done"
10174 * will never exit even if $child died, unless we do this
10175 * to reap the zombie and make kill detect that it's gone: */
10176 dowait(DOWAIT_NONBLOCK, NULL);
10177
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020010178 if (evalbltin(cmdentry.u.cmd, argc, argv, flags)) {
Denys Vlasenkoc0663c72016-10-27 21:09:01 +020010179 if (exception_type == EXERROR && spclbltin <= 0) {
10180 FORCE_INT_ON;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020010181 goto readstatus;
Eric Andersenc470f442003-07-28 09:56:35 +000010182 }
Denys Vlasenkoc0663c72016-10-27 21:09:01 +020010183 raise:
10184 longjmp(exception_handler->loc, 1);
Eric Andersenc470f442003-07-28 09:56:35 +000010185 }
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020010186 goto readstatus;
Eric Andersenc470f442003-07-28 09:56:35 +000010187
10188 case CMDFUNCTION:
Denys Vlasenko981a0562017-07-26 19:53:11 +020010189 poplocalvars(1);
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +000010190 /* See above for the rationale */
10191 dowait(DOWAIT_NONBLOCK, NULL);
Eric Andersenc470f442003-07-28 09:56:35 +000010192 if (evalfun(cmdentry.u.func, argc, argv, flags))
10193 goto raise;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020010194 readstatus:
10195 status = exitstatus;
Eric Andersenc470f442003-07-28 09:56:35 +000010196 break;
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +020010197 } /* switch */
Eric Andersenc470f442003-07-28 09:56:35 +000010198
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010199 out:
Denys Vlasenkoeaf94362016-10-25 21:46:03 +020010200 if (cmd->ncmd.redirect)
Denys Vlasenko035486c2017-07-31 04:09:19 +020010201 popredir(/*drop:*/ cmd_is_exec);
Denys Vlasenko1c79aeb2017-07-29 22:51:52 +020010202 unwindredir(redir_stop);
Denys Vlasenko484fc202017-07-26 19:55:31 +020010203 unwindlocalvars(localvar_stop);
Denis Vlasenko6514c5e2008-07-24 13:41:37 +000010204 if (lastarg) {
Eric Andersenc470f442003-07-28 09:56:35 +000010205 /* dsl: I think this is intended to be used to support
10206 * '_' in 'vi' command mode during line editing...
10207 * However I implemented that within libedit itself.
10208 */
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020010209 setvar0("_", lastarg);
Denis Vlasenko6514c5e2008-07-24 13:41:37 +000010210 }
Eric Andersenc470f442003-07-28 09:56:35 +000010211 popstackmark(&smark);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020010212
10213 return status;
Eric Andersenc470f442003-07-28 09:56:35 +000010214}
10215
10216static int
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020010217evalbltin(const struct builtincmd *cmd, int argc, char **argv, int flags)
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010218{
Eric Andersenc470f442003-07-28 09:56:35 +000010219 char *volatile savecmdname;
10220 struct jmploc *volatile savehandler;
10221 struct jmploc jmploc;
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020010222 int status;
Eric Andersenc470f442003-07-28 09:56:35 +000010223 int i;
10224
10225 savecmdname = commandname;
Denys Vlasenkoa2d121c2016-09-30 11:30:11 +020010226 savehandler = exception_handler;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010227 i = setjmp(jmploc.loc);
10228 if (i)
Eric Andersenc470f442003-07-28 09:56:35 +000010229 goto cmddone;
Denis Vlasenko2da584f2007-02-19 22:44:05 +000010230 exception_handler = &jmploc;
Eric Andersenc470f442003-07-28 09:56:35 +000010231 commandname = argv[0];
10232 argptr = argv + 1;
10233 optptr = NULL; /* initialize nextopt */
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020010234 if (cmd == EVALCMD)
10235 status = evalcmd(argc, argv, flags);
10236 else
10237 status = (*cmd->builtin)(argc, argv);
Denis Vlasenkob012b102007-02-19 22:43:01 +000010238 flush_stdout_stderr();
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020010239 status |= ferror(stdout);
10240 exitstatus = status;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010241 cmddone:
Rob Landleyf296f0b2006-07-06 01:09:21 +000010242 clearerr(stdout);
Eric Andersenc470f442003-07-28 09:56:35 +000010243 commandname = savecmdname;
Denis Vlasenko2da584f2007-02-19 22:44:05 +000010244 exception_handler = savehandler;
Eric Andersenc470f442003-07-28 09:56:35 +000010245
10246 return i;
10247}
10248
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010249static int
10250goodname(const char *p)
Glenn L McGrath16e45d72004-02-04 08:24:39 +000010251{
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +020010252 return endofname(p)[0] == '\0';
Glenn L McGrath16e45d72004-02-04 08:24:39 +000010253}
10254
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010255
Glenn L McGrath50812ff2002-08-23 13:14:48 +000010256/*
10257 * Search for a command. This is called before we fork so that the
10258 * location of the command will be available in the parent as well as
Glenn L McGrath16e45d72004-02-04 08:24:39 +000010259 * the child. The check for "goodname" is an overly conservative
10260 * check that the name will not be subject to expansion.
Glenn L McGrath50812ff2002-08-23 13:14:48 +000010261 */
Eric Andersenc470f442003-07-28 09:56:35 +000010262static void
10263prehash(union node *n)
Glenn L McGrath50812ff2002-08-23 13:14:48 +000010264{
10265 struct cmdentry entry;
10266
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000010267 if (n->type == NCMD && n->ncmd.args && goodname(n->ncmd.args->narg.text))
10268 find_command(n->ncmd.args->narg.text, &entry, 0, pathval());
Glenn L McGrath50812ff2002-08-23 13:14:48 +000010269}
10270
Eric Andersencb57d552001-06-28 07:25:16 +000010271
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000010272/* ============ Builtin commands
10273 *
10274 * Builtin commands whose functions are closely tied to evaluation
10275 * are implemented here.
Eric Andersencb57d552001-06-28 07:25:16 +000010276 */
10277
10278/*
Eric Andersencb57d552001-06-28 07:25:16 +000010279 * Handle break and continue commands. Break, continue, and return are
10280 * all handled by setting the evalskip flag. The evaluation routines
10281 * above all check this flag, and if it is set they start skipping
10282 * commands rather than executing them. The variable skipcount is
10283 * the number of loops to break/continue, or the number of function
10284 * levels to return. (The latter is always 1.) It should probably
10285 * be an error to break out of more loops than exist, but it isn't
10286 * in the standard shell so we don't make it one here.
10287 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010288static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010289breakcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000010290{
Denis Vlasenko68404f12008-03-17 09:00:54 +000010291 int n = argv[1] ? number(argv[1]) : 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010292
Aaron Lehmann2aef3a62001-12-31 06:03:12 +000010293 if (n <= 0)
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +020010294 ash_msg_and_raise_error(msg_illnum, argv[1]);
Eric Andersencb57d552001-06-28 07:25:16 +000010295 if (n > loopnest)
10296 n = loopnest;
10297 if (n > 0) {
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000010298 evalskip = (**argv == 'c') ? SKIPCONT : SKIPBREAK;
Eric Andersencb57d552001-06-28 07:25:16 +000010299 skipcount = n;
10300 }
10301 return 0;
10302}
10303
Eric Andersenc470f442003-07-28 09:56:35 +000010304
Denys Vlasenko70392332016-10-27 02:31:55 +020010305/*
Eric Andersen90898442003-08-06 11:20:52 +000010306 * This implements the input routines used by the parser.
Eric Andersencb57d552001-06-28 07:25:16 +000010307 */
Denis Vlasenko99eb8502007-02-23 21:09:49 +000010308
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010309enum {
10310 INPUT_PUSH_FILE = 1,
10311 INPUT_NOFILE_OK = 2,
10312};
Eric Andersencb57d552001-06-28 07:25:16 +000010313
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010314static smallint checkkwd;
Denis Vlasenko99eb8502007-02-23 21:09:49 +000010315/* values of checkkwd variable */
10316#define CHKALIAS 0x1
10317#define CHKKWD 0x2
10318#define CHKNL 0x4
Denys Vlasenkoa7328982017-07-29 19:57:28 +020010319#define CHKEOFMARK 0x8
Denis Vlasenko99eb8502007-02-23 21:09:49 +000010320
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010321/*
10322 * Push a string back onto the input at this current parsefile level.
10323 * We handle aliases this way.
10324 */
10325#if !ENABLE_ASH_ALIAS
10326#define pushstring(s, ap) pushstring(s)
10327#endif
10328static void
10329pushstring(char *s, struct alias *ap)
10330{
10331 struct strpush *sp;
10332 int len;
10333
10334 len = strlen(s);
10335 INT_OFF;
10336 if (g_parsefile->strpush) {
10337 sp = ckzalloc(sizeof(*sp));
10338 sp->prev = g_parsefile->strpush;
10339 } else {
10340 sp = &(g_parsefile->basestrpush);
10341 }
10342 g_parsefile->strpush = sp;
10343 sp->prev_string = g_parsefile->next_to_pgetc;
10344 sp->prev_left_in_line = g_parsefile->left_in_line;
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010345 sp->unget = g_parsefile->unget;
10346 memcpy(sp->lastc, g_parsefile->lastc, sizeof(sp->lastc));
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010347#if ENABLE_ASH_ALIAS
10348 sp->ap = ap;
10349 if (ap) {
10350 ap->flag |= ALIASINUSE;
10351 sp->string = s;
10352 }
10353#endif
10354 g_parsefile->next_to_pgetc = s;
10355 g_parsefile->left_in_line = len;
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010356 g_parsefile->unget = 0;
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010357 INT_ON;
10358}
10359
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010360static void
10361popstring(void)
Eric Andersenc470f442003-07-28 09:56:35 +000010362{
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010363 struct strpush *sp = g_parsefile->strpush;
Eric Andersenc470f442003-07-28 09:56:35 +000010364
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010365 INT_OFF;
Denis Vlasenko131ae172007-02-18 13:00:19 +000010366#if ENABLE_ASH_ALIAS
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010367 if (sp->ap) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010368 if (g_parsefile->next_to_pgetc[-1] == ' '
10369 || g_parsefile->next_to_pgetc[-1] == '\t'
10370 ) {
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010371 checkkwd |= CHKALIAS;
Glenn L McGrath28939ad2004-07-21 10:20:19 +000010372 }
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010373 if (sp->string != sp->ap->val) {
10374 free(sp->string);
10375 }
10376 sp->ap->flag &= ~ALIASINUSE;
10377 if (sp->ap->flag & ALIASDEAD) {
10378 unalias(sp->ap->name);
10379 }
Glenn L McGrath28939ad2004-07-21 10:20:19 +000010380 }
Denis Vlasenko8e1c7152007-01-22 07:21:38 +000010381#endif
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010382 g_parsefile->next_to_pgetc = sp->prev_string;
10383 g_parsefile->left_in_line = sp->prev_left_in_line;
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010384 g_parsefile->unget = sp->unget;
10385 memcpy(g_parsefile->lastc, sp->lastc, sizeof(sp->lastc));
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010386 g_parsefile->strpush = sp->prev;
10387 if (sp != &(g_parsefile->basestrpush))
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010388 free(sp);
10389 INT_ON;
10390}
Denis Vlasenko8e1c7152007-01-22 07:21:38 +000010391
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010392static int
10393preadfd(void)
Eric Andersencb57d552001-06-28 07:25:16 +000010394{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010395 int nr;
Denis Vlasenko6a0ad252008-07-25 13:34:05 +000010396 char *buf = g_parsefile->buf;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010397
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010398 g_parsefile->next_to_pgetc = buf;
Denis Vlasenko38f63192007-01-22 09:03:07 +000010399#if ENABLE_FEATURE_EDITING
Denis Vlasenko85c24712008-03-17 09:04:04 +000010400 retry:
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010401 if (!iflag || g_parsefile->pf_fd != STDIN_FILENO)
Ron Yorston61d6ae22015-04-19 10:50:25 +010010402 nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1);
Eric Andersenc470f442003-07-28 09:56:35 +000010403 else {
Denys Vlasenko66c5b122011-02-08 05:07:02 +010010404# if ENABLE_ASH_IDLE_TIMEOUT
Denys Vlasenko84ea60e2017-08-02 17:27:28 +020010405 int timeout = -1;
Denys Vlasenko66c5b122011-02-08 05:07:02 +010010406 if (iflag) {
10407 const char *tmout_var = lookupvar("TMOUT");
10408 if (tmout_var) {
10409 timeout = atoi(tmout_var) * 1000;
10410 if (timeout <= 0)
10411 timeout = -1;
10412 }
10413 }
Denys Vlasenko84ea60e2017-08-02 17:27:28 +020010414 line_input_state->timeout = timeout;
Denys Vlasenko66c5b122011-02-08 05:07:02 +010010415# endif
Denys Vlasenko8c52f802011-02-04 17:36:21 +010010416# if ENABLE_FEATURE_TAB_COMPLETION
Denis Vlasenko8e1c7152007-01-22 07:21:38 +000010417 line_input_state->path_lookup = pathval();
Denys Vlasenko8c52f802011-02-04 17:36:21 +010010418# endif
Denys Vlasenkoe9ab07c2014-08-13 18:00:08 +020010419 reinit_unicode_for_ash();
Denys Vlasenko84ea60e2017-08-02 17:27:28 +020010420 nr = read_line_input(line_input_state, cmdedit_prompt, buf, IBUFSIZ);
Denis Vlasenko8e1c7152007-01-22 07:21:38 +000010421 if (nr == 0) {
Denys Vlasenko4b89d512016-11-25 03:41:03 +010010422 /* ^C pressed, "convert" to SIGINT */
10423 write(STDOUT_FILENO, "^C", 2);
Denis Vlasenko8e1c7152007-01-22 07:21:38 +000010424 if (trap[SIGINT]) {
Glenn L McGrath16e45d72004-02-04 08:24:39 +000010425 buf[0] = '\n';
Denis Vlasenko8e1c7152007-01-22 07:21:38 +000010426 buf[1] = '\0';
Glenn L McGrath16e45d72004-02-04 08:24:39 +000010427 raise(SIGINT);
10428 return 1;
10429 }
Denys Vlasenko8660aeb2016-11-24 17:44:02 +010010430 exitstatus = 128 + SIGINT;
Denys Vlasenko4b89d512016-11-25 03:41:03 +010010431 bb_putchar('\n');
Eric Andersenc470f442003-07-28 09:56:35 +000010432 goto retry;
10433 }
Denys Vlasenko66c5b122011-02-08 05:07:02 +010010434 if (nr < 0) {
10435 if (errno == 0) {
10436 /* Ctrl+D pressed */
10437 nr = 0;
10438 }
10439# if ENABLE_ASH_IDLE_TIMEOUT
10440 else if (errno == EAGAIN && timeout > 0) {
Denys Vlasenkod60752f2015-10-07 22:42:45 +020010441 puts("\007timed out waiting for input: auto-logout");
Denys Vlasenko66c5b122011-02-08 05:07:02 +010010442 exitshell();
10443 }
10444# endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010445 }
Eric Andersencb57d552001-06-28 07:25:16 +000010446 }
10447#else
Ron Yorston61d6ae22015-04-19 10:50:25 +010010448 nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1);
Eric Andersencb57d552001-06-28 07:25:16 +000010449#endif
10450
Denys Vlasenko80c5b682011-05-08 21:21:10 +020010451#if 0 /* disabled: nonblock_immune_read() handles this problem */
Eric Andersencb57d552001-06-28 07:25:16 +000010452 if (nr < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +000010453 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
Denis Vlasenkod37f2222007-08-19 13:42:08 +000010454 int flags = fcntl(0, F_GETFL);
Denis Vlasenko9cb220b2007-12-09 10:03:28 +000010455 if (flags >= 0 && (flags & O_NONBLOCK)) {
10456 flags &= ~O_NONBLOCK;
Eric Andersencb57d552001-06-28 07:25:16 +000010457 if (fcntl(0, F_SETFL, flags) >= 0) {
10458 out2str("sh: turning off NDELAY mode\n");
10459 goto retry;
10460 }
10461 }
10462 }
10463 }
Denis Vlasenkoe376d452008-02-20 22:23:24 +000010464#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010465 return nr;
10466}
10467
10468/*
10469 * Refill the input buffer and return the next input character:
10470 *
10471 * 1) If a string was pushed back on the input, pop it;
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010472 * 2) If an EOF was pushed back (g_parsefile->left_in_line < -BIGNUM)
10473 * or we are reading from a string so we can't refill the buffer,
10474 * return EOF.
Denys Vlasenko883cea42009-07-11 15:31:59 +020010475 * 3) If there is more stuff in this buffer, use it else call read to fill it.
Eric Andersencb57d552001-06-28 07:25:16 +000010476 * 4) Process input up to the next newline, deleting nul characters.
10477 */
Denis Vlasenko727752d2008-11-28 03:41:47 +000010478//#define pgetc_debug(...) bb_error_msg(__VA_ARGS__)
10479#define pgetc_debug(...) ((void)0)
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010480static int pgetc(void);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010481static int
Eric Andersenc470f442003-07-28 09:56:35 +000010482preadbuffer(void)
Eric Andersencb57d552001-06-28 07:25:16 +000010483{
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010484 char *q;
Eric Andersencb57d552001-06-28 07:25:16 +000010485 int more;
Eric Andersencb57d552001-06-28 07:25:16 +000010486
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010487 if (g_parsefile->strpush) {
Denis Vlasenko131ae172007-02-18 13:00:19 +000010488#if ENABLE_ASH_ALIAS
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010489 if (g_parsefile->left_in_line == -1
10490 && g_parsefile->strpush->ap
10491 && g_parsefile->next_to_pgetc[-1] != ' '
10492 && g_parsefile->next_to_pgetc[-1] != '\t'
Denis Vlasenko16898402008-11-25 01:34:52 +000010493 ) {
Denis Vlasenko727752d2008-11-28 03:41:47 +000010494 pgetc_debug("preadbuffer PEOA");
Eric Andersencb57d552001-06-28 07:25:16 +000010495 return PEOA;
10496 }
Eric Andersen2870d962001-07-02 17:27:21 +000010497#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010498 popstring();
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010499 return pgetc();
Eric Andersencb57d552001-06-28 07:25:16 +000010500 }
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010501 /* on both branches above g_parsefile->left_in_line < 0.
Denis Vlasenko727752d2008-11-28 03:41:47 +000010502 * "pgetc" needs refilling.
10503 */
10504
Denis Vlasenkoe27dafd2008-11-28 04:01:03 +000010505 /* -90 is our -BIGNUM. Below we use -99 to mark "EOF on read",
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010506 * pungetc() may increment it a few times.
Denis Vlasenkoe27dafd2008-11-28 04:01:03 +000010507 * Assuming it won't increment it to less than -90.
Denis Vlasenko727752d2008-11-28 03:41:47 +000010508 */
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010509 if (g_parsefile->left_in_line < -90 || g_parsefile->buf == NULL) {
Denis Vlasenko727752d2008-11-28 03:41:47 +000010510 pgetc_debug("preadbuffer PEOF1");
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010511 /* even in failure keep left_in_line and next_to_pgetc
10512 * in lock step, for correct multi-layer pungetc.
10513 * left_in_line was decremented before preadbuffer(),
10514 * must inc next_to_pgetc: */
10515 g_parsefile->next_to_pgetc++;
Eric Andersencb57d552001-06-28 07:25:16 +000010516 return PEOF;
Denis Vlasenko727752d2008-11-28 03:41:47 +000010517 }
Eric Andersencb57d552001-06-28 07:25:16 +000010518
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010519 more = g_parsefile->left_in_buffer;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010520 if (more <= 0) {
Denis Vlasenko727752d2008-11-28 03:41:47 +000010521 flush_stdout_stderr();
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010522 again:
10523 more = preadfd();
10524 if (more <= 0) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010525 /* don't try reading again */
10526 g_parsefile->left_in_line = -99;
Denis Vlasenko727752d2008-11-28 03:41:47 +000010527 pgetc_debug("preadbuffer PEOF2");
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010528 g_parsefile->next_to_pgetc++;
Eric Andersencb57d552001-06-28 07:25:16 +000010529 return PEOF;
10530 }
10531 }
10532
Denis Vlasenko727752d2008-11-28 03:41:47 +000010533 /* Find out where's the end of line.
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010534 * Set g_parsefile->left_in_line
10535 * and g_parsefile->left_in_buffer acordingly.
Denis Vlasenko727752d2008-11-28 03:41:47 +000010536 * NUL chars are deleted.
10537 */
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010538 q = g_parsefile->next_to_pgetc;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010539 for (;;) {
Denis Vlasenko727752d2008-11-28 03:41:47 +000010540 char c;
Eric Andersencb57d552001-06-28 07:25:16 +000010541
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010542 more--;
Eric Andersenc470f442003-07-28 09:56:35 +000010543
Denis Vlasenko727752d2008-11-28 03:41:47 +000010544 c = *q;
10545 if (c == '\0') {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010546 memmove(q, q + 1, more);
Denis Vlasenko727752d2008-11-28 03:41:47 +000010547 } else {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010548 q++;
10549 if (c == '\n') {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010550 g_parsefile->left_in_line = q - g_parsefile->next_to_pgetc - 1;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010551 break;
10552 }
Eric Andersencb57d552001-06-28 07:25:16 +000010553 }
10554
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010555 if (more <= 0) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010556 g_parsefile->left_in_line = q - g_parsefile->next_to_pgetc - 1;
10557 if (g_parsefile->left_in_line < 0)
Eric Andersencb57d552001-06-28 07:25:16 +000010558 goto again;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010559 break;
Eric Andersencb57d552001-06-28 07:25:16 +000010560 }
10561 }
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010562 g_parsefile->left_in_buffer = more;
Eric Andersencb57d552001-06-28 07:25:16 +000010563
Eric Andersencb57d552001-06-28 07:25:16 +000010564 if (vflag) {
Denis Vlasenko727752d2008-11-28 03:41:47 +000010565 char save = *q;
10566 *q = '\0';
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010567 out2str(g_parsefile->next_to_pgetc);
Denis Vlasenko727752d2008-11-28 03:41:47 +000010568 *q = save;
Eric Andersencb57d552001-06-28 07:25:16 +000010569 }
10570
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010571 pgetc_debug("preadbuffer at %d:%p'%s'",
10572 g_parsefile->left_in_line,
10573 g_parsefile->next_to_pgetc,
10574 g_parsefile->next_to_pgetc);
Denys Vlasenkocd716832009-11-28 22:14:02 +010010575 return (unsigned char)*g_parsefile->next_to_pgetc++;
Eric Andersencb57d552001-06-28 07:25:16 +000010576}
10577
Denys Vlasenkoce332a22016-10-02 23:47:34 +020010578static void
10579nlprompt(void)
10580{
10581 g_parsefile->linno++;
10582 setprompt_if(doprompt, 2);
10583}
10584static void
10585nlnoprompt(void)
10586{
10587 g_parsefile->linno++;
10588 needprompt = doprompt;
10589}
10590
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010591static int
10592pgetc(void)
10593{
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010594 int c;
10595
10596 pgetc_debug("pgetc at %d:%p'%s'",
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010597 g_parsefile->left_in_line,
10598 g_parsefile->next_to_pgetc,
10599 g_parsefile->next_to_pgetc);
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010600 if (g_parsefile->unget)
10601 return g_parsefile->lastc[--g_parsefile->unget];
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010602
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010603 if (--g_parsefile->left_in_line >= 0)
Denys Vlasenko2fe66b12016-12-12 17:39:12 +010010604 c = (unsigned char)*g_parsefile->next_to_pgetc++;
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010605 else
10606 c = preadbuffer();
10607
10608 g_parsefile->lastc[1] = g_parsefile->lastc[0];
10609 g_parsefile->lastc[0] = c;
10610
10611 return c;
10612}
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010613
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010614#if ENABLE_ASH_ALIAS
10615static int
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010010616pgetc_without_PEOA(void)
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010617{
10618 int c;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010619 do {
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010620 pgetc_debug("pgetc at %d:%p'%s'",
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010621 g_parsefile->left_in_line,
10622 g_parsefile->next_to_pgetc,
10623 g_parsefile->next_to_pgetc);
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010624 c = pgetc();
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010625 } while (c == PEOA);
10626 return c;
10627}
10628#else
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010010629# define pgetc_without_PEOA() pgetc()
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010630#endif
10631
10632/*
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010633 * Undo a call to pgetc. Only two characters may be pushed back.
Eric Andersenc470f442003-07-28 09:56:35 +000010634 * PEOF may be pushed back.
10635 */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010636static void
Eric Andersenc470f442003-07-28 09:56:35 +000010637pungetc(void)
10638{
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010639 g_parsefile->unget++;
Eric Andersencb57d552001-06-28 07:25:16 +000010640}
10641
Denys Vlasenko73c3e072016-09-29 17:17:04 +020010642/* This one eats backslash+newline */
10643static int
10644pgetc_eatbnl(void)
10645{
10646 int c;
10647
10648 while ((c = pgetc()) == '\\') {
10649 if (pgetc() != '\n') {
10650 pungetc();
10651 break;
10652 }
10653
Denys Vlasenkoce332a22016-10-02 23:47:34 +020010654 nlprompt();
Denys Vlasenko73c3e072016-09-29 17:17:04 +020010655 }
10656
10657 return c;
10658}
10659
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010660/*
10661 * To handle the "." command, a stack of input files is used. Pushfile
10662 * adds a new entry to the stack and popfile restores the previous level.
10663 */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010664static void
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010665pushfile(void)
Eric Andersenc470f442003-07-28 09:56:35 +000010666{
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010667 struct parsefile *pf;
10668
Denis Vlasenko597906c2008-02-20 16:38:54 +000010669 pf = ckzalloc(sizeof(*pf));
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010670 pf->prev = g_parsefile;
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010671 pf->pf_fd = -1;
Denis Vlasenko597906c2008-02-20 16:38:54 +000010672 /*pf->strpush = NULL; - ckzalloc did it */
10673 /*pf->basestrpush.prev = NULL;*/
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010674 /*pf->unget = 0;*/
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010675 g_parsefile = pf;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010676}
10677
10678static void
10679popfile(void)
10680{
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010681 struct parsefile *pf = g_parsefile;
Eric Andersenc470f442003-07-28 09:56:35 +000010682
Denys Vlasenko493b9ca2016-10-30 18:27:14 +010010683 if (pf == &basepf)
10684 return;
10685
Denis Vlasenkob012b102007-02-19 22:43:01 +000010686 INT_OFF;
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010687 if (pf->pf_fd >= 0)
10688 close(pf->pf_fd);
Denis Vlasenko60818682007-09-28 22:07:23 +000010689 free(pf->buf);
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010690 while (pf->strpush)
10691 popstring();
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010692 g_parsefile = pf->prev;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010693 free(pf);
Denis Vlasenkob012b102007-02-19 22:43:01 +000010694 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +000010695}
10696
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010697/*
10698 * Return to top level.
10699 */
10700static void
10701popallfiles(void)
10702{
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010703 while (g_parsefile != &basepf)
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010704 popfile();
10705}
10706
10707/*
10708 * Close the file(s) that the shell is reading commands from. Called
10709 * after a fork is done.
10710 */
10711static void
10712closescript(void)
10713{
10714 popallfiles();
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010715 if (g_parsefile->pf_fd > 0) {
10716 close(g_parsefile->pf_fd);
10717 g_parsefile->pf_fd = 0;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010718 }
10719}
10720
10721/*
10722 * Like setinputfile, but takes an open file descriptor. Call this with
10723 * interrupts off.
10724 */
10725static void
10726setinputfd(int fd, int push)
10727{
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010728 if (push) {
10729 pushfile();
Denis Vlasenko727752d2008-11-28 03:41:47 +000010730 g_parsefile->buf = NULL;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010731 }
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010732 g_parsefile->pf_fd = fd;
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010733 if (g_parsefile->buf == NULL)
10734 g_parsefile->buf = ckmalloc(IBUFSIZ);
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010735 g_parsefile->left_in_buffer = 0;
10736 g_parsefile->left_in_line = 0;
10737 g_parsefile->linno = 1;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010738}
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010739
Eric Andersenc470f442003-07-28 09:56:35 +000010740/*
10741 * Set the input to take input from a file. If push is set, push the
10742 * old input onto the stack first.
10743 */
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010744static int
10745setinputfile(const char *fname, int flags)
Eric Andersenc470f442003-07-28 09:56:35 +000010746{
10747 int fd;
Eric Andersenc470f442003-07-28 09:56:35 +000010748
Denis Vlasenkob012b102007-02-19 22:43:01 +000010749 INT_OFF;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010750 fd = open(fname, O_RDONLY);
10751 if (fd < 0) {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010752 if (flags & INPUT_NOFILE_OK)
10753 goto out;
Denys Vlasenkob7adf7a2016-10-25 17:00:13 +020010754 exitstatus = 127;
Johannes Schindelin20a63b22017-08-22 22:03:17 +020010755 ash_msg_and_raise_perror("can't open '%s'", fname);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010756 }
Denys Vlasenko64774602016-10-26 15:24:30 +020010757 if (fd < 10)
10758 fd = savefd(fd);
Denys Vlasenkoe19923f2016-10-26 15:38:44 +020010759 else
10760 close_on_exec_on(fd);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010761 setinputfd(fd, flags & INPUT_PUSH_FILE);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010762 out:
Denis Vlasenkob012b102007-02-19 22:43:01 +000010763 INT_ON;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010764 return fd;
Eric Andersenc470f442003-07-28 09:56:35 +000010765}
10766
Eric Andersencb57d552001-06-28 07:25:16 +000010767/*
10768 * Like setinputfile, but takes input from a string.
10769 */
Eric Andersenc470f442003-07-28 09:56:35 +000010770static void
10771setinputstring(char *string)
Eric Andersen62483552001-07-10 06:09:16 +000010772{
Denis Vlasenkob012b102007-02-19 22:43:01 +000010773 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +000010774 pushfile();
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010775 g_parsefile->next_to_pgetc = string;
10776 g_parsefile->left_in_line = strlen(string);
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010777 g_parsefile->buf = NULL;
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010778 g_parsefile->linno = 1;
Denis Vlasenkob012b102007-02-19 22:43:01 +000010779 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +000010780}
10781
10782
Denys Vlasenko70392332016-10-27 02:31:55 +020010783/*
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010784 * Routines to check for mail.
Eric Andersencb57d552001-06-28 07:25:16 +000010785 */
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010786
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010787#if ENABLE_ASH_MAIL
Eric Andersencb57d552001-06-28 07:25:16 +000010788
Denys Vlasenko23841622015-10-09 15:52:03 +020010789/* Hash of mtimes of mailboxes */
10790static unsigned mailtime_hash;
Eric Andersenc470f442003-07-28 09:56:35 +000010791/* Set if MAIL or MAILPATH is changed. */
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010792static smallint mail_var_path_changed;
Eric Andersencb57d552001-06-28 07:25:16 +000010793
Eric Andersencb57d552001-06-28 07:25:16 +000010794/*
Eric Andersenc470f442003-07-28 09:56:35 +000010795 * Print appropriate message(s) if mail has arrived.
10796 * If mail_var_path_changed is set,
10797 * then the value of MAIL has mail_var_path_changed,
10798 * so we just update the values.
Eric Andersencb57d552001-06-28 07:25:16 +000010799 */
Eric Andersenc470f442003-07-28 09:56:35 +000010800static void
10801chkmail(void)
Eric Andersencb57d552001-06-28 07:25:16 +000010802{
Eric Andersencb57d552001-06-28 07:25:16 +000010803 const char *mpath;
10804 char *p;
10805 char *q;
Denys Vlasenko23841622015-10-09 15:52:03 +020010806 unsigned new_hash;
Eric Andersencb57d552001-06-28 07:25:16 +000010807 struct stackmark smark;
10808 struct stat statb;
10809
Eric Andersencb57d552001-06-28 07:25:16 +000010810 setstackmark(&smark);
Eric Andersenc470f442003-07-28 09:56:35 +000010811 mpath = mpathset() ? mpathval() : mailval();
Denys Vlasenko23841622015-10-09 15:52:03 +020010812 new_hash = 0;
10813 for (;;) {
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020010814 p = path_advance(&mpath, nullstr);
Eric Andersencb57d552001-06-28 07:25:16 +000010815 if (p == NULL)
10816 break;
10817 if (*p == '\0')
10818 continue;
Denis Vlasenkof7d56652008-03-25 05:51:41 +000010819 for (q = p; *q; q++)
10820 continue;
Denis Vlasenkoa7189f02006-11-17 20:29:00 +000010821#if DEBUG
Eric Andersencb57d552001-06-28 07:25:16 +000010822 if (q[-1] != '/')
10823 abort();
10824#endif
Eric Andersenc470f442003-07-28 09:56:35 +000010825 q[-1] = '\0'; /* delete trailing '/' */
10826 if (stat(p, &statb) < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +000010827 continue;
Eric Andersencb57d552001-06-28 07:25:16 +000010828 }
Denys Vlasenko23841622015-10-09 15:52:03 +020010829 /* Very simplistic "hash": just a sum of all mtimes */
10830 new_hash += (unsigned)statb.st_mtime;
10831 }
10832 if (!mail_var_path_changed && mailtime_hash != new_hash) {
Denys Vlasenko4cd99e72015-10-09 16:02:53 +020010833 if (mailtime_hash != 0)
10834 out2str("you have mail\n");
Denys Vlasenko23841622015-10-09 15:52:03 +020010835 mailtime_hash = new_hash;
Eric Andersencb57d552001-06-28 07:25:16 +000010836 }
Eric Andersenc470f442003-07-28 09:56:35 +000010837 mail_var_path_changed = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010838 popstackmark(&smark);
10839}
Eric Andersencb57d552001-06-28 07:25:16 +000010840
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010841static void FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010842changemail(const char *val UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000010843{
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010844 mail_var_path_changed = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000010845}
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010846
Denis Vlasenko131ae172007-02-18 13:00:19 +000010847#endif /* ASH_MAIL */
Eric Andersenc470f442003-07-28 09:56:35 +000010848
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010849
10850/* ============ ??? */
10851
Eric Andersencb57d552001-06-28 07:25:16 +000010852/*
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010853 * Set the shell parameters.
Eric Andersencb57d552001-06-28 07:25:16 +000010854 */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010855static void
10856setparam(char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000010857{
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010858 char **newparam;
10859 char **ap;
10860 int nparam;
Eric Andersencb57d552001-06-28 07:25:16 +000010861
Denis Vlasenkof7d56652008-03-25 05:51:41 +000010862 for (nparam = 0; argv[nparam]; nparam++)
10863 continue;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010864 ap = newparam = ckmalloc((nparam + 1) * sizeof(*ap));
10865 while (*argv) {
10866 *ap++ = ckstrdup(*argv++);
Eric Andersencb57d552001-06-28 07:25:16 +000010867 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010868 *ap = NULL;
10869 freeparam(&shellparam);
Denis Vlasenko01631112007-12-16 17:20:38 +000010870 shellparam.malloced = 1;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010871 shellparam.nparam = nparam;
10872 shellparam.p = newparam;
10873#if ENABLE_ASH_GETOPTS
10874 shellparam.optind = 1;
10875 shellparam.optoff = -1;
10876#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010877}
10878
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010879/*
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010880 * Process shell options. The global variable argptr contains a pointer
10881 * to the argument list; we advance it past the options.
Denis Vlasenko94e87bc2008-02-14 16:51:58 +000010882 *
10883 * SUSv3 section 2.8.1 "Consequences of Shell Errors" says:
10884 * For a non-interactive shell, an error condition encountered
10885 * by a special built-in ... shall cause the shell to write a diagnostic message
10886 * to standard error and exit as shown in the following table:
Denis Vlasenko56244732008-02-17 15:14:04 +000010887 * Error Special Built-In
Denis Vlasenko94e87bc2008-02-14 16:51:58 +000010888 * ...
10889 * Utility syntax error (option or operand error) Shall exit
10890 * ...
10891 * However, in bug 1142 (http://busybox.net/bugs/view.php?id=1142)
10892 * we see that bash does not do that (set "finishes" with error code 1 instead,
10893 * and shell continues), and people rely on this behavior!
10894 * Testcase:
10895 * set -o barfoo 2>/dev/null
10896 * echo $?
10897 *
10898 * Oh well. Let's mimic that.
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010899 */
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010900static int
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010901plus_minus_o(char *name, int val)
Eric Andersen62483552001-07-10 06:09:16 +000010902{
10903 int i;
10904
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010905 if (name) {
10906 for (i = 0; i < NOPTS; i++) {
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000010907 if (strcmp(name, optnames(i)) == 0) {
Eric Andersenc470f442003-07-28 09:56:35 +000010908 optlist[i] = val;
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010909 return 0;
Eric Andersen62483552001-07-10 06:09:16 +000010910 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010911 }
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010912 ash_msg("illegal option %co %s", val ? '-' : '+', name);
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010913 return 1;
Eric Andersen62483552001-07-10 06:09:16 +000010914 }
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000010915 for (i = 0; i < NOPTS; i++) {
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010916 if (val) {
10917 out1fmt("%-16s%s\n", optnames(i), optlist[i] ? "on" : "off");
10918 } else {
10919 out1fmt("set %co %s\n", optlist[i] ? '-' : '+', optnames(i));
10920 }
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000010921 }
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010922 return 0;
Eric Andersen62483552001-07-10 06:09:16 +000010923}
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010924static void
10925setoption(int flag, int val)
10926{
10927 int i;
10928
10929 for (i = 0; i < NOPTS; i++) {
10930 if (optletters(i) == flag) {
10931 optlist[i] = val;
10932 return;
10933 }
10934 }
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010935 ash_msg_and_raise_error("illegal option %c%c", val ? '-' : '+', flag);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010936 /* NOTREACHED */
10937}
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010938static int
Denys Vlasenkoec05df12017-07-31 19:43:47 +020010939options(int cmdline, int *login_sh)
Eric Andersencb57d552001-06-28 07:25:16 +000010940{
10941 char *p;
10942 int val;
10943 int c;
10944
10945 if (cmdline)
10946 minusc = NULL;
10947 while ((p = *argptr) != NULL) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010948 c = *p++;
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010949 if (c != '-' && c != '+')
10950 break;
10951 argptr++;
10952 val = 0; /* val = 0 if c == '+' */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010953 if (c == '-') {
Eric Andersencb57d552001-06-28 07:25:16 +000010954 val = 1;
Denis Vlasenko9f739442006-12-16 23:49:13 +000010955 if (p[0] == '\0' || LONE_DASH(p)) {
Eric Andersen2870d962001-07-02 17:27:21 +000010956 if (!cmdline) {
10957 /* "-" means turn off -x and -v */
10958 if (p[0] == '\0')
10959 xflag = vflag = 0;
10960 /* "--" means reset params */
10961 else if (*argptr == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +000010962 setparam(argptr);
Eric Andersen2870d962001-07-02 17:27:21 +000010963 }
Denys Vlasenkob0b83432011-03-07 12:34:59 +010010964 break; /* "-" or "--" terminates options */
Eric Andersencb57d552001-06-28 07:25:16 +000010965 }
Eric Andersencb57d552001-06-28 07:25:16 +000010966 }
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010967 /* first char was + or - */
Eric Andersencb57d552001-06-28 07:25:16 +000010968 while ((c = *p++) != '\0') {
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010969 /* bash 3.2 indeed handles -c CMD and +c CMD the same */
Eric Andersencb57d552001-06-28 07:25:16 +000010970 if (c == 'c' && cmdline) {
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010971 minusc = p; /* command is after shell args */
Eric Andersencb57d552001-06-28 07:25:16 +000010972 } else if (c == 'o') {
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010973 if (plus_minus_o(*argptr, val)) {
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010974 /* it already printed err message */
10975 return 1; /* error */
10976 }
Eric Andersencb57d552001-06-28 07:25:16 +000010977 if (*argptr)
10978 argptr++;
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010979 } else if (cmdline && (c == 'l')) { /* -l or +l == --login */
Denys Vlasenkoec05df12017-07-31 19:43:47 +020010980 if (login_sh)
10981 *login_sh = 1;
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010982 /* bash does not accept +-login, we also won't */
10983 } else if (cmdline && val && (c == '-')) { /* long options */
Denys Vlasenkoec05df12017-07-31 19:43:47 +020010984 if (strcmp(p, "login") == 0) {
10985 if (login_sh)
10986 *login_sh = 1;
10987 }
Robert Griebl64f70cc2002-05-14 23:22:06 +000010988 break;
Eric Andersencb57d552001-06-28 07:25:16 +000010989 } else {
10990 setoption(c, val);
10991 }
10992 }
10993 }
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010994 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010995}
10996
Eric Andersencb57d552001-06-28 07:25:16 +000010997/*
Eric Andersencb57d552001-06-28 07:25:16 +000010998 * The shift builtin command.
10999 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020011000static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000011001shiftcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000011002{
11003 int n;
11004 char **ap1, **ap2;
11005
11006 n = 1;
Denis Vlasenko68404f12008-03-17 09:00:54 +000011007 if (argv[1])
Eric Andersencb57d552001-06-28 07:25:16 +000011008 n = number(argv[1]);
11009 if (n > shellparam.nparam)
Ingo van Lil9c8e94b2018-01-05 15:04:23 +010011010 return 1;
Denis Vlasenkob012b102007-02-19 22:43:01 +000011011 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +000011012 shellparam.nparam -= n;
Denis Vlasenko2da584f2007-02-19 22:44:05 +000011013 for (ap1 = shellparam.p; --n >= 0; ap1++) {
Denis Vlasenko01631112007-12-16 17:20:38 +000011014 if (shellparam.malloced)
Denis Vlasenkob012b102007-02-19 22:43:01 +000011015 free(*ap1);
Eric Andersencb57d552001-06-28 07:25:16 +000011016 }
11017 ap2 = shellparam.p;
Denis Vlasenkof7d56652008-03-25 05:51:41 +000011018 while ((*ap2++ = *ap1++) != NULL)
11019 continue;
Denis Vlasenko131ae172007-02-18 13:00:19 +000011020#if ENABLE_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +000011021 shellparam.optind = 1;
11022 shellparam.optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +000011023#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +000011024 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +000011025 return 0;
11026}
11027
Eric Andersencb57d552001-06-28 07:25:16 +000011028/*
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011029 * POSIX requires that 'set' (but not export or readonly) output the
11030 * variables in lexicographic order - by the locale's collating order (sigh).
11031 * Maybe we could keep them in an ordered balanced binary tree
11032 * instead of hashed lists.
11033 * For now just roll 'em through qsort for printing...
11034 */
11035static int
11036showvars(const char *sep_prefix, int on, int off)
11037{
11038 const char *sep;
11039 char **ep, **epend;
11040
Denys Vlasenkoa5060b82017-11-03 14:16:25 +010011041 ep = listvars(on, off, /*strlist:*/ NULL, &epend);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011042 qsort(ep, epend - ep, sizeof(char *), vpcmp);
11043
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000011044 sep = *sep_prefix ? " " : sep_prefix;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011045
11046 for (; ep < epend; ep++) {
11047 const char *p;
11048 const char *q;
11049
Denys Vlasenko9c143ce2017-11-02 12:56:24 +010011050 p = endofname(*ep);
11051/* Used to have simple "p = strchrnul(*ep, '=')" here instead, but this
11052 * makes "export -p" to have output not suitable for "eval":
11053 * import os
11054 * os.environ["test-test"]="test"
11055 * if os.fork() == 0:
11056 * os.execv("ash", [ 'ash', '-c', 'eval $(export -p); echo OK' ]) # fixes this
11057 * os.execv("ash", [ 'ash', '-c', 'env | grep test-test' ])
11058 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011059 q = nullstr;
Denys Vlasenko9c143ce2017-11-02 12:56:24 +010011060 if (*p == '=')
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011061 q = single_quote(++p);
11062 out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
11063 }
11064 return 0;
11065}
11066
11067/*
Eric Andersencb57d552001-06-28 07:25:16 +000011068 * The set command builtin.
11069 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020011070static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000011071setcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +000011072{
Denis Vlasenko28bf6712008-02-14 15:01:47 +000011073 int retval;
11074
Denis Vlasenko68404f12008-03-17 09:00:54 +000011075 if (!argv[1])
Eric Andersenc470f442003-07-28 09:56:35 +000011076 return showvars(nullstr, 0, VUNSET);
Denys Vlasenkob0b83432011-03-07 12:34:59 +010011077
Denis Vlasenkob012b102007-02-19 22:43:01 +000011078 INT_OFF;
Denys Vlasenkoec05df12017-07-31 19:43:47 +020011079 retval = options(/*cmdline:*/ 0, NULL);
Denys Vlasenkob0b83432011-03-07 12:34:59 +010011080 if (retval == 0) { /* if no parse error... */
Denis Vlasenko28bf6712008-02-14 15:01:47 +000011081 optschanged();
11082 if (*argptr != NULL) {
11083 setparam(argptr);
11084 }
Eric Andersencb57d552001-06-28 07:25:16 +000011085 }
Denis Vlasenkob012b102007-02-19 22:43:01 +000011086 INT_ON;
Denis Vlasenko28bf6712008-02-14 15:01:47 +000011087 return retval;
Eric Andersencb57d552001-06-28 07:25:16 +000011088}
11089
Denis Vlasenko131ae172007-02-18 13:00:19 +000011090#if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020011091static void FAST_FUNC
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000011092change_random(const char *value)
Eric Andersenef02f822004-03-11 13:34:24 +000011093{
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020011094 uint32_t t;
11095
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011096 if (value == NULL) {
Eric Andersen16767e22004-03-16 05:14:10 +000011097 /* "get", generate */
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020011098 t = next_random(&random_gen);
Eric Andersen16767e22004-03-16 05:14:10 +000011099 /* set without recursion */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +020011100 setvar(vrandom.var_text, utoa(t), VNOFUNC);
Eric Andersen16767e22004-03-16 05:14:10 +000011101 vrandom.flags &= ~VNOFUNC;
11102 } else {
11103 /* set/reset */
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020011104 t = strtoul(value, NULL, 10);
11105 INIT_RANDOM_T(&random_gen, (t ? t : 1), t);
Eric Andersen16767e22004-03-16 05:14:10 +000011106 }
Eric Andersenef02f822004-03-11 13:34:24 +000011107}
Eric Andersen16767e22004-03-16 05:14:10 +000011108#endif
11109
Denis Vlasenko131ae172007-02-18 13:00:19 +000011110#if ENABLE_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +000011111static int
Denys Vlasenko35c2a132016-10-26 17:34:26 +020011112getopts(char *optstr, char *optvar, char **optfirst)
Eric Andersencb57d552001-06-28 07:25:16 +000011113{
11114 char *p, *q;
11115 char c = '?';
11116 int done = 0;
Denys Vlasenko9c541002015-10-07 15:44:36 +020011117 char sbuf[2];
Eric Andersena48b0a32003-10-22 10:56:47 +000011118 char **optnext;
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020011119 int ind = shellparam.optind;
11120 int off = shellparam.optoff;
Eric Andersencb57d552001-06-28 07:25:16 +000011121
Denys Vlasenko9c541002015-10-07 15:44:36 +020011122 sbuf[1] = '\0';
11123
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020011124 shellparam.optind = -1;
11125 optnext = optfirst + ind - 1;
Eric Andersena48b0a32003-10-22 10:56:47 +000011126
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020011127 if (ind <= 1 || off < 0 || (int)strlen(optnext[-1]) < off)
Eric Andersencb57d552001-06-28 07:25:16 +000011128 p = NULL;
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020011129 else
11130 p = optnext[-1] + off;
Eric Andersencb57d552001-06-28 07:25:16 +000011131 if (p == NULL || *p == '\0') {
11132 /* Current word is done, advance */
Eric Andersencb57d552001-06-28 07:25:16 +000011133 p = *optnext;
11134 if (p == NULL || *p != '-' || *++p == '\0') {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011135 atend:
Denys Vlasenko9832bba2017-08-15 15:44:41 +020011136 unsetvar("OPTARG");
Eric Andersencb57d552001-06-28 07:25:16 +000011137 p = NULL;
11138 done = 1;
11139 goto out;
11140 }
11141 optnext++;
Denis Vlasenko9f739442006-12-16 23:49:13 +000011142 if (LONE_DASH(p)) /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +000011143 goto atend;
11144 }
11145
11146 c = *p++;
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +000011147 for (q = optstr; *q != c;) {
Eric Andersencb57d552001-06-28 07:25:16 +000011148 if (*q == '\0') {
Denys Vlasenko9832bba2017-08-15 15:44:41 +020011149 /* OPTERR is a bashism */
11150 const char *cp = lookupvar("OPTERR");
11151 if ((cp && LONE_CHAR(cp, '0'))
11152 || (optstr[0] == ':')
11153 ) {
Denys Vlasenko9c541002015-10-07 15:44:36 +020011154 sbuf[0] = c;
11155 /*sbuf[1] = '\0'; - already is */
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020011156 setvar0("OPTARG", sbuf);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011157 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000011158 fprintf(stderr, "Illegal option -%c\n", c);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011159 unsetvar("OPTARG");
Eric Andersencb57d552001-06-28 07:25:16 +000011160 }
11161 c = '?';
Eric Andersenc470f442003-07-28 09:56:35 +000011162 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +000011163 }
11164 if (*++q == ':')
11165 q++;
11166 }
11167
11168 if (*++q == ':') {
11169 if (*p == '\0' && (p = *optnext) == NULL) {
Denys Vlasenko9832bba2017-08-15 15:44:41 +020011170 /* OPTERR is a bashism */
11171 const char *cp = lookupvar("OPTERR");
11172 if ((cp && LONE_CHAR(cp, '0'))
11173 || (optstr[0] == ':')
11174 ) {
Denys Vlasenko9c541002015-10-07 15:44:36 +020011175 sbuf[0] = c;
11176 /*sbuf[1] = '\0'; - already is */
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020011177 setvar0("OPTARG", sbuf);
Eric Andersencb57d552001-06-28 07:25:16 +000011178 c = ':';
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011179 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000011180 fprintf(stderr, "No arg for -%c option\n", c);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011181 unsetvar("OPTARG");
Eric Andersencb57d552001-06-28 07:25:16 +000011182 c = '?';
11183 }
Eric Andersenc470f442003-07-28 09:56:35 +000011184 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +000011185 }
11186
11187 if (p == *optnext)
11188 optnext++;
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020011189 setvar0("OPTARG", p);
Eric Andersencb57d552001-06-28 07:25:16 +000011190 p = NULL;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011191 } else
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020011192 setvar0("OPTARG", nullstr);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011193 out:
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020011194 ind = optnext - optfirst + 1;
11195 setvar("OPTIND", itoa(ind), VNOFUNC);
Denys Vlasenko9c541002015-10-07 15:44:36 +020011196 sbuf[0] = c;
11197 /*sbuf[1] = '\0'; - already is */
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020011198 setvar0(optvar, sbuf);
11199
11200 shellparam.optoff = p ? p - *(optnext - 1) : -1;
11201 shellparam.optind = ind;
11202
Eric Andersencb57d552001-06-28 07:25:16 +000011203 return done;
11204}
Eric Andersenc470f442003-07-28 09:56:35 +000011205
11206/*
11207 * The getopts builtin. Shellparam.optnext points to the next argument
11208 * to be processed. Shellparam.optptr points to the next character to
11209 * be processed in the current argument. If shellparam.optnext is NULL,
11210 * then it's the first time getopts has been called.
11211 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020011212static int FAST_FUNC
Eric Andersenc470f442003-07-28 09:56:35 +000011213getoptscmd(int argc, char **argv)
11214{
11215 char **optbase;
11216
11217 if (argc < 3)
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +000011218 ash_msg_and_raise_error("usage: getopts optstring var [arg]");
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011219 if (argc == 3) {
Eric Andersenc470f442003-07-28 09:56:35 +000011220 optbase = shellparam.p;
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020011221 if ((unsigned)shellparam.optind > shellparam.nparam + 1) {
Eric Andersenc470f442003-07-28 09:56:35 +000011222 shellparam.optind = 1;
11223 shellparam.optoff = -1;
11224 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011225 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000011226 optbase = &argv[3];
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020011227 if ((unsigned)shellparam.optind > argc - 2) {
Eric Andersenc470f442003-07-28 09:56:35 +000011228 shellparam.optind = 1;
11229 shellparam.optoff = -1;
11230 }
11231 }
11232
Denys Vlasenko35c2a132016-10-26 17:34:26 +020011233 return getopts(argv[1], argv[2], optbase);
Eric Andersenc470f442003-07-28 09:56:35 +000011234}
Denis Vlasenko131ae172007-02-18 13:00:19 +000011235#endif /* ASH_GETOPTS */
Eric Andersencb57d552001-06-28 07:25:16 +000011236
Eric Andersencb57d552001-06-28 07:25:16 +000011237
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011238/* ============ Shell parser */
Eric Andersencb57d552001-06-28 07:25:16 +000011239
Denis Vlasenkob07a4962008-06-22 13:16:23 +000011240struct heredoc {
11241 struct heredoc *next; /* next here document in list */
11242 union node *here; /* redirection node */
11243 char *eofmark; /* string indicating end of input */
11244 smallint striptabs; /* if set, strip leading tabs */
11245};
11246
11247static smallint tokpushback; /* last token pushed back */
Denis Vlasenkob07a4962008-06-22 13:16:23 +000011248static smallint quoteflag; /* set if (part of) last token was quoted */
11249static token_id_t lasttoken; /* last token read (integer id Txxx) */
11250static struct heredoc *heredoclist; /* list of here documents to read */
11251static char *wordtext; /* text of last word returned by readtoken */
11252static struct nodelist *backquotelist;
11253static union node *redirnode;
11254static struct heredoc *heredoc;
Denis Vlasenko99eb8502007-02-23 21:09:49 +000011255
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020011256static const char *
11257tokname(char *buf, int tok)
11258{
11259 if (tok < TSEMI)
Denys Vlasenko888527c2016-10-02 16:54:17 +020011260 return tokname_array[tok];
11261 sprintf(buf, "\"%s\"", tokname_array[tok]);
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020011262 return buf;
11263}
11264
11265/* raise_error_unexpected_syntax:
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011266 * Called when an unexpected token is read during the parse. The argument
11267 * is the token that is expected, or -1 if more than one type of token can
11268 * occur at this point.
11269 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000011270static void raise_error_unexpected_syntax(int) NORETURN;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011271static void
11272raise_error_unexpected_syntax(int token)
11273{
11274 char msg[64];
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020011275 char buf[16];
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011276 int l;
11277
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020011278 l = sprintf(msg, "unexpected %s", tokname(buf, lasttoken));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011279 if (token >= 0)
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020011280 sprintf(msg + l, " (expecting %s)", tokname(buf, token));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011281 raise_error_syntax(msg);
11282 /* NOTREACHED */
11283}
Eric Andersencb57d552001-06-28 07:25:16 +000011284
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011285/* parsing is heavily cross-recursive, need these forward decls */
11286static union node *andor(void);
11287static union node *pipeline(void);
11288static union node *parse_command(void);
11289static void parseheredoc(void);
Ron Yorstonc0e00762015-10-29 11:30:55 +000011290static int peektoken(void);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011291static int readtoken(void);
Eric Andersencb57d552001-06-28 07:25:16 +000011292
Eric Andersenc470f442003-07-28 09:56:35 +000011293static union node *
11294list(int nlflag)
Eric Andersencb57d552001-06-28 07:25:16 +000011295{
11296 union node *n1, *n2, *n3;
11297 int tok;
11298
Eric Andersencb57d552001-06-28 07:25:16 +000011299 n1 = NULL;
11300 for (;;) {
Ron Yorstonc0e00762015-10-29 11:30:55 +000011301 switch (peektoken()) {
11302 case TNL:
11303 if (!(nlflag & 1))
11304 break;
11305 parseheredoc();
11306 return n1;
11307
11308 case TEOF:
11309 if (!n1 && (nlflag & 1))
11310 n1 = NODE_EOF;
11311 parseheredoc();
11312 return n1;
11313 }
11314
11315 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Denys Vlasenko888527c2016-10-02 16:54:17 +020011316 if (nlflag == 2 && ((1 << peektoken()) & tokendlist))
Ron Yorstonc0e00762015-10-29 11:30:55 +000011317 return n1;
11318 nlflag |= 2;
11319
Eric Andersencb57d552001-06-28 07:25:16 +000011320 n2 = andor();
11321 tok = readtoken();
11322 if (tok == TBACKGND) {
Eric Andersenc470f442003-07-28 09:56:35 +000011323 if (n2->type == NPIPE) {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +000011324 n2->npipe.pipe_backgnd = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011325 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000011326 if (n2->type != NREDIR) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011327 n3 = stzalloc(sizeof(struct nredir));
Eric Andersenc470f442003-07-28 09:56:35 +000011328 n3->nredir.n = n2;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011329 /*n3->nredir.redirect = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011330 n2 = n3;
11331 }
11332 n2->type = NBACKGND;
Eric Andersencb57d552001-06-28 07:25:16 +000011333 }
11334 }
11335 if (n1 == NULL) {
11336 n1 = n2;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011337 } else {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011338 n3 = stzalloc(sizeof(struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +000011339 n3->type = NSEMI;
11340 n3->nbinary.ch1 = n1;
11341 n3->nbinary.ch2 = n2;
11342 n1 = n3;
11343 }
11344 switch (tok) {
Ron Yorstonc0e00762015-10-29 11:30:55 +000011345 case TNL:
11346 case TEOF:
11347 tokpushback = 1;
11348 /* fall through */
Eric Andersencb57d552001-06-28 07:25:16 +000011349 case TBACKGND:
11350 case TSEMI:
Eric Andersencb57d552001-06-28 07:25:16 +000011351 break;
Eric Andersencb57d552001-06-28 07:25:16 +000011352 default:
Ron Yorstonc0e00762015-10-29 11:30:55 +000011353 if ((nlflag & 1))
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011354 raise_error_unexpected_syntax(-1);
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011355 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011356 return n1;
11357 }
11358 }
11359}
11360
Eric Andersenc470f442003-07-28 09:56:35 +000011361static union node *
11362andor(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011363{
Eric Andersencb57d552001-06-28 07:25:16 +000011364 union node *n1, *n2, *n3;
11365 int t;
11366
Eric Andersencb57d552001-06-28 07:25:16 +000011367 n1 = pipeline();
11368 for (;;) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011369 t = readtoken();
11370 if (t == TAND) {
Eric Andersencb57d552001-06-28 07:25:16 +000011371 t = NAND;
11372 } else if (t == TOR) {
11373 t = NOR;
11374 } else {
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011375 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011376 return n1;
11377 }
Eric Andersenc470f442003-07-28 09:56:35 +000011378 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000011379 n2 = pipeline();
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011380 n3 = stzalloc(sizeof(struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +000011381 n3->type = t;
11382 n3->nbinary.ch1 = n1;
11383 n3->nbinary.ch2 = n2;
11384 n1 = n3;
11385 }
11386}
11387
Eric Andersenc470f442003-07-28 09:56:35 +000011388static union node *
11389pipeline(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011390{
Eric Andersencb57d552001-06-28 07:25:16 +000011391 union node *n1, *n2, *pipenode;
11392 struct nodelist *lp, *prev;
11393 int negate;
11394
11395 negate = 0;
11396 TRACE(("pipeline: entered\n"));
11397 if (readtoken() == TNOT) {
11398 negate = !negate;
Eric Andersenc470f442003-07-28 09:56:35 +000011399 checkkwd = CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000011400 } else
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011401 tokpushback = 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011402 n1 = parse_command();
Eric Andersencb57d552001-06-28 07:25:16 +000011403 if (readtoken() == TPIPE) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011404 pipenode = stzalloc(sizeof(struct npipe));
Eric Andersencb57d552001-06-28 07:25:16 +000011405 pipenode->type = NPIPE;
Denis Vlasenko2dc240c2008-07-24 06:07:50 +000011406 /*pipenode->npipe.pipe_backgnd = 0; - stzalloc did it */
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011407 lp = stzalloc(sizeof(struct nodelist));
Eric Andersencb57d552001-06-28 07:25:16 +000011408 pipenode->npipe.cmdlist = lp;
11409 lp->n = n1;
11410 do {
11411 prev = lp;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011412 lp = stzalloc(sizeof(struct nodelist));
Eric Andersenc470f442003-07-28 09:56:35 +000011413 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011414 lp->n = parse_command();
Eric Andersencb57d552001-06-28 07:25:16 +000011415 prev->next = lp;
11416 } while (readtoken() == TPIPE);
11417 lp->next = NULL;
11418 n1 = pipenode;
11419 }
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011420 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011421 if (negate) {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011422 n2 = stzalloc(sizeof(struct nnot));
Eric Andersencb57d552001-06-28 07:25:16 +000011423 n2->type = NNOT;
11424 n2->nnot.com = n1;
11425 return n2;
Denis Vlasenko2da584f2007-02-19 22:44:05 +000011426 }
11427 return n1;
Eric Andersencb57d552001-06-28 07:25:16 +000011428}
11429
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011430static union node *
11431makename(void)
11432{
11433 union node *n;
11434
Denis Vlasenko597906c2008-02-20 16:38:54 +000011435 n = stzalloc(sizeof(struct narg));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011436 n->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011437 /*n->narg.next = NULL; - stzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011438 n->narg.text = wordtext;
11439 n->narg.backquote = backquotelist;
11440 return n;
11441}
11442
11443static void
11444fixredir(union node *n, const char *text, int err)
11445{
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000011446 int fd;
11447
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011448 TRACE(("Fix redir %s %d\n", text, err));
11449 if (!err)
11450 n->ndup.vname = NULL;
11451
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000011452 fd = bb_strtou(text, NULL, 10);
11453 if (!errno && fd >= 0)
11454 n->ndup.dupfd = fd;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011455 else if (LONE_DASH(text))
11456 n->ndup.dupfd = -1;
11457 else {
11458 if (err)
Denis Vlasenko559691a2008-10-05 18:39:31 +000011459 raise_error_syntax("bad fd number");
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011460 n->ndup.vname = makename();
11461 }
11462}
11463
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011464static void
11465parsefname(void)
11466{
11467 union node *n = redirnode;
11468
Denys Vlasenkoa7328982017-07-29 19:57:28 +020011469 if (n->type == NHERE)
11470 checkkwd = CHKEOFMARK;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011471 if (readtoken() != TWORD)
11472 raise_error_unexpected_syntax(-1);
11473 if (n->type == NHERE) {
11474 struct heredoc *here = heredoc;
11475 struct heredoc *p;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011476
11477 if (quoteflag == 0)
11478 n->type = NXHERE;
11479 TRACE(("Here document %d\n", n->type));
Denys Vlasenko740058b2018-01-09 17:01:00 +010011480 rmescapes(wordtext, 0, NULL);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011481 here->eofmark = wordtext;
11482 here->next = NULL;
11483 if (heredoclist == NULL)
11484 heredoclist = here;
11485 else {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011486 for (p = heredoclist; p->next; p = p->next)
11487 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011488 p->next = here;
11489 }
11490 } else if (n->type == NTOFD || n->type == NFROMFD) {
11491 fixredir(n, wordtext, 0);
11492 } else {
11493 n->nfile.fname = makename();
11494 }
11495}
Eric Andersencb57d552001-06-28 07:25:16 +000011496
Eric Andersenc470f442003-07-28 09:56:35 +000011497static union node *
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011498simplecmd(void)
11499{
11500 union node *args, **app;
11501 union node *n = NULL;
11502 union node *vars, **vpp;
11503 union node **rpp, *redir;
11504 int savecheckkwd;
Denys Vlasenko675d24a2018-01-27 22:02:05 +010011505 int savelinno;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011506#if BASH_TEST2
Denis Vlasenko80591b02008-03-25 07:49:43 +000011507 smallint double_brackets_flag = 0;
11508#endif
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011509 IF_BASH_FUNCTION(smallint function_flag = 0;)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011510
11511 args = NULL;
11512 app = &args;
11513 vars = NULL;
11514 vpp = &vars;
11515 redir = NULL;
11516 rpp = &redir;
11517
11518 savecheckkwd = CHKALIAS;
Denys Vlasenko675d24a2018-01-27 22:02:05 +010011519 savelinno = g_parsefile->linno;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011520 for (;;) {
Denis Vlasenko80591b02008-03-25 07:49:43 +000011521 int t;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011522 checkkwd = savecheckkwd;
Denis Vlasenko80591b02008-03-25 07:49:43 +000011523 t = readtoken();
11524 switch (t) {
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011525#if BASH_FUNCTION
Ron Yorston95ebcf72015-11-03 09:42:23 +000011526 case TFUNCTION:
11527 if (peektoken() != TWORD)
11528 raise_error_unexpected_syntax(TWORD);
11529 function_flag = 1;
11530 break;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011531#endif
11532#if BASH_TEST2
Denis Vlasenko80591b02008-03-25 07:49:43 +000011533 case TAND: /* "&&" */
11534 case TOR: /* "||" */
11535 if (!double_brackets_flag) {
11536 tokpushback = 1;
11537 goto out;
11538 }
11539 wordtext = (char *) (t == TAND ? "-a" : "-o");
11540#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011541 case TWORD:
Denis Vlasenko597906c2008-02-20 16:38:54 +000011542 n = stzalloc(sizeof(struct narg));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011543 n->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011544 /*n->narg.next = NULL; - stzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011545 n->narg.text = wordtext;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011546#if BASH_TEST2
Denis Vlasenko80591b02008-03-25 07:49:43 +000011547 if (strcmp("[[", wordtext) == 0)
11548 double_brackets_flag = 1;
11549 else if (strcmp("]]", wordtext) == 0)
11550 double_brackets_flag = 0;
11551#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011552 n->narg.backquote = backquotelist;
11553 if (savecheckkwd && isassignment(wordtext)) {
11554 *vpp = n;
11555 vpp = &n->narg.next;
11556 } else {
11557 *app = n;
11558 app = &n->narg.next;
11559 savecheckkwd = 0;
11560 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011561#if BASH_FUNCTION
Ron Yorston95ebcf72015-11-03 09:42:23 +000011562 if (function_flag) {
11563 checkkwd = CHKNL | CHKKWD;
11564 switch (peektoken()) {
11565 case TBEGIN:
11566 case TIF:
11567 case TCASE:
11568 case TUNTIL:
11569 case TWHILE:
11570 case TFOR:
11571 goto do_func;
11572 case TLP:
11573 function_flag = 0;
11574 break;
11575 case TWORD:
11576 if (strcmp("[[", wordtext) == 0)
11577 goto do_func;
11578 /* fall through */
11579 default:
11580 raise_error_unexpected_syntax(-1);
11581 }
11582 }
11583#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011584 break;
11585 case TREDIR:
11586 *rpp = n = redirnode;
11587 rpp = &n->nfile.next;
11588 parsefname(); /* read name of redirection file */
11589 break;
11590 case TLP:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011591 IF_BASH_FUNCTION(do_func:)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011592 if (args && app == &args->narg.next
11593 && !vars && !redir
11594 ) {
11595 struct builtincmd *bcmd;
11596 const char *name;
11597
11598 /* We have a function */
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011599 if (IF_BASH_FUNCTION(!function_flag &&) readtoken() != TRP)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011600 raise_error_unexpected_syntax(TRP);
11601 name = n->narg.text;
11602 if (!goodname(name)
11603 || ((bcmd = find_builtin(name)) && IS_BUILTIN_SPECIAL(bcmd))
11604 ) {
Denis Vlasenko559691a2008-10-05 18:39:31 +000011605 raise_error_syntax("bad function name");
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011606 }
11607 n->type = NDEFUN;
11608 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Denys Vlasenko675d24a2018-01-27 22:02:05 +010011609 n->ndefun.text = n->narg.text;
11610 n->ndefun.linno = g_parsefile->linno;
11611 n->ndefun.body = parse_command();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011612 return n;
11613 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011614 IF_BASH_FUNCTION(function_flag = 0;)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011615 /* fall through */
11616 default:
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011617 tokpushback = 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011618 goto out;
11619 }
11620 }
11621 out:
11622 *app = NULL;
11623 *vpp = NULL;
11624 *rpp = NULL;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011625 n = stzalloc(sizeof(struct ncmd));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011626 n->type = NCMD;
Denys Vlasenko675d24a2018-01-27 22:02:05 +010011627 n->ncmd.linno = savelinno;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011628 n->ncmd.args = args;
11629 n->ncmd.assign = vars;
11630 n->ncmd.redirect = redir;
11631 return n;
11632}
11633
11634static union node *
11635parse_command(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011636{
Eric Andersencb57d552001-06-28 07:25:16 +000011637 union node *n1, *n2;
11638 union node *ap, **app;
11639 union node *cp, **cpp;
11640 union node *redir, **rpp;
Eric Andersenc470f442003-07-28 09:56:35 +000011641 union node **rpp2;
Eric Andersencb57d552001-06-28 07:25:16 +000011642 int t;
Denys Vlasenko675d24a2018-01-27 22:02:05 +010011643 int savelinno;
Eric Andersencb57d552001-06-28 07:25:16 +000011644
11645 redir = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +000011646 rpp2 = &redir;
Eric Andersen88cec252001-09-06 17:35:20 +000011647
Denys Vlasenko675d24a2018-01-27 22:02:05 +010011648 savelinno = g_parsefile->linno;
11649
Eric Andersencb57d552001-06-28 07:25:16 +000011650 switch (readtoken()) {
Eric Andersenc470f442003-07-28 09:56:35 +000011651 default:
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011652 raise_error_unexpected_syntax(-1);
Eric Andersenc470f442003-07-28 09:56:35 +000011653 /* NOTREACHED */
Eric Andersencb57d552001-06-28 07:25:16 +000011654 case TIF:
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011655 n1 = stzalloc(sizeof(struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +000011656 n1->type = NIF;
11657 n1->nif.test = list(0);
11658 if (readtoken() != TTHEN)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011659 raise_error_unexpected_syntax(TTHEN);
Eric Andersencb57d552001-06-28 07:25:16 +000011660 n1->nif.ifpart = list(0);
11661 n2 = n1;
11662 while (readtoken() == TELIF) {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011663 n2->nif.elsepart = stzalloc(sizeof(struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +000011664 n2 = n2->nif.elsepart;
11665 n2->type = NIF;
11666 n2->nif.test = list(0);
11667 if (readtoken() != TTHEN)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011668 raise_error_unexpected_syntax(TTHEN);
Eric Andersencb57d552001-06-28 07:25:16 +000011669 n2->nif.ifpart = list(0);
11670 }
11671 if (lasttoken == TELSE)
11672 n2->nif.elsepart = list(0);
11673 else {
11674 n2->nif.elsepart = NULL;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011675 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011676 }
Eric Andersenc470f442003-07-28 09:56:35 +000011677 t = TFI;
Eric Andersencb57d552001-06-28 07:25:16 +000011678 break;
11679 case TWHILE:
Eric Andersenc470f442003-07-28 09:56:35 +000011680 case TUNTIL: {
Eric Andersencb57d552001-06-28 07:25:16 +000011681 int got;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011682 n1 = stzalloc(sizeof(struct nbinary));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011683 n1->type = (lasttoken == TWHILE) ? NWHILE : NUNTIL;
Eric Andersencb57d552001-06-28 07:25:16 +000011684 n1->nbinary.ch1 = list(0);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011685 got = readtoken();
11686 if (got != TDO) {
Denys Vlasenko888527c2016-10-02 16:54:17 +020011687 TRACE(("expecting DO got '%s' %s\n", tokname_array[got],
Denis Vlasenko131ae172007-02-18 13:00:19 +000011688 got == TWORD ? wordtext : ""));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011689 raise_error_unexpected_syntax(TDO);
Eric Andersencb57d552001-06-28 07:25:16 +000011690 }
11691 n1->nbinary.ch2 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +000011692 t = TDONE;
Eric Andersencb57d552001-06-28 07:25:16 +000011693 break;
11694 }
11695 case TFOR:
Denis Vlasenko2dc240c2008-07-24 06:07:50 +000011696 if (readtoken() != TWORD || quoteflag || !goodname(wordtext))
Denis Vlasenko559691a2008-10-05 18:39:31 +000011697 raise_error_syntax("bad for loop variable");
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011698 n1 = stzalloc(sizeof(struct nfor));
Eric Andersencb57d552001-06-28 07:25:16 +000011699 n1->type = NFOR;
Denys Vlasenko675d24a2018-01-27 22:02:05 +010011700 n1->nfor.linno = savelinno;
Eric Andersencb57d552001-06-28 07:25:16 +000011701 n1->nfor.var = wordtext;
Ron Yorstonab80e012015-08-03 13:46:00 +010011702 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000011703 if (readtoken() == TIN) {
11704 app = &ap;
11705 while (readtoken() == TWORD) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011706 n2 = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000011707 n2->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011708 /*n2->narg.next = NULL; - stzalloc did it */
Eric Andersencb57d552001-06-28 07:25:16 +000011709 n2->narg.text = wordtext;
11710 n2->narg.backquote = backquotelist;
11711 *app = n2;
11712 app = &n2->narg.next;
11713 }
11714 *app = NULL;
11715 n1->nfor.args = ap;
11716 if (lasttoken != TNL && lasttoken != TSEMI)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011717 raise_error_unexpected_syntax(-1);
Eric Andersencb57d552001-06-28 07:25:16 +000011718 } else {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011719 n2 = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000011720 n2->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011721 /*n2->narg.next = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011722 n2->narg.text = (char *)dolatstr;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011723 /*n2->narg.backquote = NULL;*/
Eric Andersencb57d552001-06-28 07:25:16 +000011724 n1->nfor.args = n2;
11725 /*
11726 * Newline or semicolon here is optional (but note
11727 * that the original Bourne shell only allowed NL).
11728 */
Ron Yorstonab80e012015-08-03 13:46:00 +010011729 if (lasttoken != TSEMI)
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011730 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011731 }
Eric Andersenc470f442003-07-28 09:56:35 +000011732 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000011733 if (readtoken() != TDO)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011734 raise_error_unexpected_syntax(TDO);
Eric Andersencb57d552001-06-28 07:25:16 +000011735 n1->nfor.body = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +000011736 t = TDONE;
Eric Andersencb57d552001-06-28 07:25:16 +000011737 break;
11738 case TCASE:
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011739 n1 = stzalloc(sizeof(struct ncase));
Eric Andersencb57d552001-06-28 07:25:16 +000011740 n1->type = NCASE;
Denys Vlasenko675d24a2018-01-27 22:02:05 +010011741 n1->ncase.linno = savelinno;
Eric Andersencb57d552001-06-28 07:25:16 +000011742 if (readtoken() != TWORD)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011743 raise_error_unexpected_syntax(TWORD);
Denis Vlasenko597906c2008-02-20 16:38:54 +000011744 n1->ncase.expr = n2 = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000011745 n2->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011746 /*n2->narg.next = NULL; - stzalloc did it */
Eric Andersencb57d552001-06-28 07:25:16 +000011747 n2->narg.text = wordtext;
11748 n2->narg.backquote = backquotelist;
Ron Yorston383b8852015-08-03 13:46:25 +010011749 checkkwd = CHKNL | CHKKWD | CHKALIAS;
11750 if (readtoken() != TIN)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011751 raise_error_unexpected_syntax(TIN);
Eric Andersencb57d552001-06-28 07:25:16 +000011752 cpp = &n1->ncase.cases;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011753 next_case:
Eric Andersenc470f442003-07-28 09:56:35 +000011754 checkkwd = CHKNL | CHKKWD;
11755 t = readtoken();
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011756 while (t != TESAC) {
Eric Andersencb57d552001-06-28 07:25:16 +000011757 if (lasttoken == TLP)
11758 readtoken();
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011759 *cpp = cp = stzalloc(sizeof(struct nclist));
Eric Andersencb57d552001-06-28 07:25:16 +000011760 cp->type = NCLIST;
11761 app = &cp->nclist.pattern;
11762 for (;;) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011763 *app = ap = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000011764 ap->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011765 /*ap->narg.next = NULL; - stzalloc did it */
Eric Andersencb57d552001-06-28 07:25:16 +000011766 ap->narg.text = wordtext;
11767 ap->narg.backquote = backquotelist;
Eric Andersenc470f442003-07-28 09:56:35 +000011768 if (readtoken() != TPIPE)
Eric Andersencb57d552001-06-28 07:25:16 +000011769 break;
11770 app = &ap->narg.next;
11771 readtoken();
11772 }
Denis Vlasenko597906c2008-02-20 16:38:54 +000011773 //ap->narg.next = NULL;
Eric Andersencb57d552001-06-28 07:25:16 +000011774 if (lasttoken != TRP)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011775 raise_error_unexpected_syntax(TRP);
Eric Andersenc470f442003-07-28 09:56:35 +000011776 cp->nclist.body = list(2);
Eric Andersencb57d552001-06-28 07:25:16 +000011777
Eric Andersenc470f442003-07-28 09:56:35 +000011778 cpp = &cp->nclist.next;
11779
11780 checkkwd = CHKNL | CHKKWD;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011781 t = readtoken();
11782 if (t != TESAC) {
Eric Andersencb57d552001-06-28 07:25:16 +000011783 if (t != TENDCASE)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011784 raise_error_unexpected_syntax(TENDCASE);
11785 goto next_case;
Eric Andersencb57d552001-06-28 07:25:16 +000011786 }
Eric Andersenc470f442003-07-28 09:56:35 +000011787 }
Eric Andersencb57d552001-06-28 07:25:16 +000011788 *cpp = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +000011789 goto redir;
Eric Andersencb57d552001-06-28 07:25:16 +000011790 case TLP:
Denis Vlasenko597906c2008-02-20 16:38:54 +000011791 n1 = stzalloc(sizeof(struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +000011792 n1->type = NSUBSHELL;
Denys Vlasenko675d24a2018-01-27 22:02:05 +010011793 n1->nredir.linno = savelinno;
Eric Andersencb57d552001-06-28 07:25:16 +000011794 n1->nredir.n = list(0);
Denis Vlasenko597906c2008-02-20 16:38:54 +000011795 /*n1->nredir.redirect = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011796 t = TRP;
Eric Andersencb57d552001-06-28 07:25:16 +000011797 break;
11798 case TBEGIN:
11799 n1 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +000011800 t = TEND;
Eric Andersencb57d552001-06-28 07:25:16 +000011801 break;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011802 IF_BASH_FUNCTION(case TFUNCTION:)
Eric Andersencb57d552001-06-28 07:25:16 +000011803 case TWORD:
Eric Andersenc470f442003-07-28 09:56:35 +000011804 case TREDIR:
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011805 tokpushback = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000011806 return simplecmd();
Eric Andersencb57d552001-06-28 07:25:16 +000011807 }
11808
Eric Andersenc470f442003-07-28 09:56:35 +000011809 if (readtoken() != t)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011810 raise_error_unexpected_syntax(t);
Eric Andersenc470f442003-07-28 09:56:35 +000011811
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011812 redir:
Eric Andersencb57d552001-06-28 07:25:16 +000011813 /* Now check for redirection which may follow command */
Eric Andersenc470f442003-07-28 09:56:35 +000011814 checkkwd = CHKKWD | CHKALIAS;
11815 rpp = rpp2;
Eric Andersencb57d552001-06-28 07:25:16 +000011816 while (readtoken() == TREDIR) {
11817 *rpp = n2 = redirnode;
11818 rpp = &n2->nfile.next;
11819 parsefname();
11820 }
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011821 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011822 *rpp = NULL;
11823 if (redir) {
11824 if (n1->type != NSUBSHELL) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011825 n2 = stzalloc(sizeof(struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +000011826 n2->type = NREDIR;
Denys Vlasenko675d24a2018-01-27 22:02:05 +010011827 n2->nredir.linno = savelinno;
Eric Andersencb57d552001-06-28 07:25:16 +000011828 n2->nredir.n = n1;
11829 n1 = n2;
11830 }
11831 n1->nredir.redirect = redir;
11832 }
Eric Andersencb57d552001-06-28 07:25:16 +000011833 return n1;
11834}
11835
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011836#if BASH_DOLLAR_SQUOTE
Denys Vlasenko37dc08b2016-10-02 04:38:07 +020011837static int
11838decode_dollar_squote(void)
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011839{
11840 static const char C_escapes[] ALIGN1 = "nrbtfav""x\\01234567";
11841 int c, cnt;
11842 char *p;
11843 char buf[4];
11844
11845 c = pgetc();
11846 p = strchr(C_escapes, c);
11847 if (p) {
11848 buf[0] = c;
11849 p = buf;
11850 cnt = 3;
11851 if ((unsigned char)(c - '0') <= 7) { /* \ooo */
11852 do {
11853 c = pgetc();
11854 *++p = c;
11855 } while ((unsigned char)(c - '0') <= 7 && --cnt);
11856 pungetc();
11857 } else if (c == 'x') { /* \xHH */
11858 do {
11859 c = pgetc();
11860 *++p = c;
11861 } while (isxdigit(c) && --cnt);
11862 pungetc();
11863 if (cnt == 3) { /* \x but next char is "bad" */
11864 c = 'x';
11865 goto unrecognized;
11866 }
11867 } else { /* simple seq like \\ or \t */
11868 p++;
11869 }
11870 *p = '\0';
11871 p = buf;
11872 c = bb_process_escape_sequence((void*)&p);
11873 } else { /* unrecognized "\z": print both chars unless ' or " */
11874 if (c != '\'' && c != '"') {
11875 unrecognized:
11876 c |= 0x100; /* "please encode \, then me" */
11877 }
11878 }
11879 return c;
11880}
11881#endif
11882
Denys Vlasenko46999802017-07-29 21:12:29 +020011883/* Used by expandstr to get here-doc like behaviour. */
11884#define FAKEEOFMARK ((char*)(uintptr_t)1)
11885
11886static ALWAYS_INLINE int
11887realeofmark(const char *eofmark)
11888{
11889 return eofmark && eofmark != FAKEEOFMARK;
11890}
11891
Eric Andersencb57d552001-06-28 07:25:16 +000011892/*
11893 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
11894 * is not NULL, read a here document. In the latter case, eofmark is the
11895 * word which marks the end of the document and striptabs is true if
Denys Vlasenkocd716832009-11-28 22:14:02 +010011896 * leading tabs should be stripped from the document. The argument c
Eric Andersencb57d552001-06-28 07:25:16 +000011897 * is the first character of the input token or document.
11898 *
11899 * Because C does not have internal subroutines, I have simulated them
11900 * using goto's to implement the subroutine linkage. The following macros
11901 * will run code that appears at the end of readtoken1.
11902 */
Eric Andersen2870d962001-07-02 17:27:21 +000011903#define CHECKEND() {goto checkend; checkend_return:;}
11904#define PARSEREDIR() {goto parseredir; parseredir_return:;}
11905#define PARSESUB() {goto parsesub; parsesub_return:;}
11906#define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
11907#define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
11908#define PARSEARITH() {goto parsearith; parsearith_return:;}
Eric Andersencb57d552001-06-28 07:25:16 +000011909static int
Denys Vlasenkocd716832009-11-28 22:14:02 +010011910readtoken1(int c, int syntax, char *eofmark, int striptabs)
Manuel Novoa III 16815d42001-08-10 19:36:07 +000011911{
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011912 /* NB: syntax parameter fits into smallint */
Denys Vlasenkocd716832009-11-28 22:14:02 +010011913 /* c parameter is an unsigned char or PEOF or PEOA */
Eric Andersencb57d552001-06-28 07:25:16 +000011914 char *out;
Denys Vlasenko50e6d422016-09-30 11:35:54 +020011915 size_t len;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011916 struct nodelist *bqlist;
11917 smallint quotef;
11918 smallint dblquote;
11919 smallint oldstyle;
Denys Vlasenko0b883582016-12-23 16:49:07 +010011920 IF_FEATURE_SH_MATH(smallint prevsyntax;) /* syntax before arithmetic */
Denis Vlasenko46a53062007-09-24 18:30:02 +000011921 smallint pssyntax; /* we are expanding a prompt string */
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011922 int varnest; /* levels of variables expansion */
Denys Vlasenko0b883582016-12-23 16:49:07 +010011923 IF_FEATURE_SH_MATH(int arinest;) /* levels of arithmetic expansion */
11924 IF_FEATURE_SH_MATH(int parenlevel;) /* levels of parens in arithmetic */
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011925 int dqvarnest; /* levels of variables expansion within double quotes */
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011926 IF_BASH_DOLLAR_SQUOTE(smallint bash_dollar_squote = 0;)
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011927
Eric Andersencb57d552001-06-28 07:25:16 +000011928 bqlist = NULL;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011929 quotef = 0;
Denys Vlasenko0b883582016-12-23 16:49:07 +010011930 IF_FEATURE_SH_MATH(prevsyntax = 0;)
Denys Vlasenko5f0a75f2017-07-29 22:58:44 +020011931#if ENABLE_ASH_EXPAND_PRMT
Denis Vlasenko46a53062007-09-24 18:30:02 +000011932 pssyntax = (syntax == PSSYNTAX);
11933 if (pssyntax)
11934 syntax = DQSYNTAX;
Denys Vlasenko5f0a75f2017-07-29 22:58:44 +020011935#else
11936 pssyntax = 0; /* constant */
11937#endif
Denis Vlasenko46a53062007-09-24 18:30:02 +000011938 dblquote = (syntax == DQSYNTAX);
Eric Andersencb57d552001-06-28 07:25:16 +000011939 varnest = 0;
Denys Vlasenko0b883582016-12-23 16:49:07 +010011940 IF_FEATURE_SH_MATH(arinest = 0;)
11941 IF_FEATURE_SH_MATH(parenlevel = 0;)
Eric Andersencb57d552001-06-28 07:25:16 +000011942 dqvarnest = 0;
11943
11944 STARTSTACKSTR(out);
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011945 loop:
11946 /* For each line, until end of word */
Denys Vlasenko958581a2010-09-12 15:04:27 +020011947 CHECKEND(); /* set c to PEOF if at end of here document */
11948 for (;;) { /* until end of line or end of word */
11949 CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */
11950 switch (SIT(c, syntax)) {
11951 case CNL: /* '\n' */
11952 if (syntax == BASESYNTAX)
11953 goto endword; /* exit outer loop */
11954 USTPUTC(c, out);
Denys Vlasenkoce332a22016-10-02 23:47:34 +020011955 nlprompt();
Denys Vlasenko958581a2010-09-12 15:04:27 +020011956 c = pgetc();
11957 goto loop; /* continue outer loop */
11958 case CWORD:
11959 USTPUTC(c, out);
11960 break;
11961 case CCTL:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011962#if BASH_DOLLAR_SQUOTE
Denys Vlasenko958581a2010-09-12 15:04:27 +020011963 if (c == '\\' && bash_dollar_squote) {
11964 c = decode_dollar_squote();
Denys Vlasenko13f20912016-09-25 20:54:25 +020011965 if (c == '\0') {
11966 /* skip $'\000', $'\x00' (like bash) */
11967 break;
11968 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020011969 if (c & 0x100) {
Denys Vlasenko13f20912016-09-25 20:54:25 +020011970 /* Unknown escape. Encode as '\z' */
Denys Vlasenko958581a2010-09-12 15:04:27 +020011971 c = (unsigned char)c;
Denys Vlasenko13f20912016-09-25 20:54:25 +020011972 if (eofmark == NULL || dblquote)
11973 USTPUTC(CTLESC, out);
11974 USTPUTC('\\', out);
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011975 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020011976 }
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011977#endif
Denys Vlasenko13f20912016-09-25 20:54:25 +020011978 if (eofmark == NULL || dblquote)
11979 USTPUTC(CTLESC, out);
Denys Vlasenko958581a2010-09-12 15:04:27 +020011980 USTPUTC(c, out);
11981 break;
11982 case CBACK: /* backslash */
11983 c = pgetc_without_PEOA();
11984 if (c == PEOF) {
11985 USTPUTC(CTLESC, out);
11986 USTPUTC('\\', out);
11987 pungetc();
11988 } else if (c == '\n') {
Denys Vlasenkoce332a22016-10-02 23:47:34 +020011989 nlprompt();
Denys Vlasenko958581a2010-09-12 15:04:27 +020011990 } else {
Denys Vlasenko5f0a75f2017-07-29 22:58:44 +020011991 if (pssyntax && c == '$') {
Eric Andersenc470f442003-07-28 09:56:35 +000011992 USTPUTC(CTLESC, out);
Eric Andersencb57d552001-06-28 07:25:16 +000011993 USTPUTC('\\', out);
Denys Vlasenko958581a2010-09-12 15:04:27 +020011994 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020011995 /* Backslash is retained if we are in "str" and next char isn't special */
11996 if (dblquote
11997 && c != '\\'
11998 && c != '`'
11999 && c != '$'
12000 && (c != '"' || eofmark != NULL)
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000012001 ) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020012002 USTPUTC('\\', out);
Eric Andersencb57d552001-06-28 07:25:16 +000012003 }
Ron Yorston549deab2015-05-18 09:57:51 +020012004 USTPUTC(CTLESC, out);
Denys Vlasenko0ff78a02010-08-30 15:20:07 +020012005 USTPUTC(c, out);
Denys Vlasenko958581a2010-09-12 15:04:27 +020012006 quotef = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000012007 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020012008 break;
12009 case CSQUOTE:
12010 syntax = SQSYNTAX;
12011 quotemark:
12012 if (eofmark == NULL) {
12013 USTPUTC(CTLQUOTEMARK, out);
12014 }
12015 break;
12016 case CDQUOTE:
12017 syntax = DQSYNTAX;
12018 dblquote = 1;
12019 goto quotemark;
12020 case CENDQUOTE:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010012021 IF_BASH_DOLLAR_SQUOTE(bash_dollar_squote = 0;)
Ron Yorston7e4ed262015-05-18 09:54:43 +020012022 if (eofmark != NULL && varnest == 0) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020012023 USTPUTC(c, out);
12024 } else {
12025 if (dqvarnest == 0) {
12026 syntax = BASESYNTAX;
12027 dblquote = 0;
12028 }
12029 quotef = 1;
12030 goto quotemark;
12031 }
12032 break;
12033 case CVAR: /* '$' */
12034 PARSESUB(); /* parse substitution */
12035 break;
12036 case CENDVAR: /* '}' */
12037 if (varnest > 0) {
12038 varnest--;
12039 if (dqvarnest > 0) {
12040 dqvarnest--;
12041 }
12042 c = CTLENDVAR;
12043 }
12044 USTPUTC(c, out);
12045 break;
Denys Vlasenko0b883582016-12-23 16:49:07 +010012046#if ENABLE_FEATURE_SH_MATH
Denys Vlasenko958581a2010-09-12 15:04:27 +020012047 case CLP: /* '(' in arithmetic */
12048 parenlevel++;
12049 USTPUTC(c, out);
12050 break;
12051 case CRP: /* ')' in arithmetic */
12052 if (parenlevel > 0) {
12053 parenlevel--;
12054 } else {
Denys Vlasenko459293b2016-09-29 17:58:58 +020012055 if (pgetc_eatbnl() == ')') {
Ron Yorstonad88bde2015-05-18 09:56:16 +020012056 c = CTLENDARI;
Denys Vlasenko958581a2010-09-12 15:04:27 +020012057 if (--arinest == 0) {
12058 syntax = prevsyntax;
Denys Vlasenko958581a2010-09-12 15:04:27 +020012059 }
12060 } else {
12061 /*
12062 * unbalanced parens
12063 * (don't 2nd guess - no error)
12064 */
12065 pungetc();
12066 }
12067 }
12068 USTPUTC(c, out);
12069 break;
12070#endif
12071 case CBQUOTE: /* '`' */
12072 PARSEBACKQOLD();
12073 break;
12074 case CENDFILE:
12075 goto endword; /* exit outer loop */
12076 case CIGN:
12077 break;
12078 default:
12079 if (varnest == 0) {
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010012080#if BASH_REDIR_OUTPUT
Denys Vlasenko958581a2010-09-12 15:04:27 +020012081 if (c == '&') {
Denys Vlasenko459293b2016-09-29 17:58:58 +020012082//Can't call pgetc_eatbnl() here, this requires three-deep pungetc()
Denys Vlasenko958581a2010-09-12 15:04:27 +020012083 if (pgetc() == '>')
12084 c = 0x100 + '>'; /* flag &> */
12085 pungetc();
12086 }
12087#endif
12088 goto endword; /* exit outer loop */
12089 }
12090 IF_ASH_ALIAS(if (c != PEOA))
12091 USTPUTC(c, out);
12092 }
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020012093 c = pgetc();
Denys Vlasenko958581a2010-09-12 15:04:27 +020012094 } /* for (;;) */
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000012095 endword:
Denys Vlasenko958581a2010-09-12 15:04:27 +020012096
Denys Vlasenko0b883582016-12-23 16:49:07 +010012097#if ENABLE_FEATURE_SH_MATH
Eric Andersencb57d552001-06-28 07:25:16 +000012098 if (syntax == ARISYNTAX)
Denis Vlasenko559691a2008-10-05 18:39:31 +000012099 raise_error_syntax("missing '))'");
Eric Andersenc470f442003-07-28 09:56:35 +000012100#endif
Ron Yorston0e056f72015-07-01 16:45:40 +010012101 if (syntax != BASESYNTAX && eofmark == NULL)
Denis Vlasenko559691a2008-10-05 18:39:31 +000012102 raise_error_syntax("unterminated quoted string");
Eric Andersencb57d552001-06-28 07:25:16 +000012103 if (varnest != 0) {
Eric Andersenc470f442003-07-28 09:56:35 +000012104 /* { */
Denis Vlasenko559691a2008-10-05 18:39:31 +000012105 raise_error_syntax("missing '}'");
Eric Andersencb57d552001-06-28 07:25:16 +000012106 }
12107 USTPUTC('\0', out);
Eric Andersenc470f442003-07-28 09:56:35 +000012108 len = out - (char *)stackblock();
Eric Andersencb57d552001-06-28 07:25:16 +000012109 out = stackblock();
12110 if (eofmark == NULL) {
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010012111 if ((c == '>' || c == '<' IF_BASH_REDIR_OUTPUT( || c == 0x100 + '>'))
Denis Vlasenko834dee72008-10-07 09:18:30 +000012112 && quotef == 0
12113 ) {
Denis Vlasenko559691a2008-10-05 18:39:31 +000012114 if (isdigit_str9(out)) {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000012115 PARSEREDIR(); /* passed as params: out, c */
12116 lasttoken = TREDIR;
12117 return lasttoken;
12118 }
12119 /* else: non-number X seen, interpret it
12120 * as "NNNX>file" = "NNNX >file" */
Eric Andersencb57d552001-06-28 07:25:16 +000012121 }
Denis Vlasenkoef527f52008-06-23 01:52:30 +000012122 pungetc();
Eric Andersencb57d552001-06-28 07:25:16 +000012123 }
12124 quoteflag = quotef;
12125 backquotelist = bqlist;
12126 grabstackblock(len);
12127 wordtext = out;
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000012128 lasttoken = TWORD;
12129 return lasttoken;
Eric Andersencb57d552001-06-28 07:25:16 +000012130/* end of readtoken routine */
12131
Eric Andersencb57d552001-06-28 07:25:16 +000012132/*
12133 * Check to see whether we are at the end of the here document. When this
12134 * is called, c is set to the first character of the next input line. If
12135 * we are at the end of the here document, this routine sets the c to PEOF.
12136 */
Eric Andersenc470f442003-07-28 09:56:35 +000012137checkend: {
Denys Vlasenko46999802017-07-29 21:12:29 +020012138 if (realeofmark(eofmark)) {
Denys Vlasenkoa7328982017-07-29 19:57:28 +020012139 int markloc;
12140 char *p;
12141
Denis Vlasenko131ae172007-02-18 13:00:19 +000012142#if ENABLE_ASH_ALIAS
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010012143 if (c == PEOA)
12144 c = pgetc_without_PEOA();
Eric Andersenc470f442003-07-28 09:56:35 +000012145#endif
12146 if (striptabs) {
12147 while (c == '\t') {
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010012148 c = pgetc_without_PEOA();
Eric Andersencb57d552001-06-28 07:25:16 +000012149 }
Eric Andersenc470f442003-07-28 09:56:35 +000012150 }
Eric Andersencb57d552001-06-28 07:25:16 +000012151
Denys Vlasenkoa7328982017-07-29 19:57:28 +020012152 markloc = out - (char *)stackblock();
12153 for (p = eofmark; STPUTC(c, out), *p; p++) {
12154 if (c != *p)
12155 goto more_heredoc;
12156
12157 c = pgetc_without_PEOA();
12158 }
12159
12160 if (c == '\n' || c == PEOF) {
12161 c = PEOF;
12162 g_parsefile->linno++;
12163 needprompt = doprompt;
12164 } else {
12165 int len_here;
12166
12167 more_heredoc:
12168 p = (char *)stackblock() + markloc + 1;
12169 len_here = out - p;
12170
12171 if (len_here) {
12172 len_here -= (c >= PEOF);
12173 c = p[-1];
12174
12175 if (len_here) {
12176 char *str;
12177
12178 str = alloca(len_here + 1);
12179 *(char *)mempcpy(str, p, len_here) = '\0';
12180
12181 pushstring(str, NULL);
Eric Andersencb57d552001-06-28 07:25:16 +000012182 }
12183 }
12184 }
Denys Vlasenkoa7328982017-07-29 19:57:28 +020012185
12186 STADJUST((char *)stackblock() + markloc - out, out);
Eric Andersencb57d552001-06-28 07:25:16 +000012187 }
Eric Andersenc470f442003-07-28 09:56:35 +000012188 goto checkend_return;
12189}
Eric Andersencb57d552001-06-28 07:25:16 +000012190
Eric Andersencb57d552001-06-28 07:25:16 +000012191/*
12192 * Parse a redirection operator. The variable "out" points to a string
12193 * specifying the fd to be redirected. The variable "c" contains the
12194 * first character of the redirection operator.
12195 */
Eric Andersenc470f442003-07-28 09:56:35 +000012196parseredir: {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000012197 /* out is already checked to be a valid number or "" */
12198 int fd = (*out == '\0' ? -1 : atoi(out));
Eric Andersenc470f442003-07-28 09:56:35 +000012199 union node *np;
Eric Andersencb57d552001-06-28 07:25:16 +000012200
Denis Vlasenko597906c2008-02-20 16:38:54 +000012201 np = stzalloc(sizeof(struct nfile));
Eric Andersenc470f442003-07-28 09:56:35 +000012202 if (c == '>') {
12203 np->nfile.fd = 1;
12204 c = pgetc();
12205 if (c == '>')
12206 np->type = NAPPEND;
12207 else if (c == '|')
12208 np->type = NCLOBBER;
12209 else if (c == '&')
12210 np->type = NTOFD;
Denis Vlasenko559691a2008-10-05 18:39:31 +000012211 /* it also can be NTO2 (>&file), but we can't figure it out yet */
Eric Andersenc470f442003-07-28 09:56:35 +000012212 else {
12213 np->type = NTO;
12214 pungetc();
Eric Andersencb57d552001-06-28 07:25:16 +000012215 }
Denis Vlasenko834dee72008-10-07 09:18:30 +000012216 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010012217#if BASH_REDIR_OUTPUT
Denis Vlasenko834dee72008-10-07 09:18:30 +000012218 else if (c == 0x100 + '>') { /* this flags &> redirection */
12219 np->nfile.fd = 1;
12220 pgetc(); /* this is '>', no need to check */
12221 np->type = NTO2;
12222 }
12223#endif
12224 else { /* c == '<' */
Denis Vlasenko597906c2008-02-20 16:38:54 +000012225 /*np->nfile.fd = 0; - stzalloc did it */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000012226 c = pgetc();
12227 switch (c) {
Eric Andersenc470f442003-07-28 09:56:35 +000012228 case '<':
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000012229 if (sizeof(struct nfile) != sizeof(struct nhere)) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000012230 np = stzalloc(sizeof(struct nhere));
12231 /*np->nfile.fd = 0; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000012232 }
12233 np->type = NHERE;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000012234 heredoc = stzalloc(sizeof(struct heredoc));
Eric Andersenc470f442003-07-28 09:56:35 +000012235 heredoc->here = np;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000012236 c = pgetc();
12237 if (c == '-') {
Eric Andersenc470f442003-07-28 09:56:35 +000012238 heredoc->striptabs = 1;
12239 } else {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000012240 /*heredoc->striptabs = 0; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000012241 pungetc();
12242 }
12243 break;
12244
12245 case '&':
12246 np->type = NFROMFD;
12247 break;
12248
12249 case '>':
12250 np->type = NFROMTO;
12251 break;
12252
12253 default:
12254 np->type = NFROM;
12255 pungetc();
12256 break;
12257 }
Eric Andersencb57d552001-06-28 07:25:16 +000012258 }
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000012259 if (fd >= 0)
12260 np->nfile.fd = fd;
Eric Andersenc470f442003-07-28 09:56:35 +000012261 redirnode = np;
12262 goto parseredir_return;
12263}
Eric Andersencb57d552001-06-28 07:25:16 +000012264
Eric Andersencb57d552001-06-28 07:25:16 +000012265/*
12266 * Parse a substitution. At this point, we have read the dollar sign
12267 * and nothing else.
12268 */
Denis Vlasenkocc571512007-02-23 21:10:35 +000012269
12270/* is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise
12271 * (assuming ascii char codes, as the original implementation did) */
12272#define is_special(c) \
Denis Vlasenkoef527f52008-06-23 01:52:30 +000012273 (((unsigned)(c) - 33 < 32) \
12274 && ((0xc1ff920dU >> ((unsigned)(c) - 33)) & 1))
Eric Andersenc470f442003-07-28 09:56:35 +000012275parsesub: {
Denys Vlasenkocd716832009-11-28 22:14:02 +010012276 unsigned char subtype;
Eric Andersenc470f442003-07-28 09:56:35 +000012277 int typeloc;
Eric Andersencb57d552001-06-28 07:25:16 +000012278
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012279 c = pgetc_eatbnl();
Denys Vlasenkoa7328982017-07-29 19:57:28 +020012280 if ((checkkwd & CHKEOFMARK)
12281 || c > 255 /* PEOA or PEOF */
Denis Vlasenkoef527f52008-06-23 01:52:30 +000012282 || (c != '(' && c != '{' && !is_name(c) && !is_special(c))
Eric Andersenc470f442003-07-28 09:56:35 +000012283 ) {
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010012284#if BASH_DOLLAR_SQUOTE
Ron Yorston84ba50c2016-04-03 22:43:14 +010012285 if (syntax != DQSYNTAX && c == '\'')
Denis Vlasenkoef527f52008-06-23 01:52:30 +000012286 bash_dollar_squote = 1;
12287 else
12288#endif
12289 USTPUTC('$', out);
Eric Andersenc470f442003-07-28 09:56:35 +000012290 pungetc();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012291 } else if (c == '(') {
12292 /* $(command) or $((arith)) */
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012293 if (pgetc_eatbnl() == '(') {
Denys Vlasenko0b883582016-12-23 16:49:07 +010012294#if ENABLE_FEATURE_SH_MATH
Eric Andersenc470f442003-07-28 09:56:35 +000012295 PARSEARITH();
12296#else
Denys Vlasenko4f8079d2017-07-17 17:11:48 +020012297 raise_error_syntax("support for $((arith)) is disabled");
Eric Andersenc470f442003-07-28 09:56:35 +000012298#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012299 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000012300 pungetc();
12301 PARSEBACKQNEW();
12302 }
12303 } else {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012304 /* $VAR, $<specialchar>, ${...}, or PEOA/PEOF */
Eric Andersenc470f442003-07-28 09:56:35 +000012305 USTPUTC(CTLVAR, out);
12306 typeloc = out - (char *)stackblock();
Denys Vlasenko3df14102016-10-26 16:41:13 +020012307 STADJUST(1, out);
Eric Andersenc470f442003-07-28 09:56:35 +000012308 subtype = VSNORMAL;
12309 if (c == '{') {
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012310 c = pgetc_eatbnl();
Denys Vlasenkof15aa572016-10-26 15:56:53 +020012311 subtype = 0;
Eric Andersenc470f442003-07-28 09:56:35 +000012312 }
Denys Vlasenkof15aa572016-10-26 15:56:53 +020012313 varname:
Denys Vlasenko3df14102016-10-26 16:41:13 +020012314 if (is_name(c)) {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012315 /* $[{[#]]NAME[}] */
Eric Andersenc470f442003-07-28 09:56:35 +000012316 do {
12317 STPUTC(c, out);
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012318 c = pgetc_eatbnl();
Denys Vlasenko3df14102016-10-26 16:41:13 +020012319 } while (is_in_name(c));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012320 } else if (isdigit(c)) {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012321 /* $[{[#]]NUM[}] */
Eric Andersenc470f442003-07-28 09:56:35 +000012322 do {
12323 STPUTC(c, out);
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012324 c = pgetc_eatbnl();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012325 } while (isdigit(c));
Denys Vlasenko452cc1d2017-08-14 14:23:45 +020012326 } else {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012327 /* $[{[#]]<specialchar>[}] */
Denys Vlasenkof15aa572016-10-26 15:56:53 +020012328 int cc = c;
12329
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012330 c = pgetc_eatbnl();
Denys Vlasenkof15aa572016-10-26 15:56:53 +020012331 if (!subtype && cc == '#') {
12332 subtype = VSLENGTH;
12333 if (c == '_' || isalnum(c))
12334 goto varname;
12335 cc = c;
12336 c = pgetc_eatbnl();
12337 if (cc == '}' || c != '}') {
12338 pungetc();
12339 subtype = 0;
12340 c = cc;
12341 cc = '#';
12342 }
12343 }
Denys Vlasenko452cc1d2017-08-14 14:23:45 +020012344
12345 if (!is_special(cc)) {
12346 if (subtype == VSLENGTH)
12347 subtype = 0;
12348 goto badsub;
12349 }
12350
Denys Vlasenkof15aa572016-10-26 15:56:53 +020012351 USTPUTC(cc, out);
Denis Vlasenko559691a2008-10-05 18:39:31 +000012352 }
Denys Vlasenko452cc1d2017-08-14 14:23:45 +020012353
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012354 if (c != '}' && subtype == VSLENGTH) {
12355 /* ${#VAR didn't end with } */
Cristian Ionescu-Idbohrn301f5ec2009-10-05 02:07:23 +020012356 goto badsub;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012357 }
Eric Andersencb57d552001-06-28 07:25:16 +000012358
Eric Andersenc470f442003-07-28 09:56:35 +000012359 if (subtype == 0) {
Denys Vlasenkof8ddbe12016-07-25 03:56:00 +020012360 static const char types[] ALIGN1 = "}-+?=";
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012361 /* ${VAR...} but not $VAR or ${#VAR} */
12362 /* c == first char after VAR */
Eric Andersenc470f442003-07-28 09:56:35 +000012363 switch (c) {
12364 case ':':
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012365 c = pgetc_eatbnl();
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010012366#if BASH_SUBSTR
Denys Vlasenkof8ddbe12016-07-25 03:56:00 +020012367 /* This check is only needed to not misinterpret
12368 * ${VAR:-WORD}, ${VAR:+WORD}, ${VAR:=WORD}, ${VAR:?WORD}
12369 * constructs.
12370 */
12371 if (!strchr(types, c)) {
Denis Vlasenko92e13c22008-03-25 01:17:40 +000012372 subtype = VSSUBSTR;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012373 pungetc();
Denys Vlasenko88e15702016-10-26 01:55:56 +020012374 break; /* "goto badsub" is bigger (!) */
Denis Vlasenko92e13c22008-03-25 01:17:40 +000012375 }
12376#endif
Denys Vlasenko3df14102016-10-26 16:41:13 +020012377 subtype = VSNUL;
Eric Andersenc470f442003-07-28 09:56:35 +000012378 /*FALLTHROUGH*/
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012379 default: {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012380 const char *p = strchr(types, c);
Eric Andersenc470f442003-07-28 09:56:35 +000012381 if (p == NULL)
Denys Vlasenko88e15702016-10-26 01:55:56 +020012382 break;
Denys Vlasenko3df14102016-10-26 16:41:13 +020012383 subtype |= p - types + VSNORMAL;
Eric Andersenc470f442003-07-28 09:56:35 +000012384 break;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012385 }
Eric Andersenc470f442003-07-28 09:56:35 +000012386 case '%':
Denis Vlasenko92e13c22008-03-25 01:17:40 +000012387 case '#': {
12388 int cc = c;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012389 subtype = (c == '#' ? VSTRIMLEFT : VSTRIMRIGHT);
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012390 c = pgetc_eatbnl();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012391 if (c != cc)
Denys Vlasenko88e15702016-10-26 01:55:56 +020012392 goto badsub;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012393 subtype++;
Denis Vlasenko92e13c22008-03-25 01:17:40 +000012394 break;
12395 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010012396#if BASH_PATTERN_SUBST
Denis Vlasenko92e13c22008-03-25 01:17:40 +000012397 case '/':
Denys Vlasenko6040fe82010-09-12 15:03:16 +020012398 /* ${v/[/]pattern/repl} */
12399//TODO: encode pattern and repl separately.
12400// Currently ${v/$var_with_slash/repl} is horribly broken
Denis Vlasenko92e13c22008-03-25 01:17:40 +000012401 subtype = VSREPLACE;
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012402 c = pgetc_eatbnl();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012403 if (c != '/')
Denys Vlasenko88e15702016-10-26 01:55:56 +020012404 goto badsub;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012405 subtype++; /* VSREPLACEALL */
Denis Vlasenko92e13c22008-03-25 01:17:40 +000012406 break;
12407#endif
Eric Andersencb57d552001-06-28 07:25:16 +000012408 }
Eric Andersenc470f442003-07-28 09:56:35 +000012409 } else {
Denys Vlasenko88e15702016-10-26 01:55:56 +020012410 badsub:
Eric Andersenc470f442003-07-28 09:56:35 +000012411 pungetc();
12412 }
Denys Vlasenko3df14102016-10-26 16:41:13 +020012413 ((unsigned char *)stackblock())[typeloc] = subtype;
Eric Andersenc470f442003-07-28 09:56:35 +000012414 if (subtype != VSNORMAL) {
12415 varnest++;
Denys Vlasenko3df14102016-10-26 16:41:13 +020012416 if (dblquote)
Eric Andersenc470f442003-07-28 09:56:35 +000012417 dqvarnest++;
Eric Andersencb57d552001-06-28 07:25:16 +000012418 }
Denys Vlasenko88e15702016-10-26 01:55:56 +020012419 STPUTC('=', out);
Eric Andersencb57d552001-06-28 07:25:16 +000012420 }
Eric Andersenc470f442003-07-28 09:56:35 +000012421 goto parsesub_return;
12422}
Eric Andersencb57d552001-06-28 07:25:16 +000012423
Eric Andersencb57d552001-06-28 07:25:16 +000012424/*
12425 * Called to parse command substitutions. Newstyle is set if the command
12426 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
12427 * list of commands (passed by reference), and savelen is the number of
12428 * characters on the top of the stack which must be preserved.
12429 */
Eric Andersenc470f442003-07-28 09:56:35 +000012430parsebackq: {
12431 struct nodelist **nlpp;
Eric Andersenc470f442003-07-28 09:56:35 +000012432 union node *n;
Ron Yorston072fc602015-07-01 16:46:18 +010012433 char *str;
Eric Andersenc470f442003-07-28 09:56:35 +000012434 size_t savelen;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000012435 smallint saveprompt = 0;
12436
Eric Andersenc470f442003-07-28 09:56:35 +000012437 str = NULL;
12438 savelen = out - (char *)stackblock();
12439 if (savelen > 0) {
Denys Vlasenko7bc3d392016-09-17 20:53:47 +020012440 /*
12441 * FIXME: this can allocate very large block on stack and SEGV.
12442 * Example:
12443 * echo "..<100kbytes>..`true` $(true) `true` ..."
Denys Vlasenko73737592016-09-17 20:58:22 +020012444 * allocates 100kb for every command subst. With about
Denys Vlasenko7bc3d392016-09-17 20:53:47 +020012445 * a hundred command substitutions stack overflows.
12446 * With larger prepended string, SEGV happens sooner.
12447 */
Ron Yorston072fc602015-07-01 16:46:18 +010012448 str = alloca(savelen);
Eric Andersenc470f442003-07-28 09:56:35 +000012449 memcpy(str, stackblock(), savelen);
12450 }
Denys Vlasenko7bc3d392016-09-17 20:53:47 +020012451
Eric Andersenc470f442003-07-28 09:56:35 +000012452 if (oldstyle) {
12453 /* We must read until the closing backquote, giving special
Denys Vlasenko60cb48c2013-01-14 15:57:44 +010012454 * treatment to some slashes, and then push the string and
12455 * reread it as input, interpreting it normally.
12456 */
Eric Andersenc470f442003-07-28 09:56:35 +000012457 char *pout;
Eric Andersenc470f442003-07-28 09:56:35 +000012458 size_t psavelen;
12459 char *pstr;
12460
Eric Andersenc470f442003-07-28 09:56:35 +000012461 STARTSTACKSTR(pout);
12462 for (;;) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020012463 int pc;
12464
12465 setprompt_if(needprompt, 2);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000012466 pc = pgetc();
12467 switch (pc) {
Eric Andersenc470f442003-07-28 09:56:35 +000012468 case '`':
12469 goto done;
12470
12471 case '\\':
Denis Vlasenko5cedb752007-02-18 19:56:41 +000012472 pc = pgetc();
12473 if (pc == '\n') {
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012474 nlprompt();
Eric Andersenc470f442003-07-28 09:56:35 +000012475 /*
12476 * If eating a newline, avoid putting
12477 * the newline into the new character
12478 * stream (via the STPUTC after the
12479 * switch).
12480 */
12481 continue;
12482 }
12483 if (pc != '\\' && pc != '`' && pc != '$'
Denys Vlasenko76bc2d62009-11-29 01:37:46 +010012484 && (!dblquote || pc != '"')
12485 ) {
Eric Andersenc470f442003-07-28 09:56:35 +000012486 STPUTC('\\', pout);
Denys Vlasenko76bc2d62009-11-29 01:37:46 +010012487 }
Denys Vlasenkocd716832009-11-28 22:14:02 +010012488 if (pc <= 255 /* not PEOA or PEOF */) {
Eric Andersenc470f442003-07-28 09:56:35 +000012489 break;
12490 }
12491 /* fall through */
12492
12493 case PEOF:
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010012494 IF_ASH_ALIAS(case PEOA:)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000012495 raise_error_syntax("EOF in backquote substitution");
Eric Andersenc470f442003-07-28 09:56:35 +000012496
12497 case '\n':
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012498 nlnoprompt();
Eric Andersenc470f442003-07-28 09:56:35 +000012499 break;
12500
12501 default:
12502 break;
12503 }
12504 STPUTC(pc, pout);
12505 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +000012506 done:
Eric Andersenc470f442003-07-28 09:56:35 +000012507 STPUTC('\0', pout);
12508 psavelen = pout - (char *)stackblock();
12509 if (psavelen > 0) {
12510 pstr = grabstackstr(pout);
12511 setinputstring(pstr);
12512 }
12513 }
12514 nlpp = &bqlist;
12515 while (*nlpp)
12516 nlpp = &(*nlpp)->next;
Denis Vlasenko597906c2008-02-20 16:38:54 +000012517 *nlpp = stzalloc(sizeof(**nlpp));
12518 /* (*nlpp)->next = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000012519
12520 if (oldstyle) {
12521 saveprompt = doprompt;
12522 doprompt = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000012523 }
12524
Eric Andersenc470f442003-07-28 09:56:35 +000012525 n = list(2);
12526
12527 if (oldstyle)
12528 doprompt = saveprompt;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012529 else if (readtoken() != TRP)
12530 raise_error_unexpected_syntax(TRP);
Eric Andersenc470f442003-07-28 09:56:35 +000012531
12532 (*nlpp)->n = n;
12533 if (oldstyle) {
12534 /*
12535 * Start reading from old file again, ignoring any pushed back
12536 * tokens left from the backquote parsing
12537 */
12538 popfile();
12539 tokpushback = 0;
12540 }
12541 while (stackblocksize() <= savelen)
12542 growstackblock();
12543 STARTSTACKSTR(out);
12544 if (str) {
12545 memcpy(out, str, savelen);
12546 STADJUST(savelen, out);
Eric Andersenc470f442003-07-28 09:56:35 +000012547 }
Ron Yorston549deab2015-05-18 09:57:51 +020012548 USTPUTC(CTLBACKQ, out);
Eric Andersenc470f442003-07-28 09:56:35 +000012549 if (oldstyle)
12550 goto parsebackq_oldreturn;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000012551 goto parsebackq_newreturn;
Eric Andersenc470f442003-07-28 09:56:35 +000012552}
12553
Denys Vlasenko0b883582016-12-23 16:49:07 +010012554#if ENABLE_FEATURE_SH_MATH
Eric Andersencb57d552001-06-28 07:25:16 +000012555/*
12556 * Parse an arithmetic expansion (indicate start of one and set state)
12557 */
Eric Andersenc470f442003-07-28 09:56:35 +000012558parsearith: {
Eric Andersenc470f442003-07-28 09:56:35 +000012559 if (++arinest == 1) {
12560 prevsyntax = syntax;
12561 syntax = ARISYNTAX;
Eric Andersencb57d552001-06-28 07:25:16 +000012562 }
Ron Yorstonad88bde2015-05-18 09:56:16 +020012563 USTPUTC(CTLARI, out);
Eric Andersenc470f442003-07-28 09:56:35 +000012564 goto parsearith_return;
12565}
12566#endif
Eric Andersenc470f442003-07-28 09:56:35 +000012567} /* end of readtoken */
12568
Eric Andersencb57d552001-06-28 07:25:16 +000012569/*
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012570 * Read the next input token.
12571 * If the token is a word, we set backquotelist to the list of cmds in
12572 * backquotes. We set quoteflag to true if any part of the word was
12573 * quoted.
12574 * If the token is TREDIR, then we set redirnode to a structure containing
12575 * the redirection.
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012576 *
12577 * [Change comment: here documents and internal procedures]
12578 * [Readtoken shouldn't have any arguments. Perhaps we should make the
12579 * word parsing code into a separate routine. In this case, readtoken
12580 * doesn't need to have any internal procedures, but parseword does.
12581 * We could also make parseoperator in essence the main routine, and
12582 * have parseword (readtoken1?) handle both words and redirection.]
Eric Andersencb57d552001-06-28 07:25:16 +000012583 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012584#define NEW_xxreadtoken
12585#ifdef NEW_xxreadtoken
12586/* singles must be first! */
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000012587static const char xxreadtoken_chars[7] ALIGN1 = {
Denis Vlasenko834dee72008-10-07 09:18:30 +000012588 '\n', '(', ')', /* singles */
12589 '&', '|', ';', /* doubles */
12590 0
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000012591};
Eric Andersencb57d552001-06-28 07:25:16 +000012592
Denis Vlasenko834dee72008-10-07 09:18:30 +000012593#define xxreadtoken_singles 3
12594#define xxreadtoken_doubles 3
12595
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000012596static const char xxreadtoken_tokens[] ALIGN1 = {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012597 TNL, TLP, TRP, /* only single occurrence allowed */
12598 TBACKGND, TPIPE, TSEMI, /* if single occurrence */
12599 TEOF, /* corresponds to trailing nul */
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000012600 TAND, TOR, TENDCASE /* if double occurrence */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012601};
12602
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012603static int
12604xxreadtoken(void)
12605{
12606 int c;
12607
12608 if (tokpushback) {
12609 tokpushback = 0;
12610 return lasttoken;
Eric Andersencb57d552001-06-28 07:25:16 +000012611 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020012612 setprompt_if(needprompt, 2);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012613 for (;;) { /* until token or start of word found */
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020012614 c = pgetc();
Denis Vlasenko5e34ff22009-04-21 11:09:40 +000012615 if (c == ' ' || c == '\t' IF_ASH_ALIAS( || c == PEOA))
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012616 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012617
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012618 if (c == '#') {
12619 while ((c = pgetc()) != '\n' && c != PEOF)
12620 continue;
12621 pungetc();
12622 } else if (c == '\\') {
12623 if (pgetc() != '\n') {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012624 pungetc();
Denis Vlasenko834dee72008-10-07 09:18:30 +000012625 break; /* return readtoken1(...) */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012626 }
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012627 nlprompt();
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012628 } else {
12629 const char *p;
12630
12631 p = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
12632 if (c != PEOF) {
12633 if (c == '\n') {
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012634 nlnoprompt();
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012635 }
12636
12637 p = strchr(xxreadtoken_chars, c);
Denis Vlasenko834dee72008-10-07 09:18:30 +000012638 if (p == NULL)
12639 break; /* return readtoken1(...) */
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012640
Denis Vlasenko834dee72008-10-07 09:18:30 +000012641 if ((int)(p - xxreadtoken_chars) >= xxreadtoken_singles) {
12642 int cc = pgetc();
12643 if (cc == c) { /* double occurrence? */
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012644 p += xxreadtoken_doubles + 1;
12645 } else {
12646 pungetc();
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010012647#if BASH_REDIR_OUTPUT
Denis Vlasenko834dee72008-10-07 09:18:30 +000012648 if (c == '&' && cc == '>') /* &> */
12649 break; /* return readtoken1(...) */
12650#endif
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012651 }
12652 }
12653 }
12654 lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
12655 return lasttoken;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012656 }
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012657 } /* for (;;) */
Denis Vlasenko834dee72008-10-07 09:18:30 +000012658
12659 return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012660}
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012661#else /* old xxreadtoken */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012662#define RETURN(token) return lasttoken = token
12663static int
12664xxreadtoken(void)
12665{
12666 int c;
12667
12668 if (tokpushback) {
12669 tokpushback = 0;
12670 return lasttoken;
12671 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020012672 setprompt_if(needprompt, 2);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012673 for (;;) { /* until token or start of word found */
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020012674 c = pgetc();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012675 switch (c) {
12676 case ' ': case '\t':
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010012677 IF_ASH_ALIAS(case PEOA:)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012678 continue;
12679 case '#':
Denis Vlasenkof7d56652008-03-25 05:51:41 +000012680 while ((c = pgetc()) != '\n' && c != PEOF)
12681 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012682 pungetc();
12683 continue;
12684 case '\\':
12685 if (pgetc() == '\n') {
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012686 nlprompt();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012687 continue;
12688 }
12689 pungetc();
12690 goto breakloop;
12691 case '\n':
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012692 nlnoprompt();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012693 RETURN(TNL);
12694 case PEOF:
12695 RETURN(TEOF);
12696 case '&':
12697 if (pgetc() == '&')
12698 RETURN(TAND);
12699 pungetc();
12700 RETURN(TBACKGND);
12701 case '|':
12702 if (pgetc() == '|')
12703 RETURN(TOR);
12704 pungetc();
12705 RETURN(TPIPE);
12706 case ';':
12707 if (pgetc() == ';')
12708 RETURN(TENDCASE);
12709 pungetc();
12710 RETURN(TSEMI);
12711 case '(':
12712 RETURN(TLP);
12713 case ')':
12714 RETURN(TRP);
12715 default:
12716 goto breakloop;
12717 }
12718 }
12719 breakloop:
12720 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
12721#undef RETURN
12722}
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012723#endif /* old xxreadtoken */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012724
12725static int
12726readtoken(void)
12727{
12728 int t;
Ron Yorston713f07d2015-10-29 16:44:56 +000012729 int kwd = checkkwd;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012730#if DEBUG
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000012731 smallint alreadyseen = tokpushback;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012732#endif
12733
12734#if ENABLE_ASH_ALIAS
12735 top:
12736#endif
12737
12738 t = xxreadtoken();
12739
12740 /*
12741 * eat newlines
12742 */
Ron Yorston713f07d2015-10-29 16:44:56 +000012743 if (kwd & CHKNL) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012744 while (t == TNL) {
12745 parseheredoc();
12746 t = xxreadtoken();
12747 }
12748 }
12749
12750 if (t != TWORD || quoteflag) {
12751 goto out;
12752 }
12753
12754 /*
12755 * check for keywords
12756 */
Ron Yorston713f07d2015-10-29 16:44:56 +000012757 if (kwd & CHKKWD) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012758 const char *const *pp;
12759
12760 pp = findkwd(wordtext);
12761 if (pp) {
12762 lasttoken = t = pp - tokname_array;
Denys Vlasenko888527c2016-10-02 16:54:17 +020012763 TRACE(("keyword '%s' recognized\n", tokname_array[t]));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012764 goto out;
12765 }
12766 }
12767
12768 if (checkkwd & CHKALIAS) {
12769#if ENABLE_ASH_ALIAS
12770 struct alias *ap;
12771 ap = lookupalias(wordtext, 1);
12772 if (ap != NULL) {
12773 if (*ap->val) {
12774 pushstring(ap->val, ap);
12775 }
12776 goto top;
12777 }
12778#endif
12779 }
12780 out:
12781 checkkwd = 0;
12782#if DEBUG
12783 if (!alreadyseen)
Denys Vlasenko888527c2016-10-02 16:54:17 +020012784 TRACE(("token '%s' %s\n", tokname_array[t], t == TWORD ? wordtext : ""));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012785 else
Denys Vlasenko888527c2016-10-02 16:54:17 +020012786 TRACE(("reread token '%s' %s\n", tokname_array[t], t == TWORD ? wordtext : ""));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012787#endif
12788 return t;
Eric Andersencb57d552001-06-28 07:25:16 +000012789}
12790
Ron Yorstonc0e00762015-10-29 11:30:55 +000012791static int
Ron Yorston6bd2fab2015-10-29 11:30:22 +000012792peektoken(void)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012793{
12794 int t;
12795
12796 t = readtoken();
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000012797 tokpushback = 1;
Ron Yorstonc0e00762015-10-29 11:30:55 +000012798 return t;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012799}
Eric Andersencb57d552001-06-28 07:25:16 +000012800
12801/*
Denys Vlasenko86e83ec2009-07-23 22:07:07 +020012802 * Read and parse a command. Returns NODE_EOF on end of file.
12803 * (NULL is a valid parse tree indicating a blank line.)
Eric Andersencb57d552001-06-28 07:25:16 +000012804 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012805static union node *
12806parsecmd(int interact)
Eric Andersen90898442003-08-06 11:20:52 +000012807{
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012808 tokpushback = 0;
Ron Yorstonc0e00762015-10-29 11:30:55 +000012809 checkkwd = 0;
12810 heredoclist = 0;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012811 doprompt = interact;
Denys Vlasenko958581a2010-09-12 15:04:27 +020012812 setprompt_if(doprompt, doprompt);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012813 needprompt = 0;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012814 return list(1);
12815}
12816
12817/*
12818 * Input any here documents.
12819 */
12820static void
12821parseheredoc(void)
12822{
12823 struct heredoc *here;
12824 union node *n;
12825
12826 here = heredoclist;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000012827 heredoclist = NULL;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012828
12829 while (here) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020012830 setprompt_if(needprompt, 2);
12831 readtoken1(pgetc(), here->here->type == NHERE ? SQSYNTAX : DQSYNTAX,
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012832 here->eofmark, here->striptabs);
Denis Vlasenko597906c2008-02-20 16:38:54 +000012833 n = stzalloc(sizeof(struct narg));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012834 n->narg.type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000012835 /*n->narg.next = NULL; - stzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012836 n->narg.text = wordtext;
12837 n->narg.backquote = backquotelist;
12838 here->here->nhere.doc = n;
12839 here = here->next;
Eric Andersencb57d552001-06-28 07:25:16 +000012840 }
Eric Andersencb57d552001-06-28 07:25:16 +000012841}
12842
12843
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012844static const char *
Denys Vlasenko46999802017-07-29 21:12:29 +020012845expandstr(const char *ps, int syntax_type)
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012846{
12847 union node n;
Denys Vlasenko2a6d29a2016-10-25 21:17:52 +020012848 int saveprompt;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012849
Denys Vlasenko46999802017-07-29 21:12:29 +020012850 /* XXX Fix (char *) cast. */
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012851 setinputstring((char *)ps);
Denys Vlasenko2a6d29a2016-10-25 21:17:52 +020012852
12853 saveprompt = doprompt;
12854 doprompt = 0;
Denys Vlasenkoa2e32b32017-10-12 19:20:13 +020012855
12856 /* readtoken1() might die horribly.
Denys Vlasenko3c183a82017-10-12 19:35:42 +020012857 * Try a prompt with syntactically wrong command:
Denys Vlasenkoa2e32b32017-10-12 19:20:13 +020012858 * PS1='$(date "+%H:%M:%S) > '
12859 */
12860 {
12861 volatile int saveint;
12862 struct jmploc *volatile savehandler = exception_handler;
12863 struct jmploc jmploc;
12864 SAVE_INT(saveint);
12865 if (setjmp(jmploc.loc) == 0) {
12866 exception_handler = &jmploc;
12867 readtoken1(pgetc(), syntax_type, FAKEEOFMARK, 0);
12868 }
12869 exception_handler = savehandler;
12870 RESTORE_INT(saveint);
12871 }
12872
Denys Vlasenko2a6d29a2016-10-25 21:17:52 +020012873 doprompt = saveprompt;
12874
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012875 popfile();
12876
12877 n.narg.type = NARG;
12878 n.narg.next = NULL;
12879 n.narg.text = wordtext;
12880 n.narg.backquote = backquotelist;
12881
Ron Yorston549deab2015-05-18 09:57:51 +020012882 expandarg(&n, NULL, EXP_QUOTED);
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012883 return stackblock();
12884}
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012885
Denys Vlasenko1e3e2cc2017-07-25 20:31:14 +020012886static inline int
12887parser_eof(void)
12888{
12889 return tokpushback && lasttoken == TEOF;
12890}
12891
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012892/*
12893 * Execute a command or commands contained in a string.
12894 */
12895static int
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020012896evalstring(char *s, int flags)
Eric Andersenc470f442003-07-28 09:56:35 +000012897{
Denys Vlasenko493b9ca2016-10-30 18:27:14 +010012898 struct jmploc *volatile savehandler;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012899 struct jmploc jmploc;
12900 int ex;
12901
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012902 union node *n;
12903 struct stackmark smark;
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012904 int status;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012905
Denys Vlasenko8e2bc472016-09-28 23:02:57 +020012906 s = sstrdup(s);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012907 setinputstring(s);
12908 setstackmark(&smark);
12909
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012910 status = 0;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012911 /* On exception inside execution loop, we must popfile().
12912 * Try interactively:
12913 * readonly a=a
12914 * command eval "a=b" # throws "is read only" error
12915 * "command BLTIN" is not supposed to abort (even in non-interactive use).
12916 * But if we skip popfile(), we hit EOF in eval's string, and exit.
12917 */
12918 savehandler = exception_handler;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012919 ex = setjmp(jmploc.loc);
12920 if (ex)
12921 goto out;
Denys Vlasenko493b9ca2016-10-30 18:27:14 +010012922 exception_handler = &jmploc;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012923
Denys Vlasenko86e83ec2009-07-23 22:07:07 +020012924 while ((n = parsecmd(0)) != NODE_EOF) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020012925 int i;
12926
Denys Vlasenko1e3e2cc2017-07-25 20:31:14 +020012927 i = evaltree(n, flags & ~(parser_eof() ? 0 : EV_EXIT));
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012928 if (n)
12929 status = i;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012930 popstackmark(&smark);
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012931 if (evalskip)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012932 break;
12933 }
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012934 out:
Denys Vlasenko8e2bc472016-09-28 23:02:57 +020012935 popstackmark(&smark);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012936 popfile();
Denys Vlasenko8e2bc472016-09-28 23:02:57 +020012937 stunalloc(s);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012938
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012939 exception_handler = savehandler;
12940 if (ex)
Denys Vlasenko14c85eb2017-10-12 19:40:47 +020012941 longjmp(exception_handler->loc, ex);
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012942
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012943 return status;
Eric Andersenc470f442003-07-28 09:56:35 +000012944}
12945
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012946/*
12947 * The eval command.
12948 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012949static int FAST_FUNC
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020012950evalcmd(int argc UNUSED_PARAM, char **argv, int flags)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012951{
12952 char *p;
12953 char *concat;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012954
Denis Vlasenko68404f12008-03-17 09:00:54 +000012955 if (argv[1]) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012956 p = argv[1];
Denis Vlasenko68404f12008-03-17 09:00:54 +000012957 argv += 2;
12958 if (argv[0]) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012959 STARTSTACKSTR(concat);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012960 for (;;) {
12961 concat = stack_putstr(p, concat);
Denis Vlasenko68404f12008-03-17 09:00:54 +000012962 p = *argv++;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012963 if (p == NULL)
12964 break;
12965 STPUTC(' ', concat);
12966 }
12967 STPUTC('\0', concat);
12968 p = grabstackstr(concat);
12969 }
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020012970 return evalstring(p, flags & EV_TESTED);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012971 }
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012972 return 0;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012973}
12974
12975/*
Denys Vlasenko285ad152009-12-04 23:02:27 +010012976 * Read and execute commands.
12977 * "Top" is nonzero for the top level command loop;
12978 * it turns on prompting if the shell is interactive.
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012979 */
12980static int
12981cmdloop(int top)
12982{
12983 union node *n;
12984 struct stackmark smark;
12985 int inter;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020012986 int status = 0;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012987 int numeof = 0;
12988
12989 TRACE(("cmdloop(%d) called\n", top));
12990 for (;;) {
12991 int skip;
12992
12993 setstackmark(&smark);
12994#if JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +000012995 if (doing_jobctl)
Denys Vlasenko9c541002015-10-07 15:44:36 +020012996 showjobs(SHOW_CHANGED|SHOW_STDERR);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012997#endif
12998 inter = 0;
12999 if (iflag && top) {
13000 inter++;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013001 chkmail();
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013002 }
13003 n = parsecmd(inter);
Denys Vlasenko7cee00e2009-07-24 01:08:03 +020013004#if DEBUG
13005 if (DEBUG > 2 && debug && (n != NODE_EOF))
Denys Vlasenko883cea42009-07-11 15:31:59 +020013006 showtree(n);
Denis Vlasenko135cecb2009-04-12 00:00:57 +000013007#endif
Denys Vlasenko86e83ec2009-07-23 22:07:07 +020013008 if (n == NODE_EOF) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013009 if (!top || numeof >= 50)
13010 break;
13011 if (!stoppedjobs()) {
13012 if (!Iflag)
13013 break;
13014 out2str("\nUse \"exit\" to leave shell.\n");
13015 }
13016 numeof++;
13017 } else if (nflag == 0) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020013018 int i;
13019
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +000013020 /* job_warning can only be 2,1,0. Here 2->1, 1/0->0 */
13021 job_warning >>= 1;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013022 numeof = 0;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020013023 i = evaltree(n, 0);
13024 if (n)
13025 status = i;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013026 }
13027 popstackmark(&smark);
13028 skip = evalskip;
13029
13030 if (skip) {
Denys Vlasenko6a0710e2016-09-30 14:18:34 +020013031 evalskip &= ~SKIPFUNC;
Denys Vlasenko0840c912016-10-01 15:27:44 +020013032 break;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013033 }
13034 }
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020013035 return status;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013036}
13037
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000013038/*
13039 * Take commands from a file. To be compatible we should do a path
13040 * search for the file, which is necessary to find sub-commands.
13041 */
13042static char *
13043find_dot_file(char *name)
13044{
13045 char *fullname;
13046 const char *path = pathval();
13047 struct stat statb;
13048
13049 /* don't try this for absolute or relative paths */
13050 if (strchr(name, '/'))
13051 return name;
13052
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020013053 while ((fullname = path_advance(&path, name)) != NULL) {
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000013054 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
13055 /*
13056 * Don't bother freeing here, since it will
13057 * be freed by the caller.
13058 */
13059 return fullname;
13060 }
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020013061 if (fullname != name)
13062 stunalloc(fullname);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000013063 }
Denys Vlasenko01f7b9e2018-01-26 15:15:43 +010013064 /* not found in PATH */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000013065
Denys Vlasenko01f7b9e2018-01-26 15:15:43 +010013066#if ENABLE_ASH_BASH_SOURCE_CURDIR
13067 return name;
13068#else
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000013069 ash_msg_and_raise_error("%s: not found", name);
13070 /* NOTREACHED */
Denys Vlasenko01f7b9e2018-01-26 15:15:43 +010013071#endif
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000013072}
13073
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013074static int FAST_FUNC
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020013075dotcmd(int argc_ UNUSED_PARAM, char **argv_ UNUSED_PARAM)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013076{
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020013077 /* "false; . empty_file; echo $?" should print 0, not 1: */
13078 int status = 0;
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020013079 char *fullname;
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020013080 char **argv;
Denys Vlasenkofb87d932017-01-09 08:22:06 +010013081 char *args_need_save;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013082 volatile struct shparam saveparam;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013083
Denys Vlasenko981a0562017-07-26 19:53:11 +020013084//???
13085// struct strlist *sp;
13086// for (sp = cmdenviron; sp; sp = sp->next)
13087// setvareq(ckstrdup(sp->text), VSTRFIXED | VTEXTFIXED);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013088
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020013089 nextopt(nullstr); /* handle possible "--" */
13090 argv = argptr;
13091
13092 if (!argv[0]) {
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020013093 /* bash says: "bash: .: filename argument required" */
13094 return 2; /* bash compat */
13095 }
13096
Denys Vlasenko091f8312013-03-17 14:25:22 +010013097 /* This aborts if file isn't found, which is POSIXly correct.
13098 * bash returns exitcode 1 instead.
13099 */
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020013100 fullname = find_dot_file(argv[0]);
13101 argv++;
Denys Vlasenkofb87d932017-01-09 08:22:06 +010013102 args_need_save = argv[0];
Denys Vlasenko5f7c82b2017-02-03 13:00:06 +010013103 if (args_need_save) { /* ". FILE ARGS", and ARGS are not empty */
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020013104 int argc;
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020013105 saveparam = shellparam;
13106 shellparam.malloced = 0;
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020013107 argc = 1;
13108 while (argv[argc])
13109 argc++;
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020013110 shellparam.nparam = argc;
13111 shellparam.p = argv;
13112 };
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013113
Denys Vlasenko091f8312013-03-17 14:25:22 +010013114 /* This aborts if file can't be opened, which is POSIXly correct.
13115 * bash returns exitcode 1 instead.
13116 */
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020013117 setinputfile(fullname, INPUT_PUSH_FILE);
13118 commandname = fullname;
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020013119 status = cmdloop(0);
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020013120 popfile();
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013121
Denys Vlasenkofb87d932017-01-09 08:22:06 +010013122 if (args_need_save) {
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020013123 freeparam(&shellparam);
13124 shellparam = saveparam;
13125 };
13126
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020013127 return status;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013128}
13129
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013130static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013131exitcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013132{
13133 if (stoppedjobs())
13134 return 0;
Denis Vlasenko68404f12008-03-17 09:00:54 +000013135 if (argv[1])
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013136 exitstatus = number(argv[1]);
13137 raise_exception(EXEXIT);
13138 /* NOTREACHED */
13139}
13140
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013141/*
13142 * Read a file containing shell functions.
13143 */
13144static void
13145readcmdfile(char *name)
13146{
13147 setinputfile(name, INPUT_PUSH_FILE);
13148 cmdloop(0);
13149 popfile();
13150}
13151
13152
Denis Vlasenkocc571512007-02-23 21:10:35 +000013153/* ============ find_command inplementation */
13154
13155/*
13156 * Resolve a command name. If you change this routine, you may have to
13157 * change the shellexec routine as well.
13158 */
13159static void
13160find_command(char *name, struct cmdentry *entry, int act, const char *path)
13161{
13162 struct tblentry *cmdp;
13163 int idx;
13164 int prev;
13165 char *fullname;
13166 struct stat statb;
13167 int e;
13168 int updatetbl;
13169 struct builtincmd *bcmd;
13170
13171 /* If name contains a slash, don't use PATH or hash table */
13172 if (strchr(name, '/') != NULL) {
13173 entry->u.index = -1;
13174 if (act & DO_ABS) {
13175 while (stat(name, &statb) < 0) {
13176#ifdef SYSV
13177 if (errno == EINTR)
13178 continue;
13179#endif
13180 entry->cmdtype = CMDUNKNOWN;
13181 return;
13182 }
13183 }
13184 entry->cmdtype = CMDNORMAL;
13185 return;
13186 }
13187
Denis Vlasenkof20de5b2007-04-29 23:42:54 +000013188/* #if ENABLE_FEATURE_SH_STANDALONE... moved after builtin check */
Denis Vlasenkocc571512007-02-23 21:10:35 +000013189
13190 updatetbl = (path == pathval());
13191 if (!updatetbl) {
13192 act |= DO_ALTPATH;
13193 if (strstr(path, "%builtin") != NULL)
13194 act |= DO_ALTBLTIN;
13195 }
13196
13197 /* If name is in the table, check answer will be ok */
13198 cmdp = cmdlookup(name, 0);
13199 if (cmdp != NULL) {
13200 int bit;
13201
13202 switch (cmdp->cmdtype) {
13203 default:
13204#if DEBUG
13205 abort();
13206#endif
13207 case CMDNORMAL:
13208 bit = DO_ALTPATH;
13209 break;
13210 case CMDFUNCTION:
13211 bit = DO_NOFUNC;
13212 break;
13213 case CMDBUILTIN:
13214 bit = DO_ALTBLTIN;
13215 break;
13216 }
13217 if (act & bit) {
13218 updatetbl = 0;
13219 cmdp = NULL;
13220 } else if (cmdp->rehash == 0)
13221 /* if not invalidated by cd, we're done */
13222 goto success;
13223 }
13224
13225 /* If %builtin not in path, check for builtin next */
13226 bcmd = find_builtin(name);
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000013227 if (bcmd) {
13228 if (IS_BUILTIN_REGULAR(bcmd))
13229 goto builtin_success;
13230 if (act & DO_ALTPATH) {
13231 if (!(act & DO_ALTBLTIN))
13232 goto builtin_success;
13233 } else if (builtinloc <= 0) {
13234 goto builtin_success;
Denis Vlasenko8e858e22007-03-07 09:35:43 +000013235 }
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000013236 }
Denis Vlasenkocc571512007-02-23 21:10:35 +000013237
Denis Vlasenkof20de5b2007-04-29 23:42:54 +000013238#if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko7465dbc2008-04-13 02:25:53 +000013239 {
13240 int applet_no = find_applet_by_name(name);
13241 if (applet_no >= 0) {
13242 entry->cmdtype = CMDNORMAL;
13243 entry->u.index = -2 - applet_no;
13244 return;
13245 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +000013246 }
13247#endif
13248
Denis Vlasenkocc571512007-02-23 21:10:35 +000013249 /* We have to search path. */
13250 prev = -1; /* where to start */
13251 if (cmdp && cmdp->rehash) { /* doing a rehash */
13252 if (cmdp->cmdtype == CMDBUILTIN)
13253 prev = builtinloc;
13254 else
13255 prev = cmdp->param.index;
13256 }
13257
13258 e = ENOENT;
13259 idx = -1;
13260 loop:
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020013261 while ((fullname = path_advance(&path, name)) != NULL) {
Denis Vlasenkocc571512007-02-23 21:10:35 +000013262 stunalloc(fullname);
Denis Vlasenkodee82b62007-07-29 14:05:27 +000013263 /* NB: code below will still use fullname
13264 * despite it being "unallocated" */
Denis Vlasenkocc571512007-02-23 21:10:35 +000013265 idx++;
13266 if (pathopt) {
13267 if (prefix(pathopt, "builtin")) {
13268 if (bcmd)
13269 goto builtin_success;
13270 continue;
Denis Vlasenko4a9ca132008-04-12 20:07:08 +000013271 }
13272 if ((act & DO_NOFUNC)
13273 || !prefix(pathopt, "func")
Denys Vlasenkoe4dcba12010-10-28 18:57:19 +020013274 ) { /* ignore unimplemented options */
Denis Vlasenkocc571512007-02-23 21:10:35 +000013275 continue;
13276 }
13277 }
13278 /* if rehash, don't redo absolute path names */
13279 if (fullname[0] == '/' && idx <= prev) {
13280 if (idx < prev)
13281 continue;
13282 TRACE(("searchexec \"%s\": no change\n", name));
13283 goto success;
13284 }
13285 while (stat(fullname, &statb) < 0) {
13286#ifdef SYSV
13287 if (errno == EINTR)
13288 continue;
13289#endif
13290 if (errno != ENOENT && errno != ENOTDIR)
13291 e = errno;
13292 goto loop;
13293 }
13294 e = EACCES; /* if we fail, this will be the error */
13295 if (!S_ISREG(statb.st_mode))
13296 continue;
13297 if (pathopt) { /* this is a %func directory */
13298 stalloc(strlen(fullname) + 1);
Denis Vlasenkodee82b62007-07-29 14:05:27 +000013299 /* NB: stalloc will return space pointed by fullname
13300 * (because we don't have any intervening allocations
13301 * between stunalloc above and this stalloc) */
Denis Vlasenkocc571512007-02-23 21:10:35 +000013302 readcmdfile(fullname);
13303 cmdp = cmdlookup(name, 0);
13304 if (cmdp == NULL || cmdp->cmdtype != CMDFUNCTION)
13305 ash_msg_and_raise_error("%s not defined in %s", name, fullname);
13306 stunalloc(fullname);
13307 goto success;
13308 }
13309 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
13310 if (!updatetbl) {
13311 entry->cmdtype = CMDNORMAL;
13312 entry->u.index = idx;
13313 return;
13314 }
13315 INT_OFF;
13316 cmdp = cmdlookup(name, 1);
13317 cmdp->cmdtype = CMDNORMAL;
13318 cmdp->param.index = idx;
13319 INT_ON;
13320 goto success;
13321 }
13322
13323 /* We failed. If there was an entry for this command, delete it */
13324 if (cmdp && updatetbl)
13325 delete_cmd_entry();
William Pitcockd8fd88a2018-01-24 18:33:18 +010013326 if (act & DO_ERR) {
13327#if ENABLE_ASH_BASH_NOT_FOUND_HOOK
13328 struct tblentry *hookp = cmdlookup("command_not_found_handle", 0);
13329 if (hookp && hookp->cmdtype == CMDFUNCTION) {
13330 char *argv[3];
13331 argv[0] = (char*) "command_not_found_handle";
13332 argv[1] = name;
13333 argv[2] = NULL;
13334 evalfun(hookp->param.func, 2, argv, 0);
13335 entry->cmdtype = CMDUNKNOWN;
13336 return;
13337 }
13338#endif
Denis Vlasenkocc571512007-02-23 21:10:35 +000013339 ash_msg("%s: %s", name, errmsg(e, "not found"));
William Pitcockd8fd88a2018-01-24 18:33:18 +010013340 }
Denis Vlasenkocc571512007-02-23 21:10:35 +000013341 entry->cmdtype = CMDUNKNOWN;
13342 return;
13343
13344 builtin_success:
13345 if (!updatetbl) {
13346 entry->cmdtype = CMDBUILTIN;
13347 entry->u.cmd = bcmd;
13348 return;
13349 }
13350 INT_OFF;
13351 cmdp = cmdlookup(name, 1);
13352 cmdp->cmdtype = CMDBUILTIN;
13353 cmdp->param.cmd = bcmd;
13354 INT_ON;
13355 success:
13356 cmdp->rehash = 0;
13357 entry->cmdtype = cmdp->cmdtype;
13358 entry->u = cmdp->param;
13359}
13360
13361
Eric Andersencb57d552001-06-28 07:25:16 +000013362/*
Eric Andersencb57d552001-06-28 07:25:16 +000013363 * The trap builtin.
13364 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013365static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013366trapcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +000013367{
13368 char *action;
13369 char **ap;
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010013370 int signo, exitcode;
Eric Andersencb57d552001-06-28 07:25:16 +000013371
Eric Andersenc470f442003-07-28 09:56:35 +000013372 nextopt(nullstr);
13373 ap = argptr;
13374 if (!*ap) {
Denis Vlasenko2da584f2007-02-19 22:44:05 +000013375 for (signo = 0; signo < NSIG; signo++) {
Denys Vlasenko21d87d42009-09-25 00:06:51 +020013376 char *tr = trap_ptr[signo];
13377 if (tr) {
Denys Vlasenkoe74aaf92009-09-27 02:05:45 +020013378 /* note: bash adds "SIG", but only if invoked
13379 * as "bash". If called as "sh", or if set -o posix,
13380 * then it prints short signal names.
13381 * We are printing short names: */
13382 out1fmt("trap -- %s %s\n",
Denys Vlasenko21d87d42009-09-25 00:06:51 +020013383 single_quote(tr),
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +000013384 get_signame(signo));
Denys Vlasenko726e1a02009-09-25 02:58:20 +020013385 /* trap_ptr != trap only if we are in special-cased `trap` code.
13386 * In this case, we will exit very soon, no need to free(). */
Denys Vlasenkoe74aaf92009-09-27 02:05:45 +020013387 /* if (trap_ptr != trap && tp[0]) */
Denys Vlasenko726e1a02009-09-25 02:58:20 +020013388 /* free(tr); */
Eric Andersencb57d552001-06-28 07:25:16 +000013389 }
13390 }
Denys Vlasenko726e1a02009-09-25 02:58:20 +020013391 /*
Denys Vlasenko21d87d42009-09-25 00:06:51 +020013392 if (trap_ptr != trap) {
13393 free(trap_ptr);
13394 trap_ptr = trap;
13395 }
Denys Vlasenko726e1a02009-09-25 02:58:20 +020013396 */
Eric Andersencb57d552001-06-28 07:25:16 +000013397 return 0;
13398 }
Denys Vlasenko21d87d42009-09-25 00:06:51 +020013399
Denys Vlasenko86981e32017-07-25 20:06:17 +020013400 /* Why the second check?
13401 * "trap NUM [sig2]..." is the same as "trap - NUM [sig2]..."
13402 * In this case, NUM is signal no, not an action.
13403 */
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +000013404 action = NULL;
Denys Vlasenko86981e32017-07-25 20:06:17 +020013405 if (ap[1] && !is_number(ap[0]))
Eric Andersencb57d552001-06-28 07:25:16 +000013406 action = *ap++;
Denys Vlasenko86981e32017-07-25 20:06:17 +020013407
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010013408 exitcode = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000013409 while (*ap) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000013410 signo = get_signum(*ap);
Denys Vlasenko86981e32017-07-25 20:06:17 +020013411 if (signo < 0) {
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010013412 /* Mimic bash message exactly */
13413 ash_msg("%s: invalid signal specification", *ap);
13414 exitcode = 1;
13415 goto next;
13416 }
Denis Vlasenkob012b102007-02-19 22:43:01 +000013417 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +000013418 if (action) {
Denis Vlasenko9f739442006-12-16 23:49:13 +000013419 if (LONE_DASH(action))
Eric Andersencb57d552001-06-28 07:25:16 +000013420 action = NULL;
Denys Vlasenkob4f51d32016-10-27 12:55:09 +020013421 else {
13422 if (action[0]) /* not NULL and not "" and not "-" */
13423 may_have_traps = 1;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013424 action = ckstrdup(action);
Denys Vlasenkob4f51d32016-10-27 12:55:09 +020013425 }
Eric Andersencb57d552001-06-28 07:25:16 +000013426 }
Denis Vlasenko60818682007-09-28 22:07:23 +000013427 free(trap[signo]);
Eric Andersencb57d552001-06-28 07:25:16 +000013428 trap[signo] = action;
13429 if (signo != 0)
13430 setsignal(signo);
Denis Vlasenkob012b102007-02-19 22:43:01 +000013431 INT_ON;
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010013432 next:
Eric Andersencb57d552001-06-28 07:25:16 +000013433 ap++;
13434 }
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010013435 return exitcode;
Eric Andersencb57d552001-06-28 07:25:16 +000013436}
13437
Eric Andersenc470f442003-07-28 09:56:35 +000013438
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013439/* ============ Builtins */
Eric Andersenc470f442003-07-28 09:56:35 +000013440
Denys Vlasenko2ec34962014-09-08 16:52:39 +020013441#if ENABLE_ASH_HELP
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013442static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013443helpcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000013444{
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000013445 unsigned col;
13446 unsigned i;
Eric Andersenc470f442003-07-28 09:56:35 +000013447
Denys Vlasenkod6b05eb2009-06-06 20:59:55 +020013448 out1fmt(
Denis Vlasenko34d4d892009-04-04 20:24:37 +000013449 "Built-in commands:\n"
13450 "------------------\n");
Denis Vlasenkob71c6682007-07-21 15:08:09 +000013451 for (col = 0, i = 0; i < ARRAY_SIZE(builtintab); i++) {
Eric Andersenc470f442003-07-28 09:56:35 +000013452 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
Denis Vlasenko52764022007-02-24 13:42:56 +000013453 builtintab[i].name + 1);
Eric Andersenc470f442003-07-28 09:56:35 +000013454 if (col > 60) {
13455 out1fmt("\n");
13456 col = 0;
13457 }
13458 }
Denys Vlasenko2ec34962014-09-08 16:52:39 +020013459# if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko1aa7e472007-11-28 06:49:03 +000013460 {
13461 const char *a = applet_names;
13462 while (*a) {
13463 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), a);
13464 if (col > 60) {
13465 out1fmt("\n");
13466 col = 0;
13467 }
Ron Yorston2b919582016-04-08 11:57:20 +010013468 while (*a++ != '\0')
13469 continue;
Eric Andersenc470f442003-07-28 09:56:35 +000013470 }
13471 }
Denys Vlasenko2ec34962014-09-08 16:52:39 +020013472# endif
Denys Vlasenkoebedb942016-10-02 18:45:09 +020013473 newline_and_flush(stdout);
Eric Andersenc470f442003-07-28 09:56:35 +000013474 return EXIT_SUCCESS;
13475}
Denys Vlasenko2ec34962014-09-08 16:52:39 +020013476#endif
Eric Andersenc470f442003-07-28 09:56:35 +000013477
Flemming Madsend96ffda2013-04-07 18:47:24 +020013478#if MAX_HISTORY
13479static int FAST_FUNC
13480historycmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
13481{
13482 show_history(line_input_state);
13483 return EXIT_SUCCESS;
13484}
13485#endif
13486
Eric Andersencb57d552001-06-28 07:25:16 +000013487/*
Eric Andersencb57d552001-06-28 07:25:16 +000013488 * The export and readonly commands.
13489 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013490static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013491exportcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000013492{
13493 struct var *vp;
13494 char *name;
13495 const char *p;
Eric Andersenc470f442003-07-28 09:56:35 +000013496 char **aptr;
Denys Vlasenkod5275882012-10-01 13:41:17 +020013497 char opt;
13498 int flag;
13499 int flag_off;
Eric Andersencb57d552001-06-28 07:25:16 +000013500
Denys Vlasenkod5275882012-10-01 13:41:17 +020013501 /* "readonly" in bash accepts, but ignores -n.
13502 * We do the same: it saves a conditional in nextopt's param.
13503 */
13504 flag_off = 0;
13505 while ((opt = nextopt("np")) != '\0') {
13506 if (opt == 'n')
13507 flag_off = VEXPORT;
13508 }
13509 flag = VEXPORT;
13510 if (argv[0][0] == 'r') {
13511 flag = VREADONLY;
13512 flag_off = 0; /* readonly ignores -n */
13513 }
13514 flag_off = ~flag_off;
13515
Denys Vlasenko10ad6222017-04-17 16:13:32 +020013516 /*if (opt_p_not_specified) - bash doesn't check this. Try "export -p NAME" */
Denys Vlasenkod5275882012-10-01 13:41:17 +020013517 {
Denis Vlasenko2da584f2007-02-19 22:44:05 +000013518 aptr = argptr;
13519 name = *aptr;
13520 if (name) {
13521 do {
13522 p = strchr(name, '=');
13523 if (p != NULL) {
13524 p++;
13525 } else {
13526 vp = *findvar(hashvar(name), name);
13527 if (vp) {
Denys Vlasenkod5275882012-10-01 13:41:17 +020013528 vp->flags = ((vp->flags | flag) & flag_off);
Denis Vlasenko2da584f2007-02-19 22:44:05 +000013529 continue;
13530 }
Eric Andersencb57d552001-06-28 07:25:16 +000013531 }
Denys Vlasenkod5275882012-10-01 13:41:17 +020013532 setvar(name, p, (flag & flag_off));
Denis Vlasenko2da584f2007-02-19 22:44:05 +000013533 } while ((name = *++aptr) != NULL);
13534 return 0;
13535 }
Eric Andersencb57d552001-06-28 07:25:16 +000013536 }
Denys Vlasenkod5275882012-10-01 13:41:17 +020013537
13538 /* No arguments. Show the list of exported or readonly vars.
13539 * -n is ignored.
13540 */
Denis Vlasenko2da584f2007-02-19 22:44:05 +000013541 showvars(argv[0], flag, 0);
Eric Andersencb57d552001-06-28 07:25:16 +000013542 return 0;
13543}
13544
Eric Andersencb57d552001-06-28 07:25:16 +000013545/*
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000013546 * Delete a function if it exists.
Eric Andersencb57d552001-06-28 07:25:16 +000013547 */
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +000013548static void
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000013549unsetfunc(const char *name)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000013550{
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000013551 struct tblentry *cmdp;
Eric Andersencb57d552001-06-28 07:25:16 +000013552
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000013553 cmdp = cmdlookup(name, 0);
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020013554 if (cmdp != NULL && cmdp->cmdtype == CMDFUNCTION)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000013555 delete_cmd_entry();
Eric Andersenc470f442003-07-28 09:56:35 +000013556}
13557
Eric Andersencb57d552001-06-28 07:25:16 +000013558/*
Eric Andersencb57d552001-06-28 07:25:16 +000013559 * The unset builtin command. We unset the function before we unset the
13560 * variable to allow a function to be unset when there is a readonly variable
13561 * with the same name.
13562 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013563static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013564unsetcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +000013565{
13566 char **ap;
13567 int i;
Eric Andersenc470f442003-07-28 09:56:35 +000013568 int flag = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000013569
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020013570 while ((i = nextopt("vf")) != 0) {
Eric Andersenc470f442003-07-28 09:56:35 +000013571 flag = i;
Eric Andersencb57d552001-06-28 07:25:16 +000013572 }
Eric Andersencb57d552001-06-28 07:25:16 +000013573
Denis Vlasenko2da584f2007-02-19 22:44:05 +000013574 for (ap = argptr; *ap; ap++) {
Eric Andersenc470f442003-07-28 09:56:35 +000013575 if (flag != 'f') {
Denys Vlasenkob28d4c32017-07-25 16:29:36 +020013576 unsetvar(*ap);
13577 continue;
Eric Andersenc470f442003-07-28 09:56:35 +000013578 }
13579 if (flag != 'v')
Eric Andersencb57d552001-06-28 07:25:16 +000013580 unsetfunc(*ap);
Eric Andersencb57d552001-06-28 07:25:16 +000013581 }
Denys Vlasenkob28d4c32017-07-25 16:29:36 +020013582 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +000013583}
13584
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000013585static const unsigned char timescmd_str[] ALIGN1 = {
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013586 ' ', offsetof(struct tms, tms_utime),
13587 '\n', offsetof(struct tms, tms_stime),
13588 ' ', offsetof(struct tms, tms_cutime),
13589 '\n', offsetof(struct tms, tms_cstime),
13590 0
13591};
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013592static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013593timescmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013594{
Denys Vlasenko11f2e992017-08-10 16:34:03 +020013595 unsigned clk_tck;
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013596 const unsigned char *p;
13597 struct tms buf;
13598
Bartosz Golaszewski5d2e4092014-06-22 14:01:13 +020013599 clk_tck = bb_clk_tck();
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013600
Denys Vlasenko11f2e992017-08-10 16:34:03 +020013601 times(&buf);
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013602 p = timescmd_str;
13603 do {
Denys Vlasenko11f2e992017-08-10 16:34:03 +020013604 unsigned sec, frac;
13605 unsigned long t;
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013606 t = *(clock_t *)(((char *) &buf) + p[1]);
Denys Vlasenko11f2e992017-08-10 16:34:03 +020013607 sec = t / clk_tck;
13608 frac = t % clk_tck;
13609 out1fmt("%um%u.%03us%c",
13610 sec / 60, sec % 60,
13611 (frac * 1000) / clk_tck,
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013612 p[0]);
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020013613 p += 2;
13614 } while (*p);
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013615
Eric Andersencb57d552001-06-28 07:25:16 +000013616 return 0;
13617}
13618
Denys Vlasenko0b883582016-12-23 16:49:07 +010013619#if ENABLE_FEATURE_SH_MATH
Eric Andersenc470f442003-07-28 09:56:35 +000013620/*
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020013621 * The let builtin. Partially stolen from GNU Bash, the Bourne Again SHell.
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +000013622 * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
Eric Andersen90898442003-08-06 11:20:52 +000013623 *
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +000013624 * Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
Eric Andersenc470f442003-07-28 09:56:35 +000013625 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013626static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013627letcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersenc470f442003-07-28 09:56:35 +000013628{
Denis Vlasenko68404f12008-03-17 09:00:54 +000013629 arith_t i;
Eric Andersenc470f442003-07-28 09:56:35 +000013630
Denis Vlasenko68404f12008-03-17 09:00:54 +000013631 argv++;
13632 if (!*argv)
Denis Vlasenkob012b102007-02-19 22:43:01 +000013633 ash_msg_and_raise_error("expression expected");
Denis Vlasenko68404f12008-03-17 09:00:54 +000013634 do {
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +000013635 i = ash_arith(*argv);
Denis Vlasenko68404f12008-03-17 09:00:54 +000013636 } while (*++argv);
Eric Andersenc470f442003-07-28 09:56:35 +000013637
Denis Vlasenkod9e15f22006-11-27 16:49:55 +000013638 return !i;
Eric Andersenc470f442003-07-28 09:56:35 +000013639}
Eric Andersenc470f442003-07-28 09:56:35 +000013640#endif
Eric Andersen74bcd162001-07-30 21:41:37 +000013641
Eric Andersenc470f442003-07-28 09:56:35 +000013642/*
Denis Vlasenko59f351c2008-03-25 00:07:12 +000013643 * The read builtin. Options:
13644 * -r Do not interpret '\' specially
13645 * -s Turn off echo (tty only)
13646 * -n NCHARS Read NCHARS max
13647 * -p PROMPT Display PROMPT on stderr (if input is from tty)
13648 * -t SECONDS Timeout after SECONDS (tty or pipe only)
13649 * -u FD Read from given FD instead of fd 0
Johannes Schindelin3bef5d82017-08-08 16:46:39 +020013650 * -d DELIM End on DELIM char, not newline
Eric Andersenc470f442003-07-28 09:56:35 +000013651 * This uses unbuffered input, which may be avoidable in some cases.
Denis Vlasenko59f351c2008-03-25 00:07:12 +000013652 * TODO: bash also has:
13653 * -a ARRAY Read into array[0],[1],etc
Denis Vlasenko59f351c2008-03-25 00:07:12 +000013654 * -e Use line editing (tty only)
Eric Andersenc470f442003-07-28 09:56:35 +000013655 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013656static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013657readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000013658{
Denys Vlasenko73067272010-01-12 22:11:24 +010013659 char *opt_n = NULL;
13660 char *opt_p = NULL;
13661 char *opt_t = NULL;
13662 char *opt_u = NULL;
Johannes Schindelin3bef5d82017-08-08 16:46:39 +020013663 char *opt_d = NULL; /* optimized out if !BASH */
Denys Vlasenko73067272010-01-12 22:11:24 +010013664 int read_flags = 0;
13665 const char *r;
Eric Andersenc470f442003-07-28 09:56:35 +000013666 int i;
13667
Johannes Schindelin3bef5d82017-08-08 16:46:39 +020013668 while ((i = nextopt("p:u:rt:n:sd:")) != '\0') {
Denis Vlasenkobf0a2012006-12-26 10:42:51 +000013669 switch (i) {
Paul Fox02eb9342005-09-07 16:56:02 +000013670 case 'p':
Denys Vlasenko73067272010-01-12 22:11:24 +010013671 opt_p = optionarg;
Paul Fox02eb9342005-09-07 16:56:02 +000013672 break;
Paul Fox02eb9342005-09-07 16:56:02 +000013673 case 'n':
Denys Vlasenko73067272010-01-12 22:11:24 +010013674 opt_n = optionarg;
Paul Fox02eb9342005-09-07 16:56:02 +000013675 break;
13676 case 's':
Denys Vlasenko73067272010-01-12 22:11:24 +010013677 read_flags |= BUILTIN_READ_SILENT;
Paul Fox02eb9342005-09-07 16:56:02 +000013678 break;
Paul Fox02eb9342005-09-07 16:56:02 +000013679 case 't':
Denys Vlasenko73067272010-01-12 22:11:24 +010013680 opt_t = optionarg;
Paul Fox02eb9342005-09-07 16:56:02 +000013681 break;
Paul Fox02eb9342005-09-07 16:56:02 +000013682 case 'r':
Denys Vlasenko73067272010-01-12 22:11:24 +010013683 read_flags |= BUILTIN_READ_RAW;
Paul Fox02eb9342005-09-07 16:56:02 +000013684 break;
Denis Vlasenko59f351c2008-03-25 00:07:12 +000013685 case 'u':
Denys Vlasenko73067272010-01-12 22:11:24 +010013686 opt_u = optionarg;
Denis Vlasenko59f351c2008-03-25 00:07:12 +000013687 break;
Johannes Schindelin3bef5d82017-08-08 16:46:39 +020013688#if BASH_READ_D
13689 case 'd':
13690 opt_d = optionarg;
13691 break;
13692#endif
Paul Fox02eb9342005-09-07 16:56:02 +000013693 default:
13694 break;
13695 }
Eric Andersenc470f442003-07-28 09:56:35 +000013696 }
Paul Fox02eb9342005-09-07 16:56:02 +000013697
Denys Vlasenko9e71e3c2012-09-06 13:28:10 +020013698 /* "read -s" needs to save/restore termios, can't allow ^C
13699 * to jump out of it.
13700 */
Denys Vlasenkof5470412017-05-22 19:34:45 +020013701 again:
Denys Vlasenko9e71e3c2012-09-06 13:28:10 +020013702 INT_OFF;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020013703 r = shell_builtin_read(setvar0,
Denys Vlasenko73067272010-01-12 22:11:24 +010013704 argptr,
13705 bltinlookup("IFS"), /* can be NULL */
13706 read_flags,
13707 opt_n,
13708 opt_p,
13709 opt_t,
Johannes Schindelin3bef5d82017-08-08 16:46:39 +020013710 opt_u,
13711 opt_d
Denys Vlasenko73067272010-01-12 22:11:24 +010013712 );
Denys Vlasenko9e71e3c2012-09-06 13:28:10 +020013713 INT_ON;
Denis Vlasenko46aeab92009-03-31 19:18:17 +000013714
Denys Vlasenkof5470412017-05-22 19:34:45 +020013715 if ((uintptr_t)r == 1 && errno == EINTR) {
Denys Vlasenko49e6bf22017-08-04 14:28:16 +020013716 /* To get SIGCHLD: sleep 1 & read x; echo $x
13717 * Correct behavior is to not exit "read"
13718 */
Denys Vlasenkof5470412017-05-22 19:34:45 +020013719 if (pending_sig == 0)
13720 goto again;
13721 }
13722
Denys Vlasenko73067272010-01-12 22:11:24 +010013723 if ((uintptr_t)r > 1)
13724 ash_msg_and_raise_error(r);
Denis Vlasenko037576d2007-10-20 18:30:38 +000013725
Denys Vlasenko73067272010-01-12 22:11:24 +010013726 return (uintptr_t)r;
Eric Andersenc470f442003-07-28 09:56:35 +000013727}
13728
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013729static int FAST_FUNC
Denys Vlasenko6283f982015-10-07 16:56:20 +020013730umaskcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000013731{
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013732 static const char permuser[3] ALIGN1 = "ogu";
Eric Andersenc470f442003-07-28 09:56:35 +000013733
Eric Andersenc470f442003-07-28 09:56:35 +000013734 mode_t mask;
Eric Andersenc470f442003-07-28 09:56:35 +000013735 int symbolic_mode = 0;
13736
13737 while (nextopt("S") != '\0') {
13738 symbolic_mode = 1;
13739 }
13740
Denis Vlasenkob012b102007-02-19 22:43:01 +000013741 INT_OFF;
Eric Andersenc470f442003-07-28 09:56:35 +000013742 mask = umask(0);
13743 umask(mask);
Denis Vlasenkob012b102007-02-19 22:43:01 +000013744 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +000013745
Denys Vlasenko6283f982015-10-07 16:56:20 +020013746 if (*argptr == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +000013747 if (symbolic_mode) {
Denys Vlasenko005c4922015-10-10 20:17:12 +020013748 char buf[sizeof(",u=rwx,g=rwx,o=rwx")];
Eric Andersenc470f442003-07-28 09:56:35 +000013749 char *p = buf;
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013750 int i;
Eric Andersenc470f442003-07-28 09:56:35 +000013751
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013752 i = 2;
13753 for (;;) {
Denys Vlasenko005c4922015-10-10 20:17:12 +020013754 *p++ = ',';
Eric Andersenc470f442003-07-28 09:56:35 +000013755 *p++ = permuser[i];
13756 *p++ = '=';
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013757 /* mask is 0..0uuugggooo. i=2 selects uuu bits */
Denys Vlasenko005c4922015-10-10 20:17:12 +020013758 if (!(mask & 0400)) *p++ = 'r';
13759 if (!(mask & 0200)) *p++ = 'w';
13760 if (!(mask & 0100)) *p++ = 'x';
13761 mask <<= 3;
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013762 if (--i < 0)
13763 break;
Eric Andersenc470f442003-07-28 09:56:35 +000013764 }
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013765 *p = '\0';
Denys Vlasenko005c4922015-10-10 20:17:12 +020013766 puts(buf + 1);
Eric Andersenc470f442003-07-28 09:56:35 +000013767 } else {
Denys Vlasenkoec046f72015-10-07 17:57:53 +020013768 out1fmt("%04o\n", mask);
Eric Andersenc470f442003-07-28 09:56:35 +000013769 }
13770 } else {
Denys Vlasenko6283f982015-10-07 16:56:20 +020013771 char *modestr = *argptr;
Denys Vlasenko14c85eb2017-10-12 19:40:47 +020013772 /* numeric umasks are taken as-is */
13773 /* symbolic umasks are inverted: "umask a=rx" calls umask(222) */
Denys Vlasenko6283f982015-10-07 16:56:20 +020013774 if (!isdigit(modestr[0]))
13775 mask ^= 0777;
Denys Vlasenko5711a2a2015-10-07 17:55:33 +020013776 mask = bb_parse_mode(modestr, mask);
13777 if ((unsigned)mask > 0777) {
Denys Vlasenko6283f982015-10-07 16:56:20 +020013778 ash_msg_and_raise_error("illegal mode: %s", modestr);
Eric Andersenc470f442003-07-28 09:56:35 +000013779 }
Denys Vlasenko6283f982015-10-07 16:56:20 +020013780 if (!isdigit(modestr[0]))
13781 mask ^= 0777;
13782 umask(mask);
Eric Andersenc470f442003-07-28 09:56:35 +000013783 }
13784 return 0;
13785}
13786
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013787static int FAST_FUNC
Denys Vlasenkof3c742f2010-03-06 20:12:00 +010013788ulimitcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersenc470f442003-07-28 09:56:35 +000013789{
Denys Vlasenkof3c742f2010-03-06 20:12:00 +010013790 return shell_builtin_ulimit(argv);
Eric Andersenc470f442003-07-28 09:56:35 +000013791}
13792
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013793/* ============ main() and helpers */
13794
13795/*
13796 * Called to exit the shell.
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013797 */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013798static void
13799exitshell(void)
13800{
13801 struct jmploc loc;
13802 char *p;
13803 int status;
13804
Denys Vlasenkobede2152011-09-04 16:12:33 +020013805#if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT
13806 save_history(line_input_state);
13807#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013808 status = exitstatus;
13809 TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
13810 if (setjmp(loc.loc)) {
Denis Vlasenko7f88e342009-03-19 03:36:18 +000013811 if (exception_type == EXEXIT)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013812 status = exitstatus;
13813 goto out;
13814 }
13815 exception_handler = &loc;
13816 p = trap[0];
13817 if (p) {
13818 trap[0] = NULL;
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020013819 evalskip = 0;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013820 evalstring(p, 0);
Denys Vlasenkof37e1152016-10-07 03:17:28 +020013821 /*free(p); - we'll exit soon */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013822 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013823 out:
Denys Vlasenkof37e1152016-10-07 03:17:28 +020013824 /* dash wraps setjobctl(0) in "if (setjmp(loc.loc) == 0) {...}".
13825 * our setjobctl(0) does not panic if tcsetpgrp fails inside it.
13826 */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013827 setjobctl(0);
Denys Vlasenkocaee80c2016-10-25 20:49:53 +020013828 flush_stdout_stderr();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013829 _exit(status);
13830 /* NOTREACHED */
13831}
13832
Denys Vlasenko49e6bf22017-08-04 14:28:16 +020013833/* Don't inline: conserve stack of caller from having our locals too */
13834static NOINLINE void
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +000013835init(void)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013836{
Denys Vlasenko82dd14a2010-05-17 10:10:01 +020013837 /* we will never free this */
13838 basepf.next_to_pgetc = basepf.buf = ckmalloc(IBUFSIZ);
Denys Vlasenko0485b672017-08-14 19:46:56 +020013839 basepf.linno = 1;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013840
Denys Vlasenko49e6bf22017-08-04 14:28:16 +020013841 sigmode[SIGCHLD - 1] = S_DFL; /* ensure we install handler even if it is SIG_IGNed */
Denys Vlasenko458c1f22016-10-27 23:51:19 +020013842 setsignal(SIGCHLD);
13843
Denys Vlasenko7a7b0342009-12-04 04:18:31 +010013844 /* bash re-enables SIGHUP which is SIG_IGNed on entry.
13845 * Try: "trap '' HUP; bash; echo RET" and type "kill -HUP $$"
13846 */
Denys Vlasenkocacb2cd2010-10-05 00:13:02 +020013847 signal(SIGHUP, SIG_DFL);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013848
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013849 {
13850 char **envp;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013851 const char *p;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013852
13853 initvar();
13854 for (envp = environ; envp && *envp; envp++) {
Denys Vlasenko9c143ce2017-11-02 12:56:24 +010013855/* Used to have
13856 * p = endofname(*envp);
13857 * if (p != *envp && *p == '=') {
13858 * here to weed out badly-named variables, but this breaks
13859 * scenarios where people do want them passed to children:
13860 * import os
13861 * os.environ["test-test"]="test"
13862 * if os.fork() == 0:
13863 * os.execv("ash", [ 'ash', '-c', 'eval $(export -p); echo OK' ]) # fixes this
13864 * os.execv("ash", [ 'ash', '-c', 'env | grep test-test' ]) # breaks this
13865 */
13866 if (strchr(*envp, '=')) {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013867 setvareq(*envp, VEXPORT|VTEXTFIXED);
13868 }
13869 }
13870
Denys Vlasenkoe627ac92016-09-30 14:36:59 +020013871 setvareq((char*)defoptindvar, VTEXTFIXED);
13872
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020013873 setvar0("PPID", utoa(getppid()));
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010013874#if BASH_SHLVL_VAR
Bernhard Reutner-Fischer80f8cdf2013-11-08 14:25:24 +010013875 p = lookupvar("SHLVL");
Denys Vlasenko5680e982014-01-07 16:12:48 +010013876 setvar("SHLVL", utoa((p ? atoi(p) : 0) + 1), VEXPORT);
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010013877#endif
13878#if BASH_HOSTNAME_VAR
Denys Vlasenko3fa97af2014-04-15 11:43:29 +020013879 if (!lookupvar("HOSTNAME")) {
13880 struct utsname uts;
13881 uname(&uts);
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020013882 setvar0("HOSTNAME", uts.nodename);
Denys Vlasenko3fa97af2014-04-15 11:43:29 +020013883 }
Bernhard Reutner-Fischer80f8cdf2013-11-08 14:25:24 +010013884#endif
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013885 p = lookupvar("PWD");
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013886 if (p) {
Denys Vlasenko49e6bf22017-08-04 14:28:16 +020013887 struct stat st1, st2;
Denys Vlasenkoef159702016-09-01 11:16:22 +020013888 if (p[0] != '/' || stat(p, &st1) || stat(".", &st2)
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013889 || st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino
13890 ) {
Denys Vlasenkoef159702016-09-01 11:16:22 +020013891 p = NULL;
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013892 }
13893 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013894 setpwd(p, 0);
13895 }
13896}
13897
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013898
13899//usage:#define ash_trivial_usage
Denys Vlasenko6b6af532011-03-08 10:24:17 +010013900//usage: "[-/+OPTIONS] [-/+o OPT]... [-c 'SCRIPT' [ARG0 [ARGS]] / FILE [ARGS]]"
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013901//usage:#define ash_full_usage "\n\n"
13902//usage: "Unix shell interpreter"
13903
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013904/*
13905 * Process the shell command line arguments.
13906 */
Denys Vlasenkoec05df12017-07-31 19:43:47 +020013907static int
Denis Vlasenko68404f12008-03-17 09:00:54 +000013908procargs(char **argv)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013909{
13910 int i;
13911 const char *xminusc;
13912 char **xargv;
Denys Vlasenkoec05df12017-07-31 19:43:47 +020013913 int login_sh;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013914
13915 xargv = argv;
Denys Vlasenkoec05df12017-07-31 19:43:47 +020013916 login_sh = xargv[0] && xargv[0][0] == '-';
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013917 arg0 = xargv[0];
Denis Vlasenko68404f12008-03-17 09:00:54 +000013918 /* if (xargv[0]) - mmm, this is always true! */
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013919 xargv++;
13920 for (i = 0; i < NOPTS; i++)
13921 optlist[i] = 2;
13922 argptr = xargv;
Denys Vlasenkoec05df12017-07-31 19:43:47 +020013923 if (options(/*cmdline:*/ 1, &login_sh)) {
Denis Vlasenko28bf6712008-02-14 15:01:47 +000013924 /* it already printed err message */
13925 raise_exception(EXERROR);
13926 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013927 xargv = argptr;
13928 xminusc = minusc;
13929 if (*xargv == NULL) {
13930 if (xminusc)
13931 ash_msg_and_raise_error(bb_msg_requires_arg, "-c");
13932 sflag = 1;
13933 }
13934 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
13935 iflag = 1;
13936 if (mflag == 2)
13937 mflag = iflag;
13938 for (i = 0; i < NOPTS; i++)
13939 if (optlist[i] == 2)
13940 optlist[i] = 0;
13941#if DEBUG == 2
13942 debug = 1;
13943#endif
Denys Vlasenko5f7c82b2017-02-03 13:00:06 +010013944 /* POSIX 1003.2: first arg after "-c CMD" is $0, remainder $1... */
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013945 if (xminusc) {
13946 minusc = *xargv++;
13947 if (*xargv)
13948 goto setarg0;
13949 } else if (!sflag) {
13950 setinputfile(*xargv, 0);
13951 setarg0:
13952 arg0 = *xargv++;
13953 commandname = arg0;
13954 }
13955
13956 shellparam.p = xargv;
13957#if ENABLE_ASH_GETOPTS
13958 shellparam.optind = 1;
13959 shellparam.optoff = -1;
13960#endif
Denis Vlasenko01631112007-12-16 17:20:38 +000013961 /* assert(shellparam.malloced == 0 && shellparam.nparam == 0); */
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013962 while (*xargv) {
13963 shellparam.nparam++;
13964 xargv++;
13965 }
13966 optschanged();
Denys Vlasenkoec05df12017-07-31 19:43:47 +020013967
13968 return login_sh;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013969}
13970
13971/*
Denys Vlasenko2eb0a7e2016-10-27 11:28:59 +020013972 * Read /etc/profile, ~/.profile, $ENV.
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013973 */
13974static void
13975read_profile(const char *name)
13976{
Denys Vlasenko46999802017-07-29 21:12:29 +020013977 name = expandstr(name, DQSYNTAX);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013978 if (setinputfile(name, INPUT_PUSH_FILE | INPUT_NOFILE_OK) < 0)
13979 return;
Denys Vlasenko0840c912016-10-01 15:27:44 +020013980 cmdloop(0);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013981 popfile();
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013982}
13983
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013984/*
13985 * This routine is called when an error or an interrupt occurs in an
13986 * interactive shell and control is returned to the main command loop.
Denys Vlasenko5ac04f22016-10-27 14:46:50 +020013987 * (In dash, this function is auto-generated by build machinery).
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013988 */
13989static void
13990reset(void)
13991{
13992 /* from eval.c: */
13993 evalskip = 0;
13994 loopnest = 0;
Denys Vlasenko5ac04f22016-10-27 14:46:50 +020013995
13996 /* from expand.c: */
13997 ifsfree();
13998
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013999 /* from input.c: */
Denis Vlasenko41eb3002008-11-28 03:42:31 +000014000 g_parsefile->left_in_buffer = 0;
14001 g_parsefile->left_in_line = 0; /* clear input buffer */
Denis Vlasenko0c032a42007-02-23 01:03:40 +000014002 popallfiles();
Denys Vlasenko5ac04f22016-10-27 14:46:50 +020014003
Denis Vlasenko0c032a42007-02-23 01:03:40 +000014004 /* from redir.c: */
Denys Vlasenko1c79aeb2017-07-29 22:51:52 +020014005 unwindredir(NULL);
Denys Vlasenkob8ab27b2017-07-26 19:22:34 +020014006
14007 /* from var.c: */
Denys Vlasenko484fc202017-07-26 19:55:31 +020014008 unwindlocalvars(NULL);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000014009}
14010
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014011#if PROFILE
14012static short profile_buf[16384];
14013extern int etext();
14014#endif
14015
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000014016/*
14017 * Main routine. We initialize things, parse the arguments, execute
14018 * profiles if we're a login shell, and then call cmdloop to execute
14019 * commands. The setjmp call sets up the location to jump to when an
14020 * exception occurs. When an exception occurs the variable "state"
14021 * is used to figure out how far we had gotten.
14022 */
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +000014023int ash_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000014024int ash_main(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014025{
Denis Vlasenko4e12b1a2008-12-23 23:36:47 +000014026 volatile smallint state;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014027 struct jmploc jmploc;
14028 struct stackmark smark;
Denys Vlasenkoec05df12017-07-31 19:43:47 +020014029 int login_sh;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014030
Denis Vlasenko01631112007-12-16 17:20:38 +000014031 /* Initialize global data */
14032 INIT_G_misc();
14033 INIT_G_memstack();
14034 INIT_G_var();
Denis Vlasenkoee87ebf2007-12-21 22:18:16 +000014035#if ENABLE_ASH_ALIAS
Denis Vlasenko01631112007-12-16 17:20:38 +000014036 INIT_G_alias();
Denis Vlasenkoee87ebf2007-12-21 22:18:16 +000014037#endif
Denis Vlasenko01631112007-12-16 17:20:38 +000014038 INIT_G_cmdtable();
14039
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014040#if PROFILE
14041 monitor(4, etext, profile_buf, sizeof(profile_buf), 50);
14042#endif
14043
14044#if ENABLE_FEATURE_EDITING
14045 line_input_state = new_line_input_t(FOR_SHELL | WITH_PATH_LOOKUP);
14046#endif
14047 state = 0;
14048 if (setjmp(jmploc.loc)) {
Denis Vlasenko7f88e342009-03-19 03:36:18 +000014049 smallint e;
Denis Vlasenko4e12b1a2008-12-23 23:36:47 +000014050 smallint s;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014051
14052 reset();
14053
Denis Vlasenko7f88e342009-03-19 03:36:18 +000014054 e = exception_type;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014055 s = state;
Denys Vlasenkob563f622010-09-25 17:15:13 +020014056 if (e == EXEXIT || s == 0 || iflag == 0 || shlvl) {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014057 exitshell();
Denys Vlasenkob563f622010-09-25 17:15:13 +020014058 }
14059 if (e == EXINT) {
Denys Vlasenko9c541002015-10-07 15:44:36 +020014060 newline_and_flush(stderr);
Denys Vlasenkob563f622010-09-25 17:15:13 +020014061 }
Denis Vlasenko7f88e342009-03-19 03:36:18 +000014062
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014063 popstackmark(&smark);
14064 FORCE_INT_ON; /* enable interrupts */
14065 if (s == 1)
14066 goto state1;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000014067 if (s == 2)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014068 goto state2;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000014069 if (s == 3)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014070 goto state3;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000014071 goto state4;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014072 }
14073 exception_handler = &jmploc;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014074 rootpid = getpid();
14075
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014076 init();
14077 setstackmark(&smark);
Denys Vlasenkoec05df12017-07-31 19:43:47 +020014078 login_sh = procargs(argv);
Denys Vlasenko474ed062016-10-30 18:30:29 +010014079#if DEBUG
14080 TRACE(("Shell args: "));
14081 trace_puts_args(argv);
14082#endif
Denis Vlasenko68404f12008-03-17 09:00:54 +000014083
Denys Vlasenkoec05df12017-07-31 19:43:47 +020014084 if (login_sh) {
Stefan Hellermann4ef14392013-03-15 02:45:50 +010014085 const char *hp;
14086
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014087 state = 1;
14088 read_profile("/etc/profile");
14089 state1:
14090 state = 2;
Stefan Hellermann4ef14392013-03-15 02:45:50 +010014091 hp = lookupvar("HOME");
Denys Vlasenko2eb0a7e2016-10-27 11:28:59 +020014092 if (hp)
14093 read_profile("$HOME/.profile");
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014094 }
14095 state2:
14096 state = 3;
14097 if (
14098#ifndef linux
Denis Vlasenko0c032a42007-02-23 01:03:40 +000014099 getuid() == geteuid() && getgid() == getegid() &&
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014100#endif
Denis Vlasenko0c032a42007-02-23 01:03:40 +000014101 iflag
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014102 ) {
Denys Vlasenko2eb0a7e2016-10-27 11:28:59 +020014103 const char *shinit = lookupvar("ENV");
14104 if (shinit != NULL && *shinit != '\0')
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014105 read_profile(shinit);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014106 }
Denys Vlasenko2eb0a7e2016-10-27 11:28:59 +020014107 popstackmark(&smark);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014108 state3:
14109 state = 4;
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000014110 if (minusc) {
14111 /* evalstring pushes parsefile stack.
14112 * Ensure we don't falsely claim that 0 (stdin)
Denis Vlasenko5368ad52009-03-20 10:20:08 +000014113 * is one of stacked source fds.
14114 * Testcase: ash -c 'exec 1>&0' must not complain. */
Denys Vlasenko79b3d422010-06-03 04:29:08 +020014115 // if (!sflag) g_parsefile->pf_fd = -1;
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +020014116 // ^^ not necessary since now we special-case fd 0
Denys Vlasenko035486c2017-07-31 04:09:19 +020014117 // in save_fd_on_redirect()
Denys Vlasenko1e3e2cc2017-07-25 20:31:14 +020014118 evalstring(minusc, sflag ? 0 : EV_EXIT);
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000014119 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014120
14121 if (sflag || minusc == NULL) {
Denys Vlasenko4840ae82011-09-04 15:28:03 +020014122#if MAX_HISTORY > 0 && ENABLE_FEATURE_EDITING_SAVEHISTORY
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +000014123 if (iflag) {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014124 const char *hp = lookupvar("HISTFILE");
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010014125 if (!hp) {
14126 hp = lookupvar("HOME");
Stefan Hellermann4ef14392013-03-15 02:45:50 +010014127 if (hp) {
Denys Vlasenko5f7c82b2017-02-03 13:00:06 +010014128 INT_OFF;
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010014129 hp = concat_path_file(hp, ".ash_history");
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020014130 setvar0("HISTFILE", hp);
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010014131 free((char*)hp);
Denys Vlasenko5f7c82b2017-02-03 13:00:06 +010014132 INT_ON;
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010014133 hp = lookupvar("HISTFILE");
14134 }
14135 }
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000014136 if (hp)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014137 line_input_state->hist_file = hp;
Denys Vlasenko2c4de5b2011-03-31 13:16:52 +020014138# if ENABLE_FEATURE_SH_HISTFILESIZE
14139 hp = lookupvar("HISTFILESIZE");
14140 line_input_state->max_history = size_from_HISTFILESIZE(hp);
14141# endif
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014142 }
14143#endif
14144 state4: /* XXX ??? - why isn't this before the "if" statement */
14145 cmdloop(1);
14146 }
14147#if PROFILE
14148 monitor(0);
14149#endif
14150#ifdef GPROF
14151 {
14152 extern void _mcleanup(void);
14153 _mcleanup();
14154 }
14155#endif
Denys Vlasenkob563f622010-09-25 17:15:13 +020014156 TRACE(("End of main reached\n"));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014157 exitshell();
14158 /* NOTREACHED */
14159}
14160
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014161
Eric Andersendf82f612001-06-28 07:46:40 +000014162/*-
14163 * Copyright (c) 1989, 1991, 1993, 1994
Eric Andersen2870d962001-07-02 17:27:21 +000014164 * The Regents of the University of California. All rights reserved.
Eric Andersendf82f612001-06-28 07:46:40 +000014165 *
14166 * This code is derived from software contributed to Berkeley by
14167 * Kenneth Almquist.
14168 *
14169 * Redistribution and use in source and binary forms, with or without
14170 * modification, are permitted provided that the following conditions
14171 * are met:
14172 * 1. Redistributions of source code must retain the above copyright
14173 * notice, this list of conditions and the following disclaimer.
14174 * 2. Redistributions in binary form must reproduce the above copyright
14175 * notice, this list of conditions and the following disclaimer in the
14176 * documentation and/or other materials provided with the distribution.
"Vladimir N. Oleynik"ddc280e2005-12-15 12:01:49 +000014177 * 3. Neither the name of the University nor the names of its contributors
Eric Andersendf82f612001-06-28 07:46:40 +000014178 * may be used to endorse or promote products derived from this software
14179 * without specific prior written permission.
14180 *
Denys Vlasenko95f79532017-08-02 14:26:33 +020014181 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND
Eric Andersendf82f612001-06-28 07:46:40 +000014182 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
14183 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
14184 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
14185 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
14186 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
14187 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
14188 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
14189 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
14190 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
14191 * SUCH DAMAGE.
14192 */