blob: 7a0b88c68573e2a243ae7c90275c1975aeaf417c [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:
54//config:config ASH_JOB_CONTROL
55//config: bool "Job control"
56//config: default y
57//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
58//config:
59//config:config ASH_ALIAS
60//config: bool "Alias support"
61//config: default y
62//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
Denys Vlasenko514b51d2016-10-01 14:33:08 +020063//config:
64//config:config ASH_RANDOM_SUPPORT
65//config: bool "Pseudorandom generator and $RANDOM variable"
66//config: default y
Denys Vlasenko0b883582016-12-23 16:49:07 +010067//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
Denys Vlasenko514b51d2016-10-01 14:33:08 +020068//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +020069//config: Enable pseudorandom generator and dynamic variable "$RANDOM".
70//config: Each read of "$RANDOM" will generate a new pseudorandom value.
71//config: You can reset the generator by using a specified start value.
72//config: After "unset RANDOM" the generator will switch off and this
73//config: variable will no longer have special treatment.
Denys Vlasenko514b51d2016-10-01 14:33:08 +020074//config:
75//config:config ASH_EXPAND_PRMT
76//config: bool "Expand prompt string"
77//config: default y
Denys Vlasenko0b883582016-12-23 16:49:07 +010078//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
Denys Vlasenko514b51d2016-10-01 14:33:08 +020079//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +020080//config: $PS# may contain volatile content, such as backquote commands.
81//config: This option recreates the prompt string from the environment
82//config: variable each time it is displayed.
Denys Vlasenko514b51d2016-10-01 14:33:08 +020083//config:
Denys Vlasenko046341e2011-02-04 17:53:59 +010084//config:config ASH_IDLE_TIMEOUT
Denys Vlasenkof5604222017-01-10 14:58:54 +010085//config: bool "Idle timeout variable $TMOUT"
Denys Vlasenko771f1992010-07-16 14:31:34 +020086//config: default y
Denys Vlasenko0b883582016-12-23 16:49:07 +010087//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
Denys Vlasenko771f1992010-07-16 14:31:34 +020088//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +020089//config: Enable bash-like auto-logout after $TMOUT seconds of idle time.
Denys Vlasenko771f1992010-07-16 14:31:34 +020090//config:
Denys Vlasenkof5604222017-01-10 14:58:54 +010091//config:config ASH_MAIL
92//config: bool "Check for new mail in interactive shell"
Denys Vlasenko771f1992010-07-16 14:31:34 +020093//config: default y
Denys Vlasenko0b883582016-12-23 16:49:07 +010094//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
Denys Vlasenko771f1992010-07-16 14:31:34 +020095//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +020096//config: Enable "check for new mail" function:
97//config: if set, $MAIL file and $MAILPATH list of files
98//config: are checked for mtime changes, and "you have mail"
99//config: message is printed if change is detected.
Denys Vlasenko771f1992010-07-16 14:31:34 +0200100//config:
Denys Vlasenko265062d2017-01-10 15:13:30 +0100101//config:config ASH_ECHO
Denys Vlasenkof5604222017-01-10 14:58:54 +0100102//config: bool "echo builtin"
Denys Vlasenko771f1992010-07-16 14:31:34 +0200103//config: default y
Denys Vlasenko0b883582016-12-23 16:49:07 +0100104//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
Denys Vlasenko771f1992010-07-16 14:31:34 +0200105//config:
Denys Vlasenko265062d2017-01-10 15:13:30 +0100106//config:config ASH_PRINTF
Denys Vlasenkof5604222017-01-10 14:58:54 +0100107//config: bool "printf builtin"
Denys Vlasenko771f1992010-07-16 14:31:34 +0200108//config: default y
Denys Vlasenko0b883582016-12-23 16:49:07 +0100109//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
Denys Vlasenko771f1992010-07-16 14:31:34 +0200110//config:
Denys Vlasenko265062d2017-01-10 15:13:30 +0100111//config:config ASH_TEST
Denys Vlasenkof5604222017-01-10 14:58:54 +0100112//config: bool "test builtin"
Denys Vlasenko771f1992010-07-16 14:31:34 +0200113//config: default y
Denys Vlasenko0b883582016-12-23 16:49:07 +0100114//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
Denys Vlasenko771f1992010-07-16 14:31:34 +0200115//config:
Denys Vlasenko2ec34962014-09-08 16:52:39 +0200116//config:config ASH_HELP
117//config: bool "help builtin"
118//config: default y
Denys Vlasenko0b883582016-12-23 16:49:07 +0100119//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
Denys Vlasenkof5604222017-01-10 14:58:54 +0100120//config:
121//config:config ASH_GETOPTS
122//config: bool "getopts builtin"
123//config: default y
124//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
Denys Vlasenko2ec34962014-09-08 16:52:39 +0200125//config:
Denys Vlasenko771f1992010-07-16 14:31:34 +0200126//config:config ASH_CMDCMD
Denys Vlasenkof5604222017-01-10 14:58:54 +0100127//config: bool "command builtin"
Denys Vlasenko771f1992010-07-16 14:31:34 +0200128//config: default y
Denys Vlasenko0b883582016-12-23 16:49:07 +0100129//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
Denys Vlasenko771f1992010-07-16 14:31:34 +0200130//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +0200131//config: Enable support for the 'command' builtin, which allows
132//config: you to run the specified command or builtin,
133//config: even when there is a function with the same name.
Kang-Che Sung6cd02942017-01-06 17:02:03 +0100134//config:
135//config:endif # ash options
Denys Vlasenko771f1992010-07-16 14:31:34 +0200136
Denys Vlasenko20704f02011-03-23 17:59:27 +0100137//applet:IF_ASH(APPLET(ash, BB_DIR_BIN, BB_SUID_DROP))
Denys Vlasenko205d48e2017-01-29 14:57:33 +0100138// APPLET_ODDNAME:name main location suid_type help
139//applet:IF_SH_IS_ASH( APPLET_ODDNAME(sh, ash, BB_DIR_BIN, BB_SUID_DROP, ash))
Denys Vlasenko0b883582016-12-23 16:49:07 +0100140//applet:IF_BASH_IS_ASH(APPLET_ODDNAME(bash, ash, BB_DIR_BIN, BB_SUID_DROP, ash))
Denys Vlasenko20704f02011-03-23 17:59:27 +0100141
142//kbuild:lib-$(CONFIG_ASH) += ash.o ash_ptr_hack.o shell_common.o
Denys Vlasenko0b883582016-12-23 16:49:07 +0100143//kbuild:lib-$(CONFIG_SH_IS_ASH) += ash.o ash_ptr_hack.o shell_common.o
144//kbuild:lib-$(CONFIG_BASH_IS_ASH) += ash.o ash_ptr_hack.o shell_common.o
Denys Vlasenko20704f02011-03-23 17:59:27 +0100145//kbuild:lib-$(CONFIG_ASH_RANDOM_SUPPORT) += random.o
146
Denys Vlasenko67047462016-12-22 15:21:58 +0100147/*
Denys Vlasenko7d4aec02017-01-11 14:00:38 +0100148 * DEBUG=1 to compile in debugging ('set -o debug' turns on)
149 * DEBUG=2 to compile in and turn on debugging.
150 * When debugging is on ("set -o debug" was executed, or DEBUG=2),
151 * debugging info is written to ./trace, quit signal generates core dump.
Denys Vlasenko67047462016-12-22 15:21:58 +0100152 */
153#define DEBUG 0
154/* Tweak debug output verbosity here */
155#define DEBUG_TIME 0
156#define DEBUG_PID 1
157#define DEBUG_SIG 1
158#define DEBUG_INTONOFF 0
159
160#define PROFILE 0
161
162#define JOBS ENABLE_ASH_JOB_CONTROL
163
164#include <setjmp.h>
165#include <fnmatch.h>
166#include <sys/times.h>
167#include <sys/utsname.h> /* for setting $HOSTNAME */
Denys Vlasenko67047462016-12-22 15:21:58 +0100168#include "busybox.h" /* for applet_names */
169
Denys Vlasenko7d4aec02017-01-11 14:00:38 +0100170/* So far, all bash compat is controlled by one config option */
171/* Separate defines document which part of code implements what */
172/* function keyword */
173#define BASH_FUNCTION ENABLE_ASH_BASH_COMPAT
174#define IF_BASH_FUNCTION IF_ASH_BASH_COMPAT
175/* &>file */
176#define BASH_REDIR_OUTPUT ENABLE_ASH_BASH_COMPAT
177#define IF_BASH_REDIR_OUTPUT IF_ASH_BASH_COMPAT
178/* $'...' */
179#define BASH_DOLLAR_SQUOTE ENABLE_ASH_BASH_COMPAT
180#define IF_BASH_DOLLAR_SQUOTE IF_ASH_BASH_COMPAT
181#define BASH_PATTERN_SUBST ENABLE_ASH_BASH_COMPAT
182#define IF_BASH_PATTERN_SUBST IF_ASH_BASH_COMPAT
183#define BASH_SUBSTR ENABLE_ASH_BASH_COMPAT
184#define IF_BASH_SUBSTR IF_ASH_BASH_COMPAT
185/* [[ EXPR ]] */
186#define BASH_TEST2 (ENABLE_ASH_BASH_COMPAT * ENABLE_ASH_TEST)
187#define BASH_SOURCE ENABLE_ASH_BASH_COMPAT
188#define BASH_PIPEFAIL ENABLE_ASH_BASH_COMPAT
189#define BASH_HOSTNAME_VAR ENABLE_ASH_BASH_COMPAT
190#define BASH_SHLVL_VAR ENABLE_ASH_BASH_COMPAT
Denys Vlasenkof8cdc7a2017-08-04 15:24:49 +0200191#define BASH_XTRACEFD ENABLE_ASH_BASH_COMPAT
Johannes Schindelin3bef5d82017-08-08 16:46:39 +0200192#define BASH_READ_D ENABLE_ASH_BASH_COMPAT
193#define IF_BASH_READ_D IF_ASH_BASH_COMPAT
Denys Vlasenko7d4aec02017-01-11 14:00:38 +0100194
Denys Vlasenko67047462016-12-22 15:21:58 +0100195#if defined(__ANDROID_API__) && __ANDROID_API__ <= 24
196/* Bionic at least up to version 24 has no glob() */
197# undef ENABLE_ASH_INTERNAL_GLOB
198# define ENABLE_ASH_INTERNAL_GLOB 1
199#endif
200
201#if !ENABLE_ASH_INTERNAL_GLOB && defined(__UCLIBC__)
202# error uClibc glob() is buggy, use ASH_INTERNAL_GLOB.
203# error The bug is: for "$PWD"/<pattern> ash will escape e.g. dashes in "$PWD"
204# error with backslash, even ones which do not need to be: "/a-b" -> "/a\-b"
205# error glob() should unbackslash them and match. uClibc does not unbackslash,
206# error fails to match dirname, subsequently not expanding <pattern> in it.
207// Testcase:
208// if (glob("/etc/polkit\\-1", 0, NULL, &pglob)) - this returns 0 on uclibc, no bug
209// if (glob("/etc/polkit\\-1/*", 0, NULL, &pglob)) printf("uclibc bug!\n");
210#endif
211
212#if !ENABLE_ASH_INTERNAL_GLOB
213# include <glob.h>
214#endif
215
216#include "unicode.h"
217#include "shell_common.h"
Denys Vlasenko0b883582016-12-23 16:49:07 +0100218#if ENABLE_FEATURE_SH_MATH
Denys Vlasenko67047462016-12-22 15:21:58 +0100219# include "math.h"
Denys Vlasenkocf3a7962017-07-26 14:38:19 +0200220#else
221typedef long arith_t;
222# define ARITH_FMT "%ld"
Denys Vlasenko67047462016-12-22 15:21:58 +0100223#endif
224#if ENABLE_ASH_RANDOM_SUPPORT
225# include "random.h"
226#else
227# define CLEAR_RANDOM_T(rnd) ((void)0)
228#endif
229
230#include "NUM_APPLETS.h"
231#if NUM_APPLETS == 1
232/* STANDALONE does not make sense, and won't compile */
233# undef CONFIG_FEATURE_SH_STANDALONE
234# undef ENABLE_FEATURE_SH_STANDALONE
235# undef IF_FEATURE_SH_STANDALONE
236# undef IF_NOT_FEATURE_SH_STANDALONE
237# define ENABLE_FEATURE_SH_STANDALONE 0
238# define IF_FEATURE_SH_STANDALONE(...)
239# define IF_NOT_FEATURE_SH_STANDALONE(...) __VA_ARGS__
240#endif
241
242#ifndef PIPE_BUF
243# define PIPE_BUF 4096 /* amount of buffering in a pipe */
244#endif
245
246#if !BB_MMU
247# error "Do not even bother, ash will not run on NOMMU machine"
248#endif
249
Denis Vlasenkob012b102007-02-19 22:43:01 +0000250
Denis Vlasenko01631112007-12-16 17:20:38 +0000251/* ============ Hash table sizes. Configurable. */
252
253#define VTABSIZE 39
254#define ATABSIZE 39
255#define CMDTABLESIZE 31 /* should be prime */
256
257
Denis Vlasenkob012b102007-02-19 22:43:01 +0000258/* ============ Shell options */
259
260static const char *const optletters_optnames[] = {
261 "e" "errexit",
262 "f" "noglob",
263 "I" "ignoreeof",
264 "i" "interactive",
265 "m" "monitor",
266 "n" "noexec",
267 "s" "stdin",
268 "x" "xtrace",
269 "v" "verbose",
270 "C" "noclobber",
271 "a" "allexport",
272 "b" "notify",
273 "u" "nounset",
Denys Vlasenkoe9ac32a2009-12-05 02:01:25 +0100274 "\0" "vi"
Denys Vlasenko7d4aec02017-01-11 14:00:38 +0100275#if BASH_PIPEFAIL
Denys Vlasenkoe9ac32a2009-12-05 02:01:25 +0100276 ,"\0" "pipefail"
Michael Abbott359da5e2009-12-04 23:03:29 +0100277#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +0000278#if DEBUG
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000279 ,"\0" "nolog"
280 ,"\0" "debug"
Denis Vlasenkob012b102007-02-19 22:43:01 +0000281#endif
282};
283
Denys Vlasenko285ad152009-12-04 23:02:27 +0100284#define optletters(n) optletters_optnames[n][0]
285#define optnames(n) (optletters_optnames[n] + 1)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000286
Denis Vlasenko80b8b392007-06-25 10:55:35 +0000287enum { NOPTS = ARRAY_SIZE(optletters_optnames) };
Denis Vlasenkob012b102007-02-19 22:43:01 +0000288
Eric Andersenc470f442003-07-28 09:56:35 +0000289
Denis Vlasenkob012b102007-02-19 22:43:01 +0000290/* ============ Misc data */
Eric Andersenc470f442003-07-28 09:56:35 +0000291
Denys Vlasenkoea8b2522010-06-02 12:57:26 +0200292#define msg_illnum "Illegal number: %s"
Denis Vlasenkoaa744452007-02-23 01:04:22 +0000293
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +0000294/*
Eric Andersenc470f442003-07-28 09:56:35 +0000295 * We enclose jmp_buf in a structure so that we can declare pointers to
296 * jump locations. The global variable handler contains the location to
Denis Vlasenkof1733952009-03-19 23:21:55 +0000297 * jump to when an exception occurs, and the global variable exception_type
Eric Andersenaff114c2004-04-14 17:51:38 +0000298 * contains a code identifying the exception. To implement nested
Eric Andersenc470f442003-07-28 09:56:35 +0000299 * exception handlers, the user should save the value of handler on entry
300 * to an inner scope, set handler to point to a jmploc structure for the
301 * inner scope, and restore handler on exit from the scope.
302 */
Eric Andersenc470f442003-07-28 09:56:35 +0000303struct jmploc {
304 jmp_buf loc;
305};
Denis Vlasenko01631112007-12-16 17:20:38 +0000306
307struct globals_misc {
Denys Vlasenko4d12e942016-10-01 16:03:11 +0200308 uint8_t exitstatus; /* exit status of last command */
309 uint8_t back_exitstatus;/* exit status of backquoted command */
310 smallint job_warning; /* user was warned about stopped jobs (can be 2, 1 or 0). */
311 int rootpid; /* pid of main shell */
Denis Vlasenko01631112007-12-16 17:20:38 +0000312 /* shell level: 0 for the main shell, 1 for its children, and so on */
313 int shlvl;
314#define rootshell (!shlvl)
315 char *minusc; /* argument to -c option */
316
317 char *curdir; // = nullstr; /* current working directory */
318 char *physdir; // = nullstr; /* physical working directory */
319
320 char *arg0; /* value of $0 */
321
322 struct jmploc *exception_handler;
Denis Vlasenko991a1da2008-02-10 19:02:53 +0000323
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200324 volatile int suppress_int; /* counter */
325 volatile /*sig_atomic_t*/ smallint pending_int; /* 1 = got SIGINT */
Denys Vlasenko458c1f22016-10-27 23:51:19 +0200326 volatile /*sig_atomic_t*/ smallint got_sigchld; /* 1 = got SIGCHLD */
Denys Vlasenko8f7b0242016-10-28 17:16:11 +0200327 volatile /*sig_atomic_t*/ smallint pending_sig; /* last pending signal */
Denis Vlasenko7f88e342009-03-19 03:36:18 +0000328 smallint exception_type; /* kind of exception (0..5) */
Denis Vlasenko01631112007-12-16 17:20:38 +0000329 /* exceptions */
Eric Andersenc470f442003-07-28 09:56:35 +0000330#define EXINT 0 /* SIGINT received */
331#define EXERROR 1 /* a generic error */
Eric Andersenc470f442003-07-28 09:56:35 +0000332#define EXEXIT 4 /* exit the shell */
Eric Andersen2870d962001-07-02 17:27:21 +0000333
Denis Vlasenkob07a4962008-06-22 13:16:23 +0000334 char nullstr[1]; /* zero length string */
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000335
336 char optlist[NOPTS];
337#define eflag optlist[0]
338#define fflag optlist[1]
339#define Iflag optlist[2]
340#define iflag optlist[3]
341#define mflag optlist[4]
342#define nflag optlist[5]
343#define sflag optlist[6]
344#define xflag optlist[7]
345#define vflag optlist[8]
346#define Cflag optlist[9]
347#define aflag optlist[10]
348#define bflag optlist[11]
349#define uflag optlist[12]
350#define viflag optlist[13]
Denys Vlasenko7d4aec02017-01-11 14:00:38 +0100351#if BASH_PIPEFAIL
Michael Abbott359da5e2009-12-04 23:03:29 +0100352# define pipefail optlist[14]
353#else
354# define pipefail 0
355#endif
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000356#if DEBUG
Denys Vlasenko7d4aec02017-01-11 14:00:38 +0100357# define nolog optlist[14 + BASH_PIPEFAIL]
358# define debug optlist[15 + BASH_PIPEFAIL]
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000359#endif
360
361 /* trap handler commands */
Denis Vlasenko01631112007-12-16 17:20:38 +0000362 /*
363 * Sigmode records the current value of the signal handlers for the various
364 * modes. A value of zero means that the current handler is not known.
Denis Vlasenkof8535cc2008-12-03 10:36:26 +0000365 * S_HARD_IGN indicates that the signal was ignored on entry to the shell.
Denis Vlasenko01631112007-12-16 17:20:38 +0000366 */
367 char sigmode[NSIG - 1];
Denis Vlasenkof8535cc2008-12-03 10:36:26 +0000368#define S_DFL 1 /* default signal handling (SIG_DFL) */
369#define S_CATCH 2 /* signal is caught */
370#define S_IGN 3 /* signal is ignored (SIG_IGN) */
Denys Vlasenko0f14f412017-08-06 20:06:19 +0200371#define S_HARD_IGN 4 /* signal is ignored permanently (it was SIG_IGN on entry to shell) */
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +0000372
Denis Vlasenko01631112007-12-16 17:20:38 +0000373 /* indicates specified signal received */
Denis Vlasenko4b875702009-03-19 13:30:04 +0000374 uint8_t gotsig[NSIG - 1]; /* offset by 1: "signal" 0 is meaningless */
Denys Vlasenko238bf182010-05-18 15:49:07 +0200375 uint8_t may_have_traps; /* 0: definitely no traps are set, 1: some traps may be set */
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000376 char *trap[NSIG];
Denys Vlasenko21d87d42009-09-25 00:06:51 +0200377 char **trap_ptr; /* used only by "trap hack" */
Denis Vlasenko448d30e2008-06-27 00:24:11 +0000378
379 /* Rarely referenced stuff */
380#if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenko3ea2e822009-10-09 20:59:04 +0200381 random_t random_gen;
Denis Vlasenko448d30e2008-06-27 00:24:11 +0000382#endif
383 pid_t backgndpid; /* pid of last background process */
Denis Vlasenko01631112007-12-16 17:20:38 +0000384};
Denis Vlasenko574f2f42008-02-27 18:41:59 +0000385extern struct globals_misc *const ash_ptr_to_globals_misc;
386#define G_misc (*ash_ptr_to_globals_misc)
Denys Vlasenko4d12e942016-10-01 16:03:11 +0200387#define exitstatus (G_misc.exitstatus )
388#define back_exitstatus (G_misc.back_exitstatus )
389#define job_warning (G_misc.job_warning)
Denis Vlasenko26bc57d2008-06-27 00:29:34 +0000390#define rootpid (G_misc.rootpid )
391#define shlvl (G_misc.shlvl )
392#define minusc (G_misc.minusc )
393#define curdir (G_misc.curdir )
394#define physdir (G_misc.physdir )
395#define arg0 (G_misc.arg0 )
Denis Vlasenko01631112007-12-16 17:20:38 +0000396#define exception_handler (G_misc.exception_handler)
Denis Vlasenko7f88e342009-03-19 03:36:18 +0000397#define exception_type (G_misc.exception_type )
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200398#define suppress_int (G_misc.suppress_int )
399#define pending_int (G_misc.pending_int )
Denys Vlasenko458c1f22016-10-27 23:51:19 +0200400#define got_sigchld (G_misc.got_sigchld )
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200401#define pending_sig (G_misc.pending_sig )
Denis Vlasenko26bc57d2008-06-27 00:29:34 +0000402#define nullstr (G_misc.nullstr )
403#define optlist (G_misc.optlist )
404#define sigmode (G_misc.sigmode )
405#define gotsig (G_misc.gotsig )
Denys Vlasenko238bf182010-05-18 15:49:07 +0200406#define may_have_traps (G_misc.may_have_traps )
Denis Vlasenko26bc57d2008-06-27 00:29:34 +0000407#define trap (G_misc.trap )
Denys Vlasenko21d87d42009-09-25 00:06:51 +0200408#define trap_ptr (G_misc.trap_ptr )
Denys Vlasenko3ea2e822009-10-09 20:59:04 +0200409#define random_gen (G_misc.random_gen )
Denis Vlasenko448d30e2008-06-27 00:24:11 +0000410#define backgndpid (G_misc.backgndpid )
Denis Vlasenko01631112007-12-16 17:20:38 +0000411#define INIT_G_misc() do { \
Denis Vlasenko574f2f42008-02-27 18:41:59 +0000412 (*(struct globals_misc**)&ash_ptr_to_globals_misc) = xzalloc(sizeof(G_misc)); \
413 barrier(); \
Denis Vlasenko01631112007-12-16 17:20:38 +0000414 curdir = nullstr; \
415 physdir = nullstr; \
Denys Vlasenko21d87d42009-09-25 00:06:51 +0200416 trap_ptr = trap; \
Denis Vlasenko01631112007-12-16 17:20:38 +0000417} while (0)
418
419
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000420/* ============ DEBUG */
421#if DEBUG
422static void trace_printf(const char *fmt, ...);
423static void trace_vprintf(const char *fmt, va_list va);
424# define TRACE(param) trace_printf param
425# define TRACEV(param) trace_vprintf param
Denis Vlasenko1bb3d7e2009-03-20 07:45:36 +0000426# define close(fd) do { \
427 int dfd = (fd); \
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +0000428 if (close(dfd) < 0) \
Denys Vlasenko883cea42009-07-11 15:31:59 +0200429 bb_error_msg("bug on %d: closing %d(0x%x)", \
Denis Vlasenko1bb3d7e2009-03-20 07:45:36 +0000430 __LINE__, dfd, dfd); \
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +0000431} while (0)
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000432#else
433# define TRACE(param)
434# define TRACEV(param)
435#endif
436
437
Denis Vlasenko559691a2008-10-05 18:39:31 +0000438/* ============ Utility functions */
Denys Vlasenko1961aea2013-02-26 00:36:53 +0100439#define is_name(c) ((c) == '_' || isalpha((unsigned char)(c)))
440#define is_in_name(c) ((c) == '_' || isalnum((unsigned char)(c)))
441
Denys Vlasenko37dc08b2016-10-02 04:38:07 +0200442static int
443isdigit_str9(const char *str)
Denis Vlasenko559691a2008-10-05 18:39:31 +0000444{
445 int maxlen = 9 + 1; /* max 9 digits: 999999999 */
446 while (--maxlen && isdigit(*str))
447 str++;
448 return (*str == '\0');
449}
Denis Vlasenko01631112007-12-16 17:20:38 +0000450
Denys Vlasenko37dc08b2016-10-02 04:38:07 +0200451static const char *
452var_end(const char *var)
Denys Vlasenko8837c5d2010-06-02 12:56:18 +0200453{
454 while (*var)
455 if (*var++ == '=')
456 break;
457 return var;
458}
459
Denis Vlasenko559691a2008-10-05 18:39:31 +0000460
461/* ============ Interrupts / exceptions */
Denys Vlasenko66c5b122011-02-08 05:07:02 +0100462
463static void exitshell(void) NORETURN;
464
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +0000465/*
Eric Andersen2870d962001-07-02 17:27:21 +0000466 * These macros allow the user to suspend the handling of interrupt signals
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +0000467 * over a period of time. This is similar to SIGHOLD or to sigblock, but
Eric Andersen2870d962001-07-02 17:27:21 +0000468 * much more efficient and portable. (But hacking the kernel is so much
469 * more fun than worrying about efficiency and portability. :-))
470 */
Denys Vlasenko06b11492016-11-04 16:43:18 +0100471#if DEBUG_INTONOFF
472# define INT_OFF do { \
473 TRACE(("%s:%d INT_OFF(%d)\n", __func__, __LINE__, suppress_int)); \
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200474 suppress_int++; \
Denys Vlasenkode892052016-10-02 01:49:13 +0200475 barrier(); \
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000476} while (0)
Denys Vlasenko06b11492016-11-04 16:43:18 +0100477#else
478# define INT_OFF do { \
479 suppress_int++; \
480 barrier(); \
481} while (0)
482#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +0000483
484/*
485 * Called to raise an exception. Since C doesn't include exceptions, we
486 * just do a longjmp to the exception handler. The type of exception is
Denis Vlasenko4b875702009-03-19 13:30:04 +0000487 * stored in the global variable "exception_type".
Denis Vlasenkob012b102007-02-19 22:43:01 +0000488 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000489static void raise_exception(int) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +0000490static void
491raise_exception(int e)
492{
493#if DEBUG
Denis Vlasenko2da584f2007-02-19 22:44:05 +0000494 if (exception_handler == NULL)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000495 abort();
496#endif
497 INT_OFF;
Denis Vlasenko7f88e342009-03-19 03:36:18 +0000498 exception_type = e;
Denis Vlasenko2da584f2007-02-19 22:44:05 +0000499 longjmp(exception_handler->loc, 1);
Denis Vlasenkob012b102007-02-19 22:43:01 +0000500}
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000501#if DEBUG
502#define raise_exception(e) do { \
503 TRACE(("raising exception %d on line %d\n", (e), __LINE__)); \
504 raise_exception(e); \
505} while (0)
506#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +0000507
508/*
Denys Vlasenkof37e1152016-10-07 03:17:28 +0200509 * Called when a SIGINT is received. (If the user specifies
Denis Vlasenkob012b102007-02-19 22:43:01 +0000510 * that SIGINT is to be trapped or ignored using the trap builtin, then
511 * this routine is not called.) Suppressint is nonzero when interrupts
512 * are held using the INT_OFF macro. (The test for iflag is just
513 * defensive programming.)
514 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000515static void raise_interrupt(void) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +0000516static void
517raise_interrupt(void)
518{
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200519 pending_int = 0;
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +0000520 /* Signal is not automatically unmasked after it is raised,
521 * do it ourself - unmask all signals */
Denis Vlasenko3f165fa2008-03-17 08:29:08 +0000522 sigprocmask_allsigs(SIG_UNBLOCK);
Denys Vlasenko238bf182010-05-18 15:49:07 +0200523 /* pending_sig = 0; - now done in signal_handler() */
Denis Vlasenko7c139b42007-03-21 20:17:27 +0000524
Denys Vlasenkoc0663c72016-10-27 21:09:01 +0200525 if (!(rootshell && iflag)) {
526 /* Kill ourself with SIGINT */
527 signal(SIGINT, SIG_DFL);
528 raise(SIGINT);
Denis Vlasenkob012b102007-02-19 22:43:01 +0000529 }
Denys Vlasenko4d12e942016-10-01 16:03:11 +0200530 /* bash: ^C even on empty command line sets $? */
531 exitstatus = SIGINT + 128;
Denys Vlasenkoc0663c72016-10-27 21:09:01 +0200532 raise_exception(EXINT);
Denis Vlasenkob012b102007-02-19 22:43:01 +0000533 /* NOTREACHED */
534}
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000535#if DEBUG
536#define raise_interrupt() do { \
537 TRACE(("raising interrupt on line %d\n", __LINE__)); \
538 raise_interrupt(); \
539} while (0)
540#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +0000541
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000542static IF_ASH_OPTIMIZE_FOR_SIZE(inline) void
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000543int_on(void)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000544{
Denys Vlasenkode892052016-10-02 01:49:13 +0200545 barrier();
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200546 if (--suppress_int == 0 && pending_int) {
Denis Vlasenkob012b102007-02-19 22:43:01 +0000547 raise_interrupt();
548 }
549}
Denys Vlasenko06b11492016-11-04 16:43:18 +0100550#if DEBUG_INTONOFF
551# define INT_ON do { \
552 TRACE(("%s:%d INT_ON(%d)\n", __func__, __LINE__, suppress_int-1)); \
553 int_on(); \
554} while (0)
555#else
556# define INT_ON int_on()
557#endif
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000558static IF_ASH_OPTIMIZE_FOR_SIZE(inline) void
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000559force_int_on(void)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000560{
Denys Vlasenkode892052016-10-02 01:49:13 +0200561 barrier();
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200562 suppress_int = 0;
563 if (pending_int)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000564 raise_interrupt();
565}
566#define FORCE_INT_ON force_int_on()
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000567
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200568#define SAVE_INT(v) ((v) = suppress_int)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000569
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000570#define RESTORE_INT(v) do { \
Denys Vlasenkode892052016-10-02 01:49:13 +0200571 barrier(); \
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200572 suppress_int = (v); \
573 if (suppress_int == 0 && pending_int) \
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000574 raise_interrupt(); \
575} while (0)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000576
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000577
Denis Vlasenkobc54cff2007-02-23 01:05:52 +0000578/* ============ Stdout/stderr output */
Eric Andersenc470f442003-07-28 09:56:35 +0000579
Eric Andersenc470f442003-07-28 09:56:35 +0000580static void
Denis Vlasenkob012b102007-02-19 22:43:01 +0000581outstr(const char *p, FILE *file)
Denis Vlasenkoe5570da2007-02-19 22:41:55 +0000582{
Denis Vlasenkob012b102007-02-19 22:43:01 +0000583 INT_OFF;
584 fputs(p, file);
585 INT_ON;
586}
587
588static void
589flush_stdout_stderr(void)
590{
591 INT_OFF;
Denys Vlasenko8131eea2009-11-02 14:19:51 +0100592 fflush_all();
Denis Vlasenkob012b102007-02-19 22:43:01 +0000593 INT_ON;
594}
595
Denys Vlasenko9c541002015-10-07 15:44:36 +0200596/* Was called outcslow(c,FILE*), but c was always '\n' */
Denis Vlasenkob012b102007-02-19 22:43:01 +0000597static void
Denys Vlasenko9c541002015-10-07 15:44:36 +0200598newline_and_flush(FILE *dest)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000599{
600 INT_OFF;
Denys Vlasenko9c541002015-10-07 15:44:36 +0200601 putc('\n', dest);
Denis Vlasenkob012b102007-02-19 22:43:01 +0000602 fflush(dest);
603 INT_ON;
604}
605
606static int out1fmt(const char *, ...) __attribute__((__format__(__printf__,1,2)));
607static int
608out1fmt(const char *fmt, ...)
609{
610 va_list ap;
611 int r;
612
613 INT_OFF;
614 va_start(ap, fmt);
615 r = vprintf(fmt, ap);
616 va_end(ap);
617 INT_ON;
618 return r;
619}
620
621static int fmtstr(char *, size_t, const char *, ...) __attribute__((__format__(__printf__,3,4)));
622static int
623fmtstr(char *outbuf, size_t length, const char *fmt, ...)
624{
625 va_list ap;
626 int ret;
627
Denis Vlasenkob012b102007-02-19 22:43:01 +0000628 INT_OFF;
Denys Vlasenkocf3a7962017-07-26 14:38:19 +0200629 va_start(ap, fmt);
Denis Vlasenkob012b102007-02-19 22:43:01 +0000630 ret = vsnprintf(outbuf, length, fmt, ap);
631 va_end(ap);
632 INT_ON;
633 return ret;
634}
635
636static void
637out1str(const char *p)
638{
639 outstr(p, stdout);
640}
641
642static void
643out2str(const char *p)
644{
645 outstr(p, stderr);
Denys Vlasenko8131eea2009-11-02 14:19:51 +0100646 flush_stdout_stderr();
Denis Vlasenkob012b102007-02-19 22:43:01 +0000647}
648
649
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +0000650/* ============ Parser structures */
Denis Vlasenko4d2183b2007-02-23 01:05:38 +0000651
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000652/* control characters in argument strings */
Denys Vlasenko2ce42e92009-11-29 02:18:13 +0100653#define CTL_FIRST CTLESC
Denys Vlasenkob6c84342009-08-29 20:23:20 +0200654#define CTLESC ((unsigned char)'\201') /* escape next character */
655#define CTLVAR ((unsigned char)'\202') /* variable defn */
656#define CTLENDVAR ((unsigned char)'\203')
657#define CTLBACKQ ((unsigned char)'\204')
Denys Vlasenkob6c84342009-08-29 20:23:20 +0200658#define CTLARI ((unsigned char)'\206') /* arithmetic expression */
659#define CTLENDARI ((unsigned char)'\207')
660#define CTLQUOTEMARK ((unsigned char)'\210')
Denys Vlasenko2ce42e92009-11-29 02:18:13 +0100661#define CTL_LAST CTLQUOTEMARK
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000662
663/* variable substitution byte (follows CTLVAR) */
664#define VSTYPE 0x0f /* type of variable substitution */
665#define VSNUL 0x10 /* colon--treat the empty string as unset */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000666
667/* values of VSTYPE field */
Denis Vlasenko92e13c22008-03-25 01:17:40 +0000668#define VSNORMAL 0x1 /* normal variable: $var or ${var} */
669#define VSMINUS 0x2 /* ${var-text} */
670#define VSPLUS 0x3 /* ${var+text} */
671#define VSQUESTION 0x4 /* ${var?message} */
672#define VSASSIGN 0x5 /* ${var=text} */
673#define VSTRIMRIGHT 0x6 /* ${var%pattern} */
674#define VSTRIMRIGHTMAX 0x7 /* ${var%%pattern} */
675#define VSTRIMLEFT 0x8 /* ${var#pattern} */
676#define VSTRIMLEFTMAX 0x9 /* ${var##pattern} */
677#define VSLENGTH 0xa /* ${#var} */
Denys Vlasenko7d4aec02017-01-11 14:00:38 +0100678#if BASH_SUBSTR
Denis Vlasenko92e13c22008-03-25 01:17:40 +0000679#define VSSUBSTR 0xc /* ${var:position:length} */
Denys Vlasenko7d4aec02017-01-11 14:00:38 +0100680#endif
681#if BASH_PATTERN_SUBST
Denis Vlasenko92e13c22008-03-25 01:17:40 +0000682#define VSREPLACE 0xd /* ${var/pattern/replacement} */
683#define VSREPLACEALL 0xe /* ${var//pattern/replacement} */
684#endif
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000685
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000686static const char dolatstr[] ALIGN1 = {
Ron Yorston549deab2015-05-18 09:57:51 +0200687 CTLQUOTEMARK, CTLVAR, VSNORMAL, '@', '=', CTLQUOTEMARK, '\0'
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000688};
Ron Yorston549deab2015-05-18 09:57:51 +0200689#define DOLATSTRLEN 6
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +0000690
Denis Vlasenko559691a2008-10-05 18:39:31 +0000691#define NCMD 0
692#define NPIPE 1
693#define NREDIR 2
694#define NBACKGND 3
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000695#define NSUBSHELL 4
Denis Vlasenko559691a2008-10-05 18:39:31 +0000696#define NAND 5
697#define NOR 6
698#define NSEMI 7
699#define NIF 8
700#define NWHILE 9
701#define NUNTIL 10
702#define NFOR 11
703#define NCASE 12
704#define NCLIST 13
705#define NDEFUN 14
706#define NARG 15
707#define NTO 16
Denys Vlasenko7d4aec02017-01-11 14:00:38 +0100708#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +0000709#define NTO2 17
710#endif
711#define NCLOBBER 18
712#define NFROM 19
713#define NFROMTO 20
714#define NAPPEND 21
715#define NTOFD 22
716#define NFROMFD 23
717#define NHERE 24
718#define NXHERE 25
719#define NNOT 26
Denis Vlasenko340299a2008-11-21 10:36:36 +0000720#define N_NUMBER 27
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000721
722union node;
723
724struct ncmd {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000725 smallint type; /* Nxxxx */
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000726 union node *assign;
727 union node *args;
728 union node *redirect;
729};
730
731struct npipe {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000732 smallint type;
733 smallint pipe_backgnd;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000734 struct nodelist *cmdlist;
735};
736
737struct nredir {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000738 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000739 union node *n;
740 union node *redirect;
741};
742
743struct nbinary {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000744 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000745 union node *ch1;
746 union node *ch2;
747};
748
749struct nif {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000750 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000751 union node *test;
752 union node *ifpart;
753 union node *elsepart;
754};
755
756struct nfor {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000757 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000758 union node *args;
759 union node *body;
760 char *var;
761};
762
763struct ncase {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000764 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000765 union node *expr;
766 union node *cases;
767};
768
769struct nclist {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000770 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000771 union node *next;
772 union node *pattern;
773 union node *body;
774};
775
776struct narg {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000777 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000778 union node *next;
779 char *text;
780 struct nodelist *backquote;
781};
782
Denis Vlasenko559691a2008-10-05 18:39:31 +0000783/* nfile and ndup layout must match!
784 * NTOFD (>&fdnum) uses ndup structure, but we may discover mid-flight
785 * that it is actually NTO2 (>&file), and change its type.
786 */
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000787struct nfile {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000788 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000789 union node *next;
790 int fd;
Denis Vlasenko559691a2008-10-05 18:39:31 +0000791 int _unused_dupfd;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000792 union node *fname;
793 char *expfname;
794};
795
796struct ndup {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000797 smallint type;
Denis Vlasenko559691a2008-10-05 18:39:31 +0000798 union node *next;
799 int fd;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000800 int dupfd;
801 union node *vname;
Denis Vlasenko559691a2008-10-05 18:39:31 +0000802 char *_unused_expfname;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000803};
804
805struct nhere {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000806 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000807 union node *next;
808 int fd;
809 union node *doc;
810};
811
812struct nnot {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000813 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000814 union node *com;
815};
816
817union node {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000818 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000819 struct ncmd ncmd;
820 struct npipe npipe;
821 struct nredir nredir;
822 struct nbinary nbinary;
823 struct nif nif;
824 struct nfor nfor;
825 struct ncase ncase;
826 struct nclist nclist;
827 struct narg narg;
828 struct nfile nfile;
829 struct ndup ndup;
830 struct nhere nhere;
831 struct nnot nnot;
832};
833
Denys Vlasenko86e83ec2009-07-23 22:07:07 +0200834/*
835 * NODE_EOF is returned by parsecmd when it encounters an end of file.
836 * It must be distinct from NULL.
837 */
838#define NODE_EOF ((union node *) -1L)
839
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000840struct nodelist {
841 struct nodelist *next;
842 union node *n;
843};
844
845struct funcnode {
846 int count;
847 union node n;
848};
849
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000850/*
851 * Free a parse tree.
852 */
853static void
854freefunc(struct funcnode *f)
855{
856 if (f && --f->count < 0)
857 free(f);
858}
859
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000860
861/* ============ Debugging output */
862
863#if DEBUG
864
865static FILE *tracefile;
866
867static void
868trace_printf(const char *fmt, ...)
869{
870 va_list va;
871
872 if (debug != 1)
873 return;
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000874 if (DEBUG_TIME)
875 fprintf(tracefile, "%u ", (int) time(NULL));
876 if (DEBUG_PID)
877 fprintf(tracefile, "[%u] ", (int) getpid());
878 if (DEBUG_SIG)
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200879 fprintf(tracefile, "pending s:%d i:%d(supp:%d) ", pending_sig, pending_int, suppress_int);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000880 va_start(va, fmt);
881 vfprintf(tracefile, fmt, va);
882 va_end(va);
883}
884
885static void
886trace_vprintf(const char *fmt, va_list va)
887{
888 if (debug != 1)
889 return;
890 vfprintf(tracefile, fmt, va);
Denys Vlasenko474ed062016-10-30 18:30:29 +0100891 fprintf(tracefile, "\n");
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000892}
893
894static void
895trace_puts(const char *s)
896{
897 if (debug != 1)
898 return;
899 fputs(s, tracefile);
900}
901
902static void
903trace_puts_quoted(char *s)
904{
905 char *p;
906 char c;
907
908 if (debug != 1)
909 return;
910 putc('"', tracefile);
911 for (p = s; *p; p++) {
Denys Vlasenkocd716832009-11-28 22:14:02 +0100912 switch ((unsigned char)*p) {
913 case '\n': c = 'n'; goto backslash;
914 case '\t': c = 't'; goto backslash;
915 case '\r': c = 'r'; goto backslash;
916 case '\"': c = '\"'; goto backslash;
917 case '\\': c = '\\'; goto backslash;
918 case CTLESC: c = 'e'; goto backslash;
919 case CTLVAR: c = 'v'; goto backslash;
Denys Vlasenkocd716832009-11-28 22:14:02 +0100920 case CTLBACKQ: c = 'q'; goto backslash;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000921 backslash:
922 putc('\\', tracefile);
923 putc(c, tracefile);
924 break;
925 default:
926 if (*p >= ' ' && *p <= '~')
927 putc(*p, tracefile);
928 else {
929 putc('\\', tracefile);
Denys Vlasenkocd716832009-11-28 22:14:02 +0100930 putc((*p >> 6) & 03, tracefile);
931 putc((*p >> 3) & 07, tracefile);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000932 putc(*p & 07, tracefile);
933 }
934 break;
935 }
936 }
937 putc('"', tracefile);
938}
939
940static void
941trace_puts_args(char **ap)
942{
943 if (debug != 1)
944 return;
945 if (!*ap)
946 return;
947 while (1) {
948 trace_puts_quoted(*ap);
949 if (!*++ap) {
950 putc('\n', tracefile);
951 break;
952 }
953 putc(' ', tracefile);
954 }
955}
956
957static void
958opentrace(void)
959{
960 char s[100];
961#ifdef O_APPEND
962 int flags;
963#endif
964
965 if (debug != 1) {
966 if (tracefile)
967 fflush(tracefile);
968 /* leave open because libedit might be using it */
969 return;
970 }
971 strcpy(s, "./trace");
972 if (tracefile) {
973 if (!freopen(s, "a", tracefile)) {
974 fprintf(stderr, "Can't re-open %s\n", s);
975 debug = 0;
976 return;
977 }
978 } else {
979 tracefile = fopen(s, "a");
980 if (tracefile == NULL) {
981 fprintf(stderr, "Can't open %s\n", s);
982 debug = 0;
983 return;
984 }
985 }
986#ifdef O_APPEND
Denis Vlasenkod37f2222007-08-19 13:42:08 +0000987 flags = fcntl(fileno(tracefile), F_GETFL);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000988 if (flags >= 0)
989 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
990#endif
991 setlinebuf(tracefile);
992 fputs("\nTracing started.\n", tracefile);
993}
994
995static void
996indent(int amount, char *pfx, FILE *fp)
997{
998 int i;
999
1000 for (i = 0; i < amount; i++) {
1001 if (pfx && i == amount - 1)
1002 fputs(pfx, fp);
1003 putc('\t', fp);
1004 }
1005}
1006
1007/* little circular references here... */
1008static void shtree(union node *n, int ind, char *pfx, FILE *fp);
1009
1010static void
1011sharg(union node *arg, FILE *fp)
1012{
1013 char *p;
1014 struct nodelist *bqlist;
Denys Vlasenkocd716832009-11-28 22:14:02 +01001015 unsigned char subtype;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001016
1017 if (arg->type != NARG) {
1018 out1fmt("<node type %d>\n", arg->type);
1019 abort();
1020 }
1021 bqlist = arg->narg.backquote;
1022 for (p = arg->narg.text; *p; p++) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01001023 switch ((unsigned char)*p) {
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001024 case CTLESC:
Dan Fandrich77d48722010-09-07 23:38:28 -07001025 p++;
1026 putc(*p, fp);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001027 break;
1028 case CTLVAR:
1029 putc('$', fp);
1030 putc('{', fp);
1031 subtype = *++p;
1032 if (subtype == VSLENGTH)
1033 putc('#', fp);
1034
Dan Fandrich77d48722010-09-07 23:38:28 -07001035 while (*p != '=') {
1036 putc(*p, fp);
1037 p++;
1038 }
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001039
1040 if (subtype & VSNUL)
1041 putc(':', fp);
1042
1043 switch (subtype & VSTYPE) {
1044 case VSNORMAL:
1045 putc('}', fp);
1046 break;
1047 case VSMINUS:
1048 putc('-', fp);
1049 break;
1050 case VSPLUS:
1051 putc('+', fp);
1052 break;
1053 case VSQUESTION:
1054 putc('?', fp);
1055 break;
1056 case VSASSIGN:
1057 putc('=', fp);
1058 break;
1059 case VSTRIMLEFT:
1060 putc('#', fp);
1061 break;
1062 case VSTRIMLEFTMAX:
1063 putc('#', fp);
1064 putc('#', fp);
1065 break;
1066 case VSTRIMRIGHT:
1067 putc('%', fp);
1068 break;
1069 case VSTRIMRIGHTMAX:
1070 putc('%', fp);
1071 putc('%', fp);
1072 break;
1073 case VSLENGTH:
1074 break;
1075 default:
1076 out1fmt("<subtype %d>", subtype);
1077 }
1078 break;
1079 case CTLENDVAR:
1080 putc('}', fp);
1081 break;
1082 case CTLBACKQ:
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001083 putc('$', fp);
1084 putc('(', fp);
1085 shtree(bqlist->n, -1, NULL, fp);
1086 putc(')', fp);
1087 break;
1088 default:
1089 putc(*p, fp);
1090 break;
1091 }
1092 }
1093}
1094
Denys Vlasenko641dd7b2009-06-11 19:30:19 +02001095static void
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001096shcmd(union node *cmd, FILE *fp)
1097{
1098 union node *np;
1099 int first;
1100 const char *s;
1101 int dftfd;
1102
1103 first = 1;
1104 for (np = cmd->ncmd.args; np; np = np->narg.next) {
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001105 if (!first)
1106 putc(' ', fp);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001107 sharg(np, fp);
1108 first = 0;
1109 }
1110 for (np = cmd->ncmd.redirect; np; np = np->nfile.next) {
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001111 if (!first)
1112 putc(' ', fp);
1113 dftfd = 0;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001114 switch (np->nfile.type) {
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001115 case NTO: s = ">>"+1; dftfd = 1; break;
1116 case NCLOBBER: s = ">|"; dftfd = 1; break;
1117 case NAPPEND: s = ">>"; dftfd = 1; break;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01001118#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00001119 case NTO2:
1120#endif
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001121 case NTOFD: s = ">&"; dftfd = 1; break;
Denis Vlasenko559691a2008-10-05 18:39:31 +00001122 case NFROM: s = "<"; break;
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001123 case NFROMFD: s = "<&"; break;
1124 case NFROMTO: s = "<>"; break;
1125 default: s = "*error*"; break;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001126 }
1127 if (np->nfile.fd != dftfd)
1128 fprintf(fp, "%d", np->nfile.fd);
1129 fputs(s, fp);
1130 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
1131 fprintf(fp, "%d", np->ndup.dupfd);
1132 } else {
1133 sharg(np->nfile.fname, fp);
1134 }
1135 first = 0;
1136 }
1137}
1138
1139static void
1140shtree(union node *n, int ind, char *pfx, FILE *fp)
1141{
1142 struct nodelist *lp;
1143 const char *s;
1144
1145 if (n == NULL)
1146 return;
1147
1148 indent(ind, pfx, fp);
Denys Vlasenko86e83ec2009-07-23 22:07:07 +02001149
1150 if (n == NODE_EOF) {
1151 fputs("<EOF>", fp);
1152 return;
1153 }
1154
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001155 switch (n->type) {
1156 case NSEMI:
1157 s = "; ";
1158 goto binop;
1159 case NAND:
1160 s = " && ";
1161 goto binop;
1162 case NOR:
1163 s = " || ";
1164 binop:
1165 shtree(n->nbinary.ch1, ind, NULL, fp);
1166 /* if (ind < 0) */
1167 fputs(s, fp);
1168 shtree(n->nbinary.ch2, ind, NULL, fp);
1169 break;
1170 case NCMD:
1171 shcmd(n, fp);
1172 if (ind >= 0)
1173 putc('\n', fp);
1174 break;
1175 case NPIPE:
1176 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
Denys Vlasenko7cee00e2009-07-24 01:08:03 +02001177 shtree(lp->n, 0, NULL, fp);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001178 if (lp->next)
1179 fputs(" | ", fp);
1180 }
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00001181 if (n->npipe.pipe_backgnd)
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001182 fputs(" &", fp);
1183 if (ind >= 0)
1184 putc('\n', fp);
1185 break;
1186 default:
1187 fprintf(fp, "<node type %d>", n->type);
1188 if (ind >= 0)
1189 putc('\n', fp);
1190 break;
1191 }
1192}
1193
1194static void
1195showtree(union node *n)
1196{
1197 trace_puts("showtree called\n");
Denys Vlasenko883cea42009-07-11 15:31:59 +02001198 shtree(n, 1, NULL, stderr);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001199}
1200
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001201#endif /* DEBUG */
1202
1203
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00001204/* ============ Parser data */
1205
1206/*
Denis Vlasenkob012b102007-02-19 22:43:01 +00001207 * ash_vmsg() needs parsefile->fd, hence parsefile definition is moved up.
1208 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001209struct strlist {
1210 struct strlist *next;
1211 char *text;
1212};
1213
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001214struct alias;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001215
Denis Vlasenkob012b102007-02-19 22:43:01 +00001216struct strpush {
1217 struct strpush *prev; /* preceding string on stack */
Denis Vlasenko41eb3002008-11-28 03:42:31 +00001218 char *prev_string;
1219 int prev_left_in_line;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001220#if ENABLE_ASH_ALIAS
1221 struct alias *ap; /* if push was associated with an alias */
1222#endif
1223 char *string; /* remember the string since it may change */
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02001224
1225 /* Remember last two characters for pungetc. */
1226 int lastc[2];
1227
1228 /* Number of outstanding calls to pungetc. */
1229 int unget;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001230};
1231
Denys Vlasenko0485b672017-08-14 19:46:56 +02001232/*
1233 * The parsefile structure pointed to by the global variable parsefile
1234 * contains information about the current file being read.
1235 */
Denis Vlasenkob012b102007-02-19 22:43:01 +00001236struct parsefile {
1237 struct parsefile *prev; /* preceding file on stack */
1238 int linno; /* current line */
Denys Vlasenko79b3d422010-06-03 04:29:08 +02001239 int pf_fd; /* file descriptor (or -1 if string) */
Denis Vlasenko41eb3002008-11-28 03:42:31 +00001240 int left_in_line; /* number of chars left in this line */
1241 int left_in_buffer; /* number of chars left in this buffer past the line */
1242 char *next_to_pgetc; /* next char in buffer */
Denis Vlasenkob012b102007-02-19 22:43:01 +00001243 char *buf; /* input buffer */
1244 struct strpush *strpush; /* for pushing strings at this level */
1245 struct strpush basestrpush; /* so pushing one is fast */
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02001246
1247 /* Remember last two characters for pungetc. */
1248 int lastc[2];
1249
1250 /* Number of outstanding calls to pungetc. */
1251 int unget;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001252};
1253
Denis Vlasenko448d30e2008-06-27 00:24:11 +00001254static struct parsefile basepf; /* top level input file */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00001255static struct parsefile *g_parsefile = &basepf; /* current input file */
Denis Vlasenkob012b102007-02-19 22:43:01 +00001256static int startlinno; /* line # where last token started */
1257static char *commandname; /* currently executing command */
Denis Vlasenkob012b102007-02-19 22:43:01 +00001258
1259
1260/* ============ Message printing */
1261
1262static void
1263ash_vmsg(const char *msg, va_list ap)
1264{
1265 fprintf(stderr, "%s: ", arg0);
1266 if (commandname) {
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00001267 if (strcmp(arg0, commandname))
1268 fprintf(stderr, "%s: ", commandname);
Denys Vlasenko79b3d422010-06-03 04:29:08 +02001269 if (!iflag || g_parsefile->pf_fd > 0)
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00001270 fprintf(stderr, "line %d: ", startlinno);
Eric Andersenc470f442003-07-28 09:56:35 +00001271 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00001272 vfprintf(stderr, msg, ap);
Denys Vlasenko9c541002015-10-07 15:44:36 +02001273 newline_and_flush(stderr);
Eric Andersenc470f442003-07-28 09:56:35 +00001274}
Denis Vlasenkob012b102007-02-19 22:43:01 +00001275
1276/*
1277 * Exverror is called to raise the error exception. If the second argument
1278 * is not NULL then error prints an error message using printf style
1279 * formatting. It then raises the error exception.
1280 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00001281static void ash_vmsg_and_raise(int, const char *, va_list) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001282static void
1283ash_vmsg_and_raise(int cond, const char *msg, va_list ap)
Eric Andersenc470f442003-07-28 09:56:35 +00001284{
Denis Vlasenkob012b102007-02-19 22:43:01 +00001285#if DEBUG
1286 if (msg) {
Denys Vlasenko474ed062016-10-30 18:30:29 +01001287 TRACE(("ash_vmsg_and_raise(%d):", cond));
Denis Vlasenkob012b102007-02-19 22:43:01 +00001288 TRACEV((msg, ap));
Denis Vlasenkob012b102007-02-19 22:43:01 +00001289 } else
Denys Vlasenko474ed062016-10-30 18:30:29 +01001290 TRACE(("ash_vmsg_and_raise(%d):NULL\n", cond));
Denis Vlasenkob012b102007-02-19 22:43:01 +00001291 if (msg)
1292#endif
1293 ash_vmsg(msg, ap);
1294
1295 flush_stdout_stderr();
1296 raise_exception(cond);
1297 /* NOTREACHED */
Eric Andersenc470f442003-07-28 09:56:35 +00001298}
Denis Vlasenkob012b102007-02-19 22:43:01 +00001299
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00001300static void ash_msg_and_raise_error(const char *, ...) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001301static void
1302ash_msg_and_raise_error(const char *msg, ...)
1303{
1304 va_list ap;
1305
Ron Yorstonea7d2f62017-01-03 11:18:23 +01001306 exitstatus = 2;
1307
Denis Vlasenkob012b102007-02-19 22:43:01 +00001308 va_start(ap, msg);
1309 ash_vmsg_and_raise(EXERROR, msg, ap);
1310 /* NOTREACHED */
1311 va_end(ap);
1312}
1313
Ron Yorstonbe366e52017-07-27 13:53:39 +01001314/*
Ron Yorstonbe366e52017-07-27 13:53:39 +01001315 * 'fmt' must be a string literal.
1316 */
Denys Vlasenko6f97b302017-09-29 18:17:25 +02001317#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 +01001318
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00001319static void raise_error_syntax(const char *) NORETURN;
1320static void
1321raise_error_syntax(const char *msg)
1322{
1323 ash_msg_and_raise_error("syntax error: %s", msg);
1324 /* NOTREACHED */
1325}
1326
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00001327static void ash_msg_and_raise(int, const char *, ...) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001328static void
1329ash_msg_and_raise(int cond, const char *msg, ...)
1330{
1331 va_list ap;
1332
1333 va_start(ap, msg);
1334 ash_vmsg_and_raise(cond, msg, ap);
1335 /* NOTREACHED */
1336 va_end(ap);
1337}
1338
1339/*
1340 * error/warning routines for external builtins
1341 */
1342static void
1343ash_msg(const char *fmt, ...)
1344{
1345 va_list ap;
1346
1347 va_start(ap, fmt);
1348 ash_vmsg(fmt, ap);
1349 va_end(ap);
1350}
1351
1352/*
1353 * Return a string describing an error. The returned string may be a
1354 * pointer to a static buffer that will be overwritten on the next call.
1355 * Action describes the operation that got the error.
1356 */
1357static const char *
1358errmsg(int e, const char *em)
1359{
1360 if (e == ENOENT || e == ENOTDIR) {
1361 return em;
1362 }
1363 return strerror(e);
1364}
1365
1366
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001367/* ============ Memory allocation */
1368
Denys Vlasenkoe7670ff2009-10-11 00:45:25 +02001369#if 0
1370/* I consider these wrappers nearly useless:
1371 * ok, they return you to nearest exception handler, but
1372 * how much memory do you leak in the process, making
1373 * memory starvation worse?
1374 */
1375static void *
1376ckrealloc(void * p, size_t nbytes)
1377{
1378 p = realloc(p, nbytes);
1379 if (!p)
1380 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1381 return p;
1382}
1383
1384static void *
1385ckmalloc(size_t nbytes)
1386{
1387 return ckrealloc(NULL, nbytes);
1388}
1389
1390static void *
1391ckzalloc(size_t nbytes)
1392{
1393 return memset(ckmalloc(nbytes), 0, nbytes);
1394}
1395
1396static char *
1397ckstrdup(const char *s)
1398{
1399 char *p = strdup(s);
1400 if (!p)
1401 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1402 return p;
1403}
1404#else
1405/* Using bbox equivalents. They exit if out of memory */
1406# define ckrealloc xrealloc
1407# define ckmalloc xmalloc
1408# define ckzalloc xzalloc
1409# define ckstrdup xstrdup
1410#endif
1411
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001412/*
1413 * It appears that grabstackstr() will barf with such alignments
1414 * because stalloc() will return a string allocated in a new stackblock.
1415 */
1416#define SHELL_ALIGN(nbytes) (((nbytes) + SHELL_SIZE) & ~SHELL_SIZE)
1417enum {
1418 /* Most machines require the value returned from malloc to be aligned
1419 * in some way. The following macro will get this right
1420 * on many machines. */
Denys Vlasenko0e5e4ea2009-10-11 00:36:20 +02001421 SHELL_SIZE = sizeof(union { int i; char *cp; double d; }) - 1,
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001422 /* Minimum size of a block */
Denis Vlasenko01631112007-12-16 17:20:38 +00001423 MINSIZE = SHELL_ALIGN(504),
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001424};
1425
1426struct stack_block {
1427 struct stack_block *prev;
1428 char space[MINSIZE];
1429};
1430
1431struct stackmark {
1432 struct stack_block *stackp;
1433 char *stacknxt;
1434 size_t stacknleft;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001435};
1436
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001437
Denis Vlasenko01631112007-12-16 17:20:38 +00001438struct globals_memstack {
1439 struct stack_block *g_stackp; // = &stackbase;
Denis Vlasenko01631112007-12-16 17:20:38 +00001440 char *g_stacknxt; // = stackbase.space;
1441 char *sstrend; // = stackbase.space + MINSIZE;
1442 size_t g_stacknleft; // = MINSIZE;
Denis Vlasenko01631112007-12-16 17:20:38 +00001443 struct stack_block stackbase;
1444};
Denis Vlasenko574f2f42008-02-27 18:41:59 +00001445extern struct globals_memstack *const ash_ptr_to_globals_memstack;
1446#define G_memstack (*ash_ptr_to_globals_memstack)
Denis Vlasenko01631112007-12-16 17:20:38 +00001447#define g_stackp (G_memstack.g_stackp )
Denis Vlasenko01631112007-12-16 17:20:38 +00001448#define g_stacknxt (G_memstack.g_stacknxt )
1449#define sstrend (G_memstack.sstrend )
1450#define g_stacknleft (G_memstack.g_stacknleft)
Denis Vlasenko01631112007-12-16 17:20:38 +00001451#define stackbase (G_memstack.stackbase )
1452#define INIT_G_memstack() do { \
Denis Vlasenko574f2f42008-02-27 18:41:59 +00001453 (*(struct globals_memstack**)&ash_ptr_to_globals_memstack) = xzalloc(sizeof(G_memstack)); \
1454 barrier(); \
Denis Vlasenko01631112007-12-16 17:20:38 +00001455 g_stackp = &stackbase; \
1456 g_stacknxt = stackbase.space; \
1457 g_stacknleft = MINSIZE; \
1458 sstrend = stackbase.space + MINSIZE; \
Denis Vlasenko01631112007-12-16 17:20:38 +00001459} while (0)
1460
Denys Vlasenkoe7670ff2009-10-11 00:45:25 +02001461
Denis Vlasenko01631112007-12-16 17:20:38 +00001462#define stackblock() ((void *)g_stacknxt)
1463#define stackblocksize() g_stacknleft
1464
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001465/*
1466 * Parse trees for commands are allocated in lifo order, so we use a stack
1467 * to make this more efficient, and also to avoid all sorts of exception
1468 * handling code to handle interrupts in the middle of a parse.
1469 *
1470 * The size 504 was chosen because the Ultrix malloc handles that size
1471 * well.
1472 */
1473static void *
1474stalloc(size_t nbytes)
1475{
1476 char *p;
1477 size_t aligned;
1478
1479 aligned = SHELL_ALIGN(nbytes);
Denis Vlasenko01631112007-12-16 17:20:38 +00001480 if (aligned > g_stacknleft) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001481 size_t len;
1482 size_t blocksize;
1483 struct stack_block *sp;
1484
1485 blocksize = aligned;
1486 if (blocksize < MINSIZE)
1487 blocksize = MINSIZE;
1488 len = sizeof(struct stack_block) - MINSIZE + blocksize;
1489 if (len < blocksize)
1490 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1491 INT_OFF;
1492 sp = ckmalloc(len);
Denis Vlasenko01631112007-12-16 17:20:38 +00001493 sp->prev = g_stackp;
1494 g_stacknxt = sp->space;
1495 g_stacknleft = blocksize;
1496 sstrend = g_stacknxt + blocksize;
1497 g_stackp = sp;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001498 INT_ON;
1499 }
Denis Vlasenko01631112007-12-16 17:20:38 +00001500 p = g_stacknxt;
1501 g_stacknxt += aligned;
1502 g_stacknleft -= aligned;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001503 return p;
1504}
1505
Denis Vlasenko597906c2008-02-20 16:38:54 +00001506static void *
1507stzalloc(size_t nbytes)
1508{
1509 return memset(stalloc(nbytes), 0, nbytes);
1510}
1511
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001512static void
1513stunalloc(void *p)
1514{
1515#if DEBUG
Denis Vlasenko01631112007-12-16 17:20:38 +00001516 if (!p || (g_stacknxt < (char *)p) || ((char *)p < g_stackp->space)) {
Bernhard Reutner-Fischer5e25ddb2008-05-19 09:48:17 +00001517 write(STDERR_FILENO, "stunalloc\n", 10);
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001518 abort();
1519 }
1520#endif
Denis Vlasenko01631112007-12-16 17:20:38 +00001521 g_stacknleft += g_stacknxt - (char *)p;
1522 g_stacknxt = p;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001523}
1524
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001525/*
1526 * Like strdup but works with the ash stack.
1527 */
1528static char *
Denys Vlasenko8e2bc472016-09-28 23:02:57 +02001529sstrdup(const char *p)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001530{
1531 size_t len = strlen(p) + 1;
1532 return memcpy(stalloc(len), p, len);
1533}
1534
Denys Vlasenkoa318bba2016-10-26 18:26:27 +02001535static inline void
Denys Vlasenko60ca8342016-09-30 11:21:21 +02001536grabstackblock(size_t len)
1537{
Denys Vlasenkoa318bba2016-10-26 18:26:27 +02001538 stalloc(len);
Denys Vlasenko60ca8342016-09-30 11:21:21 +02001539}
1540
1541static void
1542pushstackmark(struct stackmark *mark, size_t len)
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001543{
Denis Vlasenko01631112007-12-16 17:20:38 +00001544 mark->stackp = g_stackp;
1545 mark->stacknxt = g_stacknxt;
1546 mark->stacknleft = g_stacknleft;
Denys Vlasenko60ca8342016-09-30 11:21:21 +02001547 grabstackblock(len);
1548}
1549
1550static void
1551setstackmark(struct stackmark *mark)
1552{
1553 pushstackmark(mark, g_stacknxt == g_stackp->space && g_stackp != &stackbase);
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001554}
1555
1556static void
1557popstackmark(struct stackmark *mark)
1558{
1559 struct stack_block *sp;
1560
Denis Vlasenko93ebd4f2007-03-13 20:55:36 +00001561 if (!mark->stackp)
1562 return;
1563
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001564 INT_OFF;
Denis Vlasenko01631112007-12-16 17:20:38 +00001565 while (g_stackp != mark->stackp) {
1566 sp = g_stackp;
1567 g_stackp = sp->prev;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001568 free(sp);
1569 }
Denis Vlasenko01631112007-12-16 17:20:38 +00001570 g_stacknxt = mark->stacknxt;
1571 g_stacknleft = mark->stacknleft;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001572 sstrend = mark->stacknxt + mark->stacknleft;
1573 INT_ON;
1574}
1575
1576/*
1577 * When the parser reads in a string, it wants to stick the string on the
1578 * stack and only adjust the stack pointer when it knows how big the
1579 * string is. Stackblock (defined in stack.h) returns a pointer to a block
1580 * of space on top of the stack and stackblocklen returns the length of
1581 * this block. Growstackblock will grow this space by at least one byte,
1582 * possibly moving it (like realloc). Grabstackblock actually allocates the
1583 * part of the block that has been used.
1584 */
1585static void
1586growstackblock(void)
1587{
1588 size_t newlen;
1589
Denis Vlasenko01631112007-12-16 17:20:38 +00001590 newlen = g_stacknleft * 2;
1591 if (newlen < g_stacknleft)
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001592 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1593 if (newlen < 128)
1594 newlen += 128;
1595
Denis Vlasenko01631112007-12-16 17:20:38 +00001596 if (g_stacknxt == g_stackp->space && g_stackp != &stackbase) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001597 struct stack_block *sp;
1598 struct stack_block *prevstackp;
1599 size_t grosslen;
1600
1601 INT_OFF;
Denis Vlasenko01631112007-12-16 17:20:38 +00001602 sp = g_stackp;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001603 prevstackp = sp->prev;
1604 grosslen = newlen + sizeof(struct stack_block) - MINSIZE;
1605 sp = ckrealloc(sp, grosslen);
1606 sp->prev = prevstackp;
Denis Vlasenko01631112007-12-16 17:20:38 +00001607 g_stackp = sp;
1608 g_stacknxt = sp->space;
1609 g_stacknleft = newlen;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001610 sstrend = sp->space + newlen;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001611 INT_ON;
1612 } else {
Denis Vlasenko01631112007-12-16 17:20:38 +00001613 char *oldspace = g_stacknxt;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001614 size_t oldlen = g_stacknleft;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001615 char *p = stalloc(newlen);
1616
1617 /* free the space we just allocated */
Denis Vlasenko01631112007-12-16 17:20:38 +00001618 g_stacknxt = memcpy(p, oldspace, oldlen);
1619 g_stacknleft += newlen;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001620 }
1621}
1622
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001623/*
1624 * The following routines are somewhat easier to use than the above.
1625 * The user declares a variable of type STACKSTR, which may be declared
1626 * to be a register. The macro STARTSTACKSTR initializes things. Then
1627 * the user uses the macro STPUTC to add characters to the string. In
1628 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
1629 * grown as necessary. When the user is done, she can just leave the
1630 * string there and refer to it using stackblock(). Or she can allocate
1631 * the space for it using grabstackstr(). If it is necessary to allow
1632 * someone else to use the stack temporarily and then continue to grow
1633 * the string, the user should use grabstack to allocate the space, and
1634 * then call ungrabstr(p) to return to the previous mode of operation.
1635 *
1636 * USTPUTC is like STPUTC except that it doesn't check for overflow.
1637 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
1638 * is space for at least one character.
1639 */
1640static void *
1641growstackstr(void)
1642{
1643 size_t len = stackblocksize();
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001644 growstackblock();
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001645 return (char *)stackblock() + len;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001646}
1647
1648/*
1649 * Called from CHECKSTRSPACE.
1650 */
1651static char *
1652makestrspace(size_t newlen, char *p)
1653{
Denis Vlasenko01631112007-12-16 17:20:38 +00001654 size_t len = p - g_stacknxt;
Denys Vlasenko53d6e032016-09-30 11:24:12 +02001655 size_t size;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001656
1657 for (;;) {
1658 size_t nleft;
1659
1660 size = stackblocksize();
1661 nleft = size - len;
1662 if (nleft >= newlen)
1663 break;
1664 growstackblock();
1665 }
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001666 return (char *)stackblock() + len;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001667}
1668
1669static char *
1670stack_nputstr(const char *s, size_t n, char *p)
1671{
1672 p = makestrspace(n, p);
Denys Vlasenko5ace96a2017-07-23 21:46:02 +02001673 p = (char *)mempcpy(p, s, n);
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001674 return p;
1675}
1676
1677static char *
1678stack_putstr(const char *s, char *p)
1679{
1680 return stack_nputstr(s, strlen(s), p);
1681}
1682
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001683static char *
1684_STPUTC(int c, char *p)
1685{
1686 if (p == sstrend)
1687 p = growstackstr();
1688 *p++ = c;
1689 return p;
1690}
1691
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00001692#define STARTSTACKSTR(p) ((p) = stackblock())
1693#define STPUTC(c, p) ((p) = _STPUTC((c), (p)))
Denis Vlasenko843cbd52008-06-27 00:23:18 +00001694#define CHECKSTRSPACE(n, p) do { \
1695 char *q = (p); \
1696 size_t l = (n); \
1697 size_t m = sstrend - q; \
1698 if (l > m) \
1699 (p) = makestrspace(l, q); \
1700} while (0)
Denis Vlasenkoef527f52008-06-23 01:52:30 +00001701#define USTPUTC(c, p) (*(p)++ = (c))
Denis Vlasenko843cbd52008-06-27 00:23:18 +00001702#define STACKSTRNUL(p) do { \
1703 if ((p) == sstrend) \
1704 (p) = growstackstr(); \
1705 *(p) = '\0'; \
1706} while (0)
Denis Vlasenkoef527f52008-06-23 01:52:30 +00001707#define STUNPUTC(p) (--(p))
1708#define STTOPC(p) ((p)[-1])
1709#define STADJUST(amount, p) ((p) += (amount))
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001710
1711#define grabstackstr(p) stalloc((char *)(p) - (char *)stackblock())
Denis Vlasenkoef527f52008-06-23 01:52:30 +00001712#define ungrabstackstr(s, p) stunalloc(s)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001713#define stackstrend() ((void *)sstrend)
1714
1715
1716/* ============ String helpers */
1717
1718/*
1719 * prefix -- see if pfx is a prefix of string.
1720 */
1721static char *
1722prefix(const char *string, const char *pfx)
1723{
1724 while (*pfx) {
1725 if (*pfx++ != *string++)
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00001726 return NULL;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001727 }
1728 return (char *) string;
1729}
1730
1731/*
1732 * Check for a valid number. This should be elsewhere.
1733 */
1734static int
1735is_number(const char *p)
1736{
1737 do {
1738 if (!isdigit(*p))
1739 return 0;
1740 } while (*++p != '\0');
1741 return 1;
1742}
1743
1744/*
1745 * Convert a string of digits to an integer, printing an error message on
1746 * failure.
1747 */
1748static int
1749number(const char *s)
1750{
1751 if (!is_number(s))
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02001752 ash_msg_and_raise_error(msg_illnum, s);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001753 return atoi(s);
1754}
1755
1756/*
Denys Vlasenko42ba7572017-07-21 13:20:14 +02001757 * Produce a single quoted string suitable as input to the shell.
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001758 * The return string is allocated on the stack.
1759 */
1760static char *
1761single_quote(const char *s)
1762{
1763 char *p;
1764
1765 STARTSTACKSTR(p);
1766
1767 do {
1768 char *q;
1769 size_t len;
1770
1771 len = strchrnul(s, '\'') - s;
1772
1773 q = p = makestrspace(len + 3, p);
1774
1775 *q++ = '\'';
Denys Vlasenko94af83e2017-07-23 21:55:40 +02001776 q = (char *)mempcpy(q, s, len);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001777 *q++ = '\'';
1778 s += len;
1779
1780 STADJUST(q - p, p);
1781
Denys Vlasenkocd716832009-11-28 22:14:02 +01001782 if (*s != '\'')
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001783 break;
Denys Vlasenkocd716832009-11-28 22:14:02 +01001784 len = 0;
1785 do len++; while (*++s == '\'');
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001786
1787 q = p = makestrspace(len + 3, p);
1788
1789 *q++ = '"';
Denys Vlasenko5ace96a2017-07-23 21:46:02 +02001790 q = (char *)mempcpy(q, s - len, len);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001791 *q++ = '"';
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001792
1793 STADJUST(q - p, p);
1794 } while (*s);
1795
Denys Vlasenkocd716832009-11-28 22:14:02 +01001796 USTPUTC('\0', p);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001797
1798 return stackblock();
1799}
1800
Denys Vlasenko42ba7572017-07-21 13:20:14 +02001801/*
1802 * Produce a possibly single quoted string suitable as input to the shell.
Denys Vlasenko42ba7572017-07-21 13:20:14 +02001803 * If quoting was done, the return string is allocated on the stack,
1804 * otherwise a pointer to the original string is returned.
1805 */
1806static const char *
1807maybe_single_quote(const char *s)
1808{
1809 const char *p = s;
1810
1811 while (*p) {
1812 /* Assuming ACSII */
1813 /* quote ctrl_chars space !"#$%&'()* */
1814 if (*p < '+')
1815 goto need_quoting;
1816 /* quote ;<=>? */
1817 if (*p >= ';' && *p <= '?')
1818 goto need_quoting;
1819 /* quote `[\ */
1820 if (*p == '`')
1821 goto need_quoting;
1822 if (*p == '[')
1823 goto need_quoting;
1824 if (*p == '\\')
1825 goto need_quoting;
1826 /* quote {|}~ DEL and high bytes */
1827 if (*p > 'z')
1828 goto need_quoting;
1829 /* Not quoting these: +,-./ 0-9 :@ A-Z ]^_ a-z */
1830 /* TODO: maybe avoid quoting % */
1831 p++;
1832 }
1833 return s;
1834
1835 need_quoting:
1836 return single_quote(s);
1837}
1838
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001839
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00001840/* ============ nextopt */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001841
1842static char **argptr; /* argument list for builtin commands */
1843static char *optionarg; /* set by nextopt (like getopt) */
1844static char *optptr; /* used by nextopt */
1845
1846/*
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001847 * XXX - should get rid of. Have all builtins use getopt(3).
1848 * The library getopt must have the BSD extension static variable
1849 * "optreset", otherwise it can't be used within the shell safely.
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001850 *
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001851 * Standard option processing (a la getopt) for builtin routines.
1852 * The only argument that is passed to nextopt is the option string;
1853 * the other arguments are unnecessary. It returns the character,
1854 * or '\0' on end of input.
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001855 */
1856static int
1857nextopt(const char *optstring)
1858{
1859 char *p;
1860 const char *q;
1861 char c;
1862
1863 p = optptr;
1864 if (p == NULL || *p == '\0') {
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001865 /* We ate entire "-param", take next one */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001866 p = *argptr;
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001867 if (p == NULL)
1868 return '\0';
1869 if (*p != '-')
1870 return '\0';
1871 if (*++p == '\0') /* just "-" ? */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001872 return '\0';
1873 argptr++;
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001874 if (LONE_DASH(p)) /* "--" ? */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001875 return '\0';
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001876 /* p => next "-param" */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001877 }
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001878 /* p => some option char in the middle of a "-param" */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001879 c = *p++;
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +00001880 for (q = optstring; *q != c;) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001881 if (*q == '\0')
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00001882 ash_msg_and_raise_error("illegal option -%c", c);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001883 if (*++q == ':')
1884 q++;
1885 }
1886 if (*++q == ':') {
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001887 if (*p == '\0') {
1888 p = *argptr++;
1889 if (p == NULL)
1890 ash_msg_and_raise_error("no arg for -%c option", c);
1891 }
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001892 optionarg = p;
1893 p = NULL;
1894 }
1895 optptr = p;
1896 return c;
1897}
1898
1899
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00001900/* ============ Shell variables */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001901
Denis Vlasenko01631112007-12-16 17:20:38 +00001902struct shparam {
1903 int nparam; /* # of positional parameters (without $0) */
1904#if ENABLE_ASH_GETOPTS
1905 int optind; /* next parameter to be processed by getopts */
1906 int optoff; /* used by getopts */
1907#endif
1908 unsigned char malloced; /* if parameter list dynamically allocated */
1909 char **p; /* parameter list */
1910};
1911
1912/*
1913 * Free the list of positional parameters.
1914 */
1915static void
1916freeparam(volatile struct shparam *param)
1917{
Denis Vlasenko01631112007-12-16 17:20:38 +00001918 if (param->malloced) {
Denis Vlasenko3177ba02008-07-13 20:39:23 +00001919 char **ap, **ap1;
1920 ap = ap1 = param->p;
1921 while (*ap)
1922 free(*ap++);
1923 free(ap1);
Denis Vlasenko01631112007-12-16 17:20:38 +00001924 }
1925}
1926
1927#if ENABLE_ASH_GETOPTS
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02001928static void FAST_FUNC getoptsreset(const char *value);
Denis Vlasenko01631112007-12-16 17:20:38 +00001929#endif
1930
1931struct var {
1932 struct var *next; /* next entry in hash list */
1933 int flags; /* flags are defined above */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001934 const char *var_text; /* name=value */
1935 void (*var_func)(const char *) FAST_FUNC; /* function to be called when */
Denis Vlasenko01631112007-12-16 17:20:38 +00001936 /* the variable gets set/unset */
1937};
1938
1939struct localvar {
1940 struct localvar *next; /* next local variable in list */
1941 struct var *vp; /* the variable that was made local */
1942 int flags; /* saved flags */
1943 const char *text; /* saved text */
1944};
1945
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001946/* flags */
1947#define VEXPORT 0x01 /* variable is exported */
1948#define VREADONLY 0x02 /* variable cannot be modified */
1949#define VSTRFIXED 0x04 /* variable struct is statically allocated */
1950#define VTEXTFIXED 0x08 /* text is statically allocated */
1951#define VSTACK 0x10 /* text is allocated on the stack */
1952#define VUNSET 0x20 /* the variable is not set */
1953#define VNOFUNC 0x40 /* don't call the callback function */
1954#define VNOSET 0x80 /* do not set variable - just readonly test */
1955#define VNOSAVE 0x100 /* when text is on the heap before setvareq */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00001956#if ENABLE_ASH_RANDOM_SUPPORT
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00001957# define VDYNAMIC 0x200 /* dynamic variable */
1958#else
1959# define VDYNAMIC 0
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001960#endif
1961
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00001962
Denis Vlasenko01631112007-12-16 17:20:38 +00001963/* Need to be before varinit_data[] */
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00001964#if ENABLE_LOCALE_SUPPORT
Denys Vlasenko2634bf32009-06-09 18:40:07 +02001965static void FAST_FUNC
Denis Vlasenkoa8915072007-02-23 21:10:06 +00001966change_lc_all(const char *value)
1967{
1968 if (value && *value != '\0')
1969 setlocale(LC_ALL, value);
1970}
Denys Vlasenko2634bf32009-06-09 18:40:07 +02001971static void FAST_FUNC
Denis Vlasenkoa8915072007-02-23 21:10:06 +00001972change_lc_ctype(const char *value)
1973{
1974 if (value && *value != '\0')
1975 setlocale(LC_CTYPE, value);
1976}
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00001977#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001978#if ENABLE_ASH_MAIL
1979static void chkmail(void);
Denys Vlasenko8c52f802011-02-04 17:36:21 +01001980static void changemail(const char *var_value) FAST_FUNC;
1981#else
1982# define chkmail() ((void)0)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001983#endif
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02001984static void changepath(const char *) FAST_FUNC;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001985#if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02001986static void change_random(const char *) FAST_FUNC;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001987#endif
1988
Denis Vlasenko01631112007-12-16 17:20:38 +00001989static const struct {
1990 int flags;
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001991 const char *var_text;
1992 void (*var_func)(const char *) FAST_FUNC;
Denis Vlasenko01631112007-12-16 17:20:38 +00001993} varinit_data[] = {
Denys Vlasenko566a3132012-07-07 21:40:35 +02001994 /*
1995 * Note: VEXPORT would not work correctly here for NOFORK applets:
1996 * some environment strings may be constant.
1997 */
Denis Vlasenko01631112007-12-16 17:20:38 +00001998 { VSTRFIXED|VTEXTFIXED , defifsvar , NULL },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001999#if ENABLE_ASH_MAIL
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002000 { VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL" , changemail },
2001 { VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH" , changemail },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002002#endif
Denis Vlasenko01631112007-12-16 17:20:38 +00002003 { VSTRFIXED|VTEXTFIXED , bb_PATH_root_path, changepath },
2004 { VSTRFIXED|VTEXTFIXED , "PS1=$ " , NULL },
2005 { VSTRFIXED|VTEXTFIXED , "PS2=> " , NULL },
2006 { VSTRFIXED|VTEXTFIXED , "PS4=+ " , NULL },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002007#if ENABLE_ASH_GETOPTS
Denys Vlasenkoe627ac92016-09-30 14:36:59 +02002008 { VSTRFIXED|VTEXTFIXED , defoptindvar, getoptsreset },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002009#endif
2010#if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002011 { VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM", change_random },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002012#endif
2013#if ENABLE_LOCALE_SUPPORT
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002014 { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_ALL" , change_lc_all },
2015 { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_CTYPE" , change_lc_ctype },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002016#endif
2017#if ENABLE_FEATURE_EDITING_SAVEHISTORY
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002018 { VSTRFIXED|VTEXTFIXED|VUNSET, "HISTFILE" , NULL },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002019#endif
2020};
2021
Denis Vlasenko0b769642008-07-24 07:54:57 +00002022struct redirtab;
Denis Vlasenko01631112007-12-16 17:20:38 +00002023
2024struct globals_var {
2025 struct shparam shellparam; /* $@ current positional parameters */
2026 struct redirtab *redirlist;
Denys Vlasenkod07a15b2017-07-30 16:51:05 +02002027 int preverrout_fd; /* stderr fd: usually 2, unless redirect moved it */
Denis Vlasenko01631112007-12-16 17:20:38 +00002028 struct var *vartab[VTABSIZE];
2029 struct var varinit[ARRAY_SIZE(varinit_data)];
2030};
Denis Vlasenko574f2f42008-02-27 18:41:59 +00002031extern struct globals_var *const ash_ptr_to_globals_var;
2032#define G_var (*ash_ptr_to_globals_var)
Denis Vlasenko01631112007-12-16 17:20:38 +00002033#define shellparam (G_var.shellparam )
Denis Vlasenko0b769642008-07-24 07:54:57 +00002034//#define redirlist (G_var.redirlist )
Denis Vlasenko01631112007-12-16 17:20:38 +00002035#define preverrout_fd (G_var.preverrout_fd)
2036#define vartab (G_var.vartab )
2037#define varinit (G_var.varinit )
2038#define INIT_G_var() do { \
Denis Vlasenko6b06cb82008-05-15 21:30:45 +00002039 unsigned i; \
Denis Vlasenko574f2f42008-02-27 18:41:59 +00002040 (*(struct globals_var**)&ash_ptr_to_globals_var) = xzalloc(sizeof(G_var)); \
2041 barrier(); \
Denis Vlasenko01631112007-12-16 17:20:38 +00002042 for (i = 0; i < ARRAY_SIZE(varinit_data); i++) { \
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002043 varinit[i].flags = varinit_data[i].flags; \
2044 varinit[i].var_text = varinit_data[i].var_text; \
2045 varinit[i].var_func = varinit_data[i].var_func; \
Denis Vlasenko01631112007-12-16 17:20:38 +00002046 } \
2047} while (0)
2048
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002049#define vifs varinit[0]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002050#if ENABLE_ASH_MAIL
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002051# define vmail (&vifs)[1]
2052# define vmpath (&vmail)[1]
2053# define vpath (&vmpath)[1]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002054#else
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002055# define vpath (&vifs)[1]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002056#endif
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002057#define vps1 (&vpath)[1]
2058#define vps2 (&vps1)[1]
2059#define vps4 (&vps2)[1]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002060#if ENABLE_ASH_GETOPTS
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002061# define voptind (&vps4)[1]
2062# if ENABLE_ASH_RANDOM_SUPPORT
2063# define vrandom (&voptind)[1]
2064# endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002065#else
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002066# if ENABLE_ASH_RANDOM_SUPPORT
2067# define vrandom (&vps4)[1]
2068# endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002069#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002070
2071/*
2072 * The following macros access the values of the above variables.
2073 * They have to skip over the name. They return the null string
2074 * for unset variables.
2075 */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002076#define ifsval() (vifs.var_text + 4)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002077#define ifsset() ((vifs.flags & VUNSET) == 0)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002078#if ENABLE_ASH_MAIL
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002079# define mailval() (vmail.var_text + 5)
2080# define mpathval() (vmpath.var_text + 9)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002081# define mpathset() ((vmpath.flags & VUNSET) == 0)
2082#endif
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002083#define pathval() (vpath.var_text + 5)
2084#define ps1val() (vps1.var_text + 4)
2085#define ps2val() (vps2.var_text + 4)
2086#define ps4val() (vps4.var_text + 4)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002087#if ENABLE_ASH_GETOPTS
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002088# define optindval() (voptind.var_text + 7)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002089#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002090
Denis Vlasenko01631112007-12-16 17:20:38 +00002091#if ENABLE_ASH_GETOPTS
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02002092static void FAST_FUNC
Denis Vlasenko01631112007-12-16 17:20:38 +00002093getoptsreset(const char *value)
2094{
Denys Vlasenko46289452017-08-11 00:59:36 +02002095 shellparam.optind = 1;
2096 if (is_number(value))
2097 shellparam.optind = number(value) ?: 1;
Denis Vlasenko01631112007-12-16 17:20:38 +00002098 shellparam.optoff = -1;
2099}
2100#endif
2101
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002102/*
2103 * Compares two strings up to the first = or '\0'. The first
2104 * string must be terminated by '='; the second may be terminated by
2105 * either '=' or '\0'.
2106 */
2107static int
2108varcmp(const char *p, const char *q)
2109{
2110 int c, d;
2111
2112 while ((c = *p) == (d = *q)) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02002113 if (c == '\0' || c == '=')
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002114 goto out;
2115 p++;
2116 q++;
2117 }
2118 if (c == '=')
Denis Vlasenko9650f362007-02-23 01:04:37 +00002119 c = '\0';
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002120 if (d == '=')
Denis Vlasenko9650f362007-02-23 01:04:37 +00002121 d = '\0';
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002122 out:
2123 return c - d;
2124}
2125
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002126/*
2127 * Find the appropriate entry in the hash table from the name.
2128 */
2129static struct var **
2130hashvar(const char *p)
2131{
2132 unsigned hashval;
2133
2134 hashval = ((unsigned char) *p) << 4;
2135 while (*p && *p != '=')
2136 hashval += (unsigned char) *p++;
2137 return &vartab[hashval % VTABSIZE];
2138}
2139
2140static int
2141vpcmp(const void *a, const void *b)
2142{
2143 return varcmp(*(const char **)a, *(const char **)b);
2144}
2145
2146/*
2147 * This routine initializes the builtin variables.
2148 */
2149static void
2150initvar(void)
2151{
2152 struct var *vp;
2153 struct var *end;
2154 struct var **vpp;
2155
2156 /*
2157 * PS1 depends on uid
2158 */
2159#if ENABLE_FEATURE_EDITING && ENABLE_FEATURE_EDITING_FANCY_PROMPT
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002160 vps1.var_text = "PS1=\\w \\$ ";
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002161#else
2162 if (!geteuid())
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002163 vps1.var_text = "PS1=# ";
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002164#endif
2165 vp = varinit;
Denis Vlasenko80b8b392007-06-25 10:55:35 +00002166 end = vp + ARRAY_SIZE(varinit);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002167 do {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002168 vpp = hashvar(vp->var_text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002169 vp->next = *vpp;
2170 *vpp = vp;
2171 } while (++vp < end);
2172}
2173
2174static struct var **
2175findvar(struct var **vpp, const char *name)
2176{
2177 for (; *vpp; vpp = &(*vpp)->next) {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002178 if (varcmp((*vpp)->var_text, name) == 0) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002179 break;
2180 }
2181 }
2182 return vpp;
2183}
2184
2185/*
2186 * Find the value of a variable. Returns NULL if not set.
2187 */
Denys Vlasenko03dad222010-01-12 23:29:57 +01002188static const char* FAST_FUNC
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002189lookupvar(const char *name)
2190{
2191 struct var *v;
2192
2193 v = *findvar(hashvar(name), name);
2194 if (v) {
Denis Vlasenko448d30e2008-06-27 00:24:11 +00002195#if ENABLE_ASH_RANDOM_SUPPORT
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002196 /*
2197 * Dynamic variables are implemented roughly the same way they are
2198 * in bash. Namely, they're "special" so long as they aren't unset.
2199 * As soon as they're unset, they're no longer dynamic, and dynamic
2200 * lookup will no longer happen at that point. -- PFM.
2201 */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002202 if (v->flags & VDYNAMIC)
2203 v->var_func(NULL);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002204#endif
2205 if (!(v->flags & VUNSET))
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002206 return var_end(v->var_text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002207 }
2208 return NULL;
2209}
2210
Denys Vlasenko0b883582016-12-23 16:49:07 +01002211#if ENABLE_UNICODE_SUPPORT
Denys Vlasenko37dc08b2016-10-02 04:38:07 +02002212static void
2213reinit_unicode_for_ash(void)
Denys Vlasenkoe9ab07c2014-08-13 18:00:08 +02002214{
2215 /* Unicode support should be activated even if LANG is set
2216 * _during_ shell execution, not only if it was set when
2217 * shell was started. Therefore, re-check LANG every time:
2218 */
2219 if (ENABLE_FEATURE_CHECK_UNICODE_IN_ENV
2220 || ENABLE_UNICODE_USING_LOCALE
2221 ) {
2222 const char *s = lookupvar("LC_ALL");
2223 if (!s) s = lookupvar("LC_CTYPE");
2224 if (!s) s = lookupvar("LANG");
2225 reinit_unicode(s);
2226 }
2227}
Denys Vlasenko0b883582016-12-23 16:49:07 +01002228#else
2229# define reinit_unicode_for_ash() ((void)0)
2230#endif
Denys Vlasenkoe9ab07c2014-08-13 18:00:08 +02002231
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002232/*
2233 * Search the environment of a builtin command.
2234 */
Denys Vlasenko488e6092017-07-26 23:08:36 +02002235static ALWAYS_INLINE const char *
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002236bltinlookup(const char *name)
2237{
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002238 return lookupvar(name);
2239}
2240
2241/*
2242 * Same as setvar except that the variable and value are passed in
2243 * the first argument as name=value. Since the first argument will
2244 * be actually stored in the table, it should not be a string that
2245 * will go away.
2246 * Called with interrupts off.
2247 */
Denys Vlasenkod04fc712017-07-26 20:06:48 +02002248static struct var *
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002249setvareq(char *s, int flags)
2250{
2251 struct var *vp, **vpp;
2252
2253 vpp = hashvar(s);
2254 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
Denys Vlasenkod04fc712017-07-26 20:06:48 +02002255 vpp = findvar(vpp, s);
2256 vp = *vpp;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002257 if (vp) {
2258 if ((vp->flags & (VREADONLY|VDYNAMIC)) == VREADONLY) {
2259 const char *n;
2260
2261 if (flags & VNOSAVE)
2262 free(s);
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002263 n = vp->var_text;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +02002264 exitstatus = 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002265 ash_msg_and_raise_error("%.*s: is read only", strchrnul(n, '=') - n, n);
2266 }
2267
2268 if (flags & VNOSET)
Denys Vlasenkod04fc712017-07-26 20:06:48 +02002269 goto out;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002270
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002271 if (vp->var_func && !(flags & VNOFUNC))
2272 vp->var_func(var_end(s));
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002273
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002274 if (!(vp->flags & (VTEXTFIXED|VSTACK)))
2275 free((char*)vp->var_text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002276
Denys Vlasenkob28d4c32017-07-25 16:29:36 +02002277 if (((flags & (VEXPORT|VREADONLY|VSTRFIXED|VUNSET)) | (vp->flags & VSTRFIXED)) == VUNSET) {
2278 *vpp = vp->next;
2279 free(vp);
2280 out_free:
2281 if ((flags & (VTEXTFIXED|VSTACK|VNOSAVE)) == VNOSAVE)
2282 free(s);
Denys Vlasenkod04fc712017-07-26 20:06:48 +02002283 goto out;
Denys Vlasenkob28d4c32017-07-25 16:29:36 +02002284 }
2285
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002286 flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
2287 } else {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002288 /* variable s is not found */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002289 if (flags & VNOSET)
Denys Vlasenkod04fc712017-07-26 20:06:48 +02002290 goto out;
Denys Vlasenkob28d4c32017-07-25 16:29:36 +02002291 if ((flags & (VEXPORT|VREADONLY|VSTRFIXED|VUNSET)) == VUNSET)
2292 goto out_free;
Denis Vlasenko597906c2008-02-20 16:38:54 +00002293 vp = ckzalloc(sizeof(*vp));
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002294 vp->next = *vpp;
Denis Vlasenko597906c2008-02-20 16:38:54 +00002295 /*vp->func = NULL; - ckzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002296 *vpp = vp;
2297 }
2298 if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE)))
2299 s = ckstrdup(s);
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002300 vp->var_text = s;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002301 vp->flags = flags;
Denys Vlasenkod04fc712017-07-26 20:06:48 +02002302
2303 out:
2304 return vp;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002305}
2306
2307/*
2308 * Set the value of a variable. The flags argument is ored with the
2309 * flags of the variable. If val is NULL, the variable is unset.
2310 */
Denys Vlasenkod04fc712017-07-26 20:06:48 +02002311static struct var *
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002312setvar(const char *name, const char *val, int flags)
2313{
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002314 const char *q;
2315 char *p;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002316 char *nameeq;
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002317 size_t namelen;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002318 size_t vallen;
Denys Vlasenkod04fc712017-07-26 20:06:48 +02002319 struct var *vp;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002320
2321 q = endofname(name);
2322 p = strchrnul(q, '=');
2323 namelen = p - name;
2324 if (!namelen || p != q)
2325 ash_msg_and_raise_error("%.*s: bad variable name", namelen, name);
2326 vallen = 0;
2327 if (val == NULL) {
2328 flags |= VUNSET;
2329 } else {
2330 vallen = strlen(val);
2331 }
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002332
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002333 INT_OFF;
2334 nameeq = ckmalloc(namelen + vallen + 2);
Denys Vlasenkoda2244f2017-07-21 18:51:29 +02002335 p = mempcpy(nameeq, name, namelen);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002336 if (val) {
2337 *p++ = '=';
Denys Vlasenkoda2244f2017-07-21 18:51:29 +02002338 p = mempcpy(p, val, vallen);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002339 }
2340 *p = '\0';
Denys Vlasenkod04fc712017-07-26 20:06:48 +02002341 vp = setvareq(nameeq, flags | VNOSAVE);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002342 INT_ON;
Denys Vlasenkod04fc712017-07-26 20:06:48 +02002343
2344 return vp;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002345}
2346
Denys Vlasenko03dad222010-01-12 23:29:57 +01002347static void FAST_FUNC
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02002348setvar0(const char *name, const char *val)
Denys Vlasenko03dad222010-01-12 23:29:57 +01002349{
2350 setvar(name, val, 0);
2351}
2352
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002353/*
2354 * Unset the specified variable.
2355 */
Denys Vlasenkob28d4c32017-07-25 16:29:36 +02002356static void
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002357unsetvar(const char *s)
2358{
Denys Vlasenkocf3a7962017-07-26 14:38:19 +02002359 setvar(s, NULL, 0);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002360}
2361
2362/*
2363 * Process a linked list of variable assignments.
2364 */
2365static void
2366listsetvar(struct strlist *list_set_var, int flags)
2367{
2368 struct strlist *lp = list_set_var;
2369
2370 if (!lp)
2371 return;
2372 INT_OFF;
2373 do {
2374 setvareq(lp->text, flags);
Denis Vlasenko9650f362007-02-23 01:04:37 +00002375 lp = lp->next;
2376 } while (lp);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002377 INT_ON;
2378}
2379
2380/*
2381 * Generate a list of variables satisfying the given conditions.
2382 */
2383static char **
2384listvars(int on, int off, char ***end)
2385{
2386 struct var **vpp;
2387 struct var *vp;
2388 char **ep;
2389 int mask;
2390
2391 STARTSTACKSTR(ep);
2392 vpp = vartab;
2393 mask = on | off;
2394 do {
2395 for (vp = *vpp; vp; vp = vp->next) {
2396 if ((vp->flags & mask) == on) {
2397 if (ep == stackstrend())
2398 ep = growstackstr();
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002399 *ep++ = (char*)vp->var_text;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002400 }
2401 }
2402 } while (++vpp < vartab + VTABSIZE);
2403 if (ep == stackstrend())
2404 ep = growstackstr();
2405 if (end)
2406 *end = ep;
2407 *ep++ = NULL;
2408 return grabstackstr(ep);
2409}
2410
2411
2412/* ============ Path search helper
2413 *
2414 * The variable path (passed by reference) should be set to the start
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002415 * of the path before the first call; path_advance will update
2416 * this value as it proceeds. Successive calls to path_advance will return
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002417 * the possible path expansions in sequence. If an option (indicated by
2418 * a percent sign) appears in the path entry then the global variable
2419 * pathopt will be set to point to it; otherwise pathopt will be set to
2420 * NULL.
2421 */
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002422static const char *pathopt; /* set by path_advance */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002423
2424static char *
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002425path_advance(const char **path, const char *name)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002426{
2427 const char *p;
2428 char *q;
2429 const char *start;
2430 size_t len;
2431
2432 if (*path == NULL)
2433 return NULL;
2434 start = *path;
Denis Vlasenkof7d56652008-03-25 05:51:41 +00002435 for (p = start; *p && *p != ':' && *p != '%'; p++)
2436 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002437 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
2438 while (stackblocksize() < len)
2439 growstackblock();
2440 q = stackblock();
2441 if (p != start) {
Denys Vlasenko5ace96a2017-07-23 21:46:02 +02002442 q = mempcpy(q, start, p - start);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002443 *q++ = '/';
2444 }
2445 strcpy(q, name);
2446 pathopt = NULL;
2447 if (*p == '%') {
2448 pathopt = ++p;
Denis Vlasenkof7d56652008-03-25 05:51:41 +00002449 while (*p && *p != ':')
2450 p++;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002451 }
2452 if (*p == ':')
2453 *path = p + 1;
2454 else
2455 *path = NULL;
2456 return stalloc(len);
2457}
2458
2459
2460/* ============ Prompt */
2461
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +00002462static smallint doprompt; /* if set, prompt the user */
2463static smallint needprompt; /* true if interactive and at start of line */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002464
2465#if ENABLE_FEATURE_EDITING
2466static line_input_t *line_input_state;
2467static const char *cmdedit_prompt;
2468static void
2469putprompt(const char *s)
2470{
2471 if (ENABLE_ASH_EXPAND_PRMT) {
2472 free((char*)cmdedit_prompt);
Denis Vlasenko4222ae42007-02-25 02:37:49 +00002473 cmdedit_prompt = ckstrdup(s);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002474 return;
2475 }
2476 cmdedit_prompt = s;
2477}
2478#else
2479static void
2480putprompt(const char *s)
2481{
2482 out2str(s);
2483}
2484#endif
2485
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002486/* expandstr() needs parsing machinery, so it is far away ahead... */
Denys Vlasenko46999802017-07-29 21:12:29 +02002487static const char *expandstr(const char *ps, int syntax_type);
2488/* Values for syntax param */
2489#define BASESYNTAX 0 /* not in quotes */
2490#define DQSYNTAX 1 /* in double quotes */
2491#define SQSYNTAX 2 /* in single quotes */
2492#define ARISYNTAX 3 /* in arithmetic */
Denys Vlasenko5f0a75f2017-07-29 22:58:44 +02002493#if ENABLE_ASH_EXPAND_PRMT
2494# define PSSYNTAX 4 /* prompt. never passed to SIT() */
2495#endif
Denys Vlasenko46999802017-07-29 21:12:29 +02002496/* PSSYNTAX expansion is identical to DQSYNTAX, except keeping '\$' as '\$' */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002497
Denys Vlasenko46999802017-07-29 21:12:29 +02002498/*
2499 * called by editline -- any expansions to the prompt should be added here.
2500 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002501static void
Denys Vlasenko958581a2010-09-12 15:04:27 +02002502setprompt_if(smallint do_set, int whichprompt)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002503{
2504 const char *prompt;
Denys Vlasenko958581a2010-09-12 15:04:27 +02002505 IF_ASH_EXPAND_PRMT(struct stackmark smark;)
2506
2507 if (!do_set)
2508 return;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002509
2510 needprompt = 0;
2511
2512 switch (whichprompt) {
2513 case 1:
2514 prompt = ps1val();
2515 break;
2516 case 2:
2517 prompt = ps2val();
2518 break;
2519 default: /* 0 */
2520 prompt = nullstr;
2521 }
2522#if ENABLE_ASH_EXPAND_PRMT
Denys Vlasenko60ca8342016-09-30 11:21:21 +02002523 pushstackmark(&smark, stackblocksize());
Denys Vlasenko46999802017-07-29 21:12:29 +02002524 putprompt(expandstr(prompt, PSSYNTAX));
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002525 popstackmark(&smark);
Denys Vlasenko48c803a2017-07-01 23:24:48 +02002526#else
2527 putprompt(prompt);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002528#endif
2529}
2530
2531
2532/* ============ The cd and pwd commands */
2533
2534#define CD_PHYSICAL 1
2535#define CD_PRINT 2
2536
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002537static int
2538cdopt(void)
2539{
2540 int flags = 0;
2541 int i, j;
2542
2543 j = 'L';
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02002544 while ((i = nextopt("LP")) != '\0') {
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002545 if (i != j) {
2546 flags ^= CD_PHYSICAL;
2547 j = i;
2548 }
2549 }
2550
2551 return flags;
2552}
2553
2554/*
2555 * Update curdir (the name of the current directory) in response to a
2556 * cd command.
2557 */
2558static const char *
2559updatepwd(const char *dir)
2560{
2561 char *new;
2562 char *p;
2563 char *cdcomppath;
2564 const char *lim;
2565
Denys Vlasenko8e2bc472016-09-28 23:02:57 +02002566 cdcomppath = sstrdup(dir);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002567 STARTSTACKSTR(new);
2568 if (*dir != '/') {
2569 if (curdir == nullstr)
2570 return 0;
2571 new = stack_putstr(curdir, new);
2572 }
2573 new = makestrspace(strlen(dir) + 2, new);
Denis Vlasenko29eb3592008-05-18 14:06:08 +00002574 lim = (char *)stackblock() + 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002575 if (*dir != '/') {
2576 if (new[-1] != '/')
2577 USTPUTC('/', new);
2578 if (new > lim && *lim == '/')
2579 lim++;
2580 } else {
2581 USTPUTC('/', new);
2582 cdcomppath++;
2583 if (dir[1] == '/' && dir[2] != '/') {
2584 USTPUTC('/', new);
2585 cdcomppath++;
2586 lim++;
2587 }
2588 }
2589 p = strtok(cdcomppath, "/");
2590 while (p) {
2591 switch (*p) {
2592 case '.':
2593 if (p[1] == '.' && p[2] == '\0') {
2594 while (new > lim) {
2595 STUNPUTC(new);
2596 if (new[-1] == '/')
2597 break;
2598 }
2599 break;
Denis Vlasenko16abcd92007-04-13 23:59:52 +00002600 }
2601 if (p[1] == '\0')
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002602 break;
2603 /* fall through */
2604 default:
2605 new = stack_putstr(p, new);
2606 USTPUTC('/', new);
2607 }
Denys Vlasenko00da72b2015-10-23 18:43:16 +02002608 p = strtok(NULL, "/");
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002609 }
2610 if (new > lim)
2611 STUNPUTC(new);
2612 *new = 0;
2613 return stackblock();
2614}
2615
2616/*
2617 * Find out what the current directory is. If we already know the current
2618 * directory, this routine returns immediately.
2619 */
2620static char *
2621getpwd(void)
2622{
Denis Vlasenko01631112007-12-16 17:20:38 +00002623 char *dir = getcwd(NULL, 0); /* huh, using glibc extension? */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002624 return dir ? dir : nullstr;
2625}
2626
2627static void
2628setpwd(const char *val, int setold)
2629{
2630 char *oldcur, *dir;
2631
2632 oldcur = dir = curdir;
2633
2634 if (setold) {
2635 setvar("OLDPWD", oldcur, VEXPORT);
2636 }
2637 INT_OFF;
2638 if (physdir != nullstr) {
2639 if (physdir != oldcur)
2640 free(physdir);
2641 physdir = nullstr;
2642 }
2643 if (oldcur == val || !val) {
2644 char *s = getpwd();
2645 physdir = s;
2646 if (!val)
2647 dir = s;
2648 } else
2649 dir = ckstrdup(val);
2650 if (oldcur != dir && oldcur != nullstr) {
2651 free(oldcur);
2652 }
2653 curdir = dir;
2654 INT_ON;
2655 setvar("PWD", dir, VEXPORT);
2656}
2657
2658static void hashcd(void);
2659
2660/*
Denys Vlasenko70392332016-10-27 02:31:55 +02002661 * Actually do the chdir. We also call hashcd to let other routines
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002662 * know that the current directory has changed.
2663 */
2664static int
2665docd(const char *dest, int flags)
2666{
Denys Vlasenko4b1100e2010-03-05 14:10:54 +01002667 const char *dir = NULL;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002668 int err;
2669
2670 TRACE(("docd(\"%s\", %d) called\n", dest, flags));
2671
2672 INT_OFF;
2673 if (!(flags & CD_PHYSICAL)) {
2674 dir = updatepwd(dest);
2675 if (dir)
2676 dest = dir;
2677 }
2678 err = chdir(dest);
2679 if (err)
2680 goto out;
2681 setpwd(dir, 1);
2682 hashcd();
2683 out:
2684 INT_ON;
2685 return err;
2686}
2687
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02002688static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00002689cdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002690{
2691 const char *dest;
2692 const char *path;
2693 const char *p;
2694 char c;
2695 struct stat statb;
2696 int flags;
2697
2698 flags = cdopt();
2699 dest = *argptr;
2700 if (!dest)
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02002701 dest = bltinlookup("HOME");
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002702 else if (LONE_DASH(dest)) {
2703 dest = bltinlookup("OLDPWD");
2704 flags |= CD_PRINT;
2705 }
2706 if (!dest)
2707 dest = nullstr;
2708 if (*dest == '/')
Denys Vlasenko0e081d02016-10-26 19:56:05 +02002709 goto step6;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002710 if (*dest == '.') {
2711 c = dest[1];
2712 dotdot:
2713 switch (c) {
2714 case '\0':
2715 case '/':
2716 goto step6;
2717 case '.':
2718 c = dest[2];
2719 if (c != '.')
2720 goto dotdot;
2721 }
2722 }
2723 if (!*dest)
2724 dest = ".";
2725 path = bltinlookup("CDPATH");
Denys Vlasenko0e081d02016-10-26 19:56:05 +02002726 while (path) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002727 c = *path;
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002728 p = path_advance(&path, dest);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002729 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
2730 if (c && c != ':')
2731 flags |= CD_PRINT;
2732 docd:
2733 if (!docd(p, flags))
2734 goto out;
Denys Vlasenko0e081d02016-10-26 19:56:05 +02002735 goto err;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002736 }
Denys Vlasenko0e081d02016-10-26 19:56:05 +02002737 }
2738
2739 step6:
2740 p = dest;
2741 goto docd;
2742
2743 err:
Johannes Schindelin687aac02017-08-22 22:03:22 +02002744 ash_msg_and_raise_perror("can't cd to %s", dest);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002745 /* NOTREACHED */
2746 out:
2747 if (flags & CD_PRINT)
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02002748 out1fmt("%s\n", curdir);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002749 return 0;
2750}
2751
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02002752static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00002753pwdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002754{
2755 int flags;
2756 const char *dir = curdir;
2757
2758 flags = cdopt();
2759 if (flags) {
2760 if (physdir == nullstr)
2761 setpwd(dir, 0);
2762 dir = physdir;
2763 }
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02002764 out1fmt("%s\n", dir);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002765 return 0;
2766}
2767
Denis Vlasenko0c032a42007-02-23 01:03:40 +00002768
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00002769/* ============ ... */
Eric Andersenc470f442003-07-28 09:56:35 +00002770
Denis Vlasenko834dee72008-10-07 09:18:30 +00002771
Denys Vlasenko82dd14a2010-05-17 10:10:01 +02002772#define IBUFSIZ (ENABLE_FEATURE_EDITING ? CONFIG_FEATURE_EDITING_MAX_LEN : 1024)
Eric Andersenc470f442003-07-28 09:56:35 +00002773
Eric Andersenc470f442003-07-28 09:56:35 +00002774/* Syntax classes */
Denis Vlasenko834dee72008-10-07 09:18:30 +00002775#define CWORD 0 /* character is nothing special */
2776#define CNL 1 /* newline character */
2777#define CBACK 2 /* a backslash character */
2778#define CSQUOTE 3 /* single quote */
2779#define CDQUOTE 4 /* double quote */
Eric Andersenc470f442003-07-28 09:56:35 +00002780#define CENDQUOTE 5 /* a terminating quote */
Denis Vlasenko834dee72008-10-07 09:18:30 +00002781#define CBQUOTE 6 /* backwards single quote */
2782#define CVAR 7 /* a dollar sign */
2783#define CENDVAR 8 /* a '}' character */
2784#define CLP 9 /* a left paren in arithmetic */
2785#define CRP 10 /* a right paren in arithmetic */
Eric Andersenc470f442003-07-28 09:56:35 +00002786#define CENDFILE 11 /* end of file */
Denis Vlasenko834dee72008-10-07 09:18:30 +00002787#define CCTL 12 /* like CWORD, except it must be escaped */
2788#define CSPCL 13 /* these terminate a word */
2789#define CIGN 14 /* character should be ignored */
Eric Andersenc470f442003-07-28 09:56:35 +00002790
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002791#define PEOF 256
Denis Vlasenko131ae172007-02-18 13:00:19 +00002792#if ENABLE_ASH_ALIAS
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002793# define PEOA 257
Eric Andersenc470f442003-07-28 09:56:35 +00002794#endif
2795
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002796#define USE_SIT_FUNCTION ENABLE_ASH_OPTIMIZE_FOR_SIZE
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002797
Denys Vlasenko0b883582016-12-23 16:49:07 +01002798#if ENABLE_FEATURE_SH_MATH
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002799# define SIT_ITEM(a,b,c,d) (a | (b << 4) | (c << 8) | (d << 12))
Eric Andersenc470f442003-07-28 09:56:35 +00002800#else
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002801# define SIT_ITEM(a,b,c,d) (a | (b << 4) | (c << 8))
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002802#endif
Denys Vlasenko3e134eb2016-04-22 18:09:21 +02002803static const uint16_t S_I_T[] ALIGN2 = {
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002804#if ENABLE_ASH_ALIAS
2805 SIT_ITEM(CSPCL , CIGN , CIGN , CIGN ), /* 0, PEOA */
2806#endif
2807 SIT_ITEM(CSPCL , CWORD , CWORD, CWORD ), /* 1, ' ' */
2808 SIT_ITEM(CNL , CNL , CNL , CNL ), /* 2, \n */
2809 SIT_ITEM(CWORD , CCTL , CCTL , CWORD ), /* 3, !*-/:=?[]~ */
2810 SIT_ITEM(CDQUOTE , CENDQUOTE, CWORD, CWORD ), /* 4, '"' */
2811 SIT_ITEM(CVAR , CVAR , CWORD, CVAR ), /* 5, $ */
2812 SIT_ITEM(CSQUOTE , CWORD , CENDQUOTE, CWORD), /* 6, "'" */
2813 SIT_ITEM(CSPCL , CWORD , CWORD, CLP ), /* 7, ( */
2814 SIT_ITEM(CSPCL , CWORD , CWORD, CRP ), /* 8, ) */
2815 SIT_ITEM(CBACK , CBACK , CCTL , CBACK ), /* 9, \ */
2816 SIT_ITEM(CBQUOTE , CBQUOTE , CWORD, CBQUOTE), /* 10, ` */
2817 SIT_ITEM(CENDVAR , CENDVAR , CWORD, CENDVAR), /* 11, } */
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002818#if !USE_SIT_FUNCTION
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002819 SIT_ITEM(CENDFILE, CENDFILE , CENDFILE, CENDFILE),/* 12, PEOF */
2820 SIT_ITEM(CWORD , CWORD , CWORD, CWORD ), /* 13, 0-9A-Za-z */
2821 SIT_ITEM(CCTL , CCTL , CCTL , CCTL ) /* 14, CTLESC ... */
2822#endif
2823#undef SIT_ITEM
Eric Andersenc470f442003-07-28 09:56:35 +00002824};
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002825/* Constants below must match table above */
2826enum {
2827#if ENABLE_ASH_ALIAS
2828 CSPCL_CIGN_CIGN_CIGN , /* 0 */
2829#endif
2830 CSPCL_CWORD_CWORD_CWORD , /* 1 */
2831 CNL_CNL_CNL_CNL , /* 2 */
2832 CWORD_CCTL_CCTL_CWORD , /* 3 */
2833 CDQUOTE_CENDQUOTE_CWORD_CWORD , /* 4 */
2834 CVAR_CVAR_CWORD_CVAR , /* 5 */
2835 CSQUOTE_CWORD_CENDQUOTE_CWORD , /* 6 */
2836 CSPCL_CWORD_CWORD_CLP , /* 7 */
2837 CSPCL_CWORD_CWORD_CRP , /* 8 */
2838 CBACK_CBACK_CCTL_CBACK , /* 9 */
2839 CBQUOTE_CBQUOTE_CWORD_CBQUOTE , /* 10 */
2840 CENDVAR_CENDVAR_CWORD_CENDVAR , /* 11 */
2841 CENDFILE_CENDFILE_CENDFILE_CENDFILE, /* 12 */
2842 CWORD_CWORD_CWORD_CWORD , /* 13 */
2843 CCTL_CCTL_CCTL_CCTL , /* 14 */
2844};
Eric Andersen2870d962001-07-02 17:27:21 +00002845
Denys Vlasenkocd716832009-11-28 22:14:02 +01002846/* c in SIT(c, syntax) must be an *unsigned char* or PEOA or PEOF,
2847 * caller must ensure proper cast on it if c is *char_ptr!
2848 */
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002849#if USE_SIT_FUNCTION
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002850
Denis Vlasenko0c032a42007-02-23 01:03:40 +00002851static int
2852SIT(int c, int syntax)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002853{
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02002854 /* Used to also have '/' in this string: "\t\n !\"$&'()*-/:;<=>?[\\]`|}~" */
2855 static const char spec_symbls[] ALIGN1 = "\t\n !\"$&'()*-:;<=>?[\\]`|}~";
2856 /*
2857 * This causes '/' to be prepended with CTLESC in dquoted string,
2858 * making "./file"* treated incorrectly because we feed
2859 * ".\/file*" string to glob(), confusing it (see expandmeta func).
2860 * The "homegrown" glob implementation is okay with that,
2861 * but glibc one isn't. With '/' always treated as CWORD,
2862 * both work fine.
2863 */
Denys Vlasenkocd716832009-11-28 22:14:02 +01002864# if ENABLE_ASH_ALIAS
2865 static const uint8_t syntax_index_table[] ALIGN1 = {
Eric Andersenc470f442003-07-28 09:56:35 +00002866 1, 2, 1, 3, 4, 5, 1, 6, /* "\t\n !\"$&'" */
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02002867 7, 8, 3, 3,/*3,*/3, 1, 1, /* "()*-/:;<" */
Eric Andersenc470f442003-07-28 09:56:35 +00002868 3, 1, 3, 3, 9, 3, 10, 1, /* "=>?[\\]`|" */
2869 11, 3 /* "}~" */
2870 };
Denys Vlasenkocd716832009-11-28 22:14:02 +01002871# else
2872 static const uint8_t syntax_index_table[] ALIGN1 = {
Eric Andersenc470f442003-07-28 09:56:35 +00002873 0, 1, 0, 2, 3, 4, 0, 5, /* "\t\n !\"$&'" */
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02002874 6, 7, 2, 2,/*2,*/2, 0, 0, /* "()*-/:;<" */
Eric Andersenc470f442003-07-28 09:56:35 +00002875 2, 0, 2, 2, 8, 2, 9, 0, /* "=>?[\\]`|" */
2876 10, 2 /* "}~" */
2877 };
Denys Vlasenkocd716832009-11-28 22:14:02 +01002878# endif
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002879 const char *s;
2880 int indx;
2881
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002882 if (c == PEOF)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002883 return CENDFILE;
Denys Vlasenkocd716832009-11-28 22:14:02 +01002884# if ENABLE_ASH_ALIAS
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002885 if (c == PEOA)
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002886 indx = 0;
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002887 else
Denys Vlasenkocd716832009-11-28 22:14:02 +01002888# endif
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002889 {
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002890 /* Cast is purely for paranoia here,
2891 * just in case someone passed signed char to us */
2892 if ((unsigned char)c >= CTL_FIRST
2893 && (unsigned char)c <= CTL_LAST
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002894 ) {
2895 return CCTL;
2896 }
2897 s = strchrnul(spec_symbls, c);
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002898 if (*s == '\0')
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002899 return CWORD;
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002900 indx = syntax_index_table[s - spec_symbls];
2901 }
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002902 return (S_I_T[indx] >> (syntax*4)) & 0xf;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002903}
2904
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00002905#else /* !USE_SIT_FUNCTION */
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002906
Denys Vlasenko3e134eb2016-04-22 18:09:21 +02002907static const uint8_t syntax_index_table[] ALIGN1 = {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002908 /* BASESYNTAX_DQSYNTAX_SQSYNTAX_ARISYNTAX */
Denys Vlasenkocd716832009-11-28 22:14:02 +01002909 /* 0 */ CWORD_CWORD_CWORD_CWORD,
2910 /* 1 */ CWORD_CWORD_CWORD_CWORD,
2911 /* 2 */ CWORD_CWORD_CWORD_CWORD,
2912 /* 3 */ CWORD_CWORD_CWORD_CWORD,
2913 /* 4 */ CWORD_CWORD_CWORD_CWORD,
2914 /* 5 */ CWORD_CWORD_CWORD_CWORD,
2915 /* 6 */ CWORD_CWORD_CWORD_CWORD,
2916 /* 7 */ CWORD_CWORD_CWORD_CWORD,
2917 /* 8 */ CWORD_CWORD_CWORD_CWORD,
2918 /* 9 "\t" */ CSPCL_CWORD_CWORD_CWORD,
2919 /* 10 "\n" */ CNL_CNL_CNL_CNL,
2920 /* 11 */ CWORD_CWORD_CWORD_CWORD,
2921 /* 12 */ CWORD_CWORD_CWORD_CWORD,
2922 /* 13 */ CWORD_CWORD_CWORD_CWORD,
2923 /* 14 */ CWORD_CWORD_CWORD_CWORD,
2924 /* 15 */ CWORD_CWORD_CWORD_CWORD,
2925 /* 16 */ CWORD_CWORD_CWORD_CWORD,
2926 /* 17 */ CWORD_CWORD_CWORD_CWORD,
2927 /* 18 */ CWORD_CWORD_CWORD_CWORD,
2928 /* 19 */ CWORD_CWORD_CWORD_CWORD,
2929 /* 20 */ CWORD_CWORD_CWORD_CWORD,
2930 /* 21 */ CWORD_CWORD_CWORD_CWORD,
2931 /* 22 */ CWORD_CWORD_CWORD_CWORD,
2932 /* 23 */ CWORD_CWORD_CWORD_CWORD,
2933 /* 24 */ CWORD_CWORD_CWORD_CWORD,
2934 /* 25 */ CWORD_CWORD_CWORD_CWORD,
2935 /* 26 */ CWORD_CWORD_CWORD_CWORD,
2936 /* 27 */ CWORD_CWORD_CWORD_CWORD,
2937 /* 28 */ CWORD_CWORD_CWORD_CWORD,
2938 /* 29 */ CWORD_CWORD_CWORD_CWORD,
2939 /* 30 */ CWORD_CWORD_CWORD_CWORD,
2940 /* 31 */ CWORD_CWORD_CWORD_CWORD,
2941 /* 32 " " */ CSPCL_CWORD_CWORD_CWORD,
2942 /* 33 "!" */ CWORD_CCTL_CCTL_CWORD,
2943 /* 34 """ */ CDQUOTE_CENDQUOTE_CWORD_CWORD,
2944 /* 35 "#" */ CWORD_CWORD_CWORD_CWORD,
2945 /* 36 "$" */ CVAR_CVAR_CWORD_CVAR,
2946 /* 37 "%" */ CWORD_CWORD_CWORD_CWORD,
2947 /* 38 "&" */ CSPCL_CWORD_CWORD_CWORD,
2948 /* 39 "'" */ CSQUOTE_CWORD_CENDQUOTE_CWORD,
2949 /* 40 "(" */ CSPCL_CWORD_CWORD_CLP,
2950 /* 41 ")" */ CSPCL_CWORD_CWORD_CRP,
2951 /* 42 "*" */ CWORD_CCTL_CCTL_CWORD,
2952 /* 43 "+" */ CWORD_CWORD_CWORD_CWORD,
2953 /* 44 "," */ CWORD_CWORD_CWORD_CWORD,
2954 /* 45 "-" */ CWORD_CCTL_CCTL_CWORD,
2955 /* 46 "." */ CWORD_CWORD_CWORD_CWORD,
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02002956/* "/" was CWORD_CCTL_CCTL_CWORD, see comment in SIT() function why this is changed: */
2957 /* 47 "/" */ CWORD_CWORD_CWORD_CWORD,
Denys Vlasenkocd716832009-11-28 22:14:02 +01002958 /* 48 "0" */ CWORD_CWORD_CWORD_CWORD,
2959 /* 49 "1" */ CWORD_CWORD_CWORD_CWORD,
2960 /* 50 "2" */ CWORD_CWORD_CWORD_CWORD,
2961 /* 51 "3" */ CWORD_CWORD_CWORD_CWORD,
2962 /* 52 "4" */ CWORD_CWORD_CWORD_CWORD,
2963 /* 53 "5" */ CWORD_CWORD_CWORD_CWORD,
2964 /* 54 "6" */ CWORD_CWORD_CWORD_CWORD,
2965 /* 55 "7" */ CWORD_CWORD_CWORD_CWORD,
2966 /* 56 "8" */ CWORD_CWORD_CWORD_CWORD,
2967 /* 57 "9" */ CWORD_CWORD_CWORD_CWORD,
2968 /* 58 ":" */ CWORD_CCTL_CCTL_CWORD,
2969 /* 59 ";" */ CSPCL_CWORD_CWORD_CWORD,
2970 /* 60 "<" */ CSPCL_CWORD_CWORD_CWORD,
2971 /* 61 "=" */ CWORD_CCTL_CCTL_CWORD,
2972 /* 62 ">" */ CSPCL_CWORD_CWORD_CWORD,
2973 /* 63 "?" */ CWORD_CCTL_CCTL_CWORD,
2974 /* 64 "@" */ CWORD_CWORD_CWORD_CWORD,
2975 /* 65 "A" */ CWORD_CWORD_CWORD_CWORD,
2976 /* 66 "B" */ CWORD_CWORD_CWORD_CWORD,
2977 /* 67 "C" */ CWORD_CWORD_CWORD_CWORD,
2978 /* 68 "D" */ CWORD_CWORD_CWORD_CWORD,
2979 /* 69 "E" */ CWORD_CWORD_CWORD_CWORD,
2980 /* 70 "F" */ CWORD_CWORD_CWORD_CWORD,
2981 /* 71 "G" */ CWORD_CWORD_CWORD_CWORD,
2982 /* 72 "H" */ CWORD_CWORD_CWORD_CWORD,
2983 /* 73 "I" */ CWORD_CWORD_CWORD_CWORD,
2984 /* 74 "J" */ CWORD_CWORD_CWORD_CWORD,
2985 /* 75 "K" */ CWORD_CWORD_CWORD_CWORD,
2986 /* 76 "L" */ CWORD_CWORD_CWORD_CWORD,
2987 /* 77 "M" */ CWORD_CWORD_CWORD_CWORD,
2988 /* 78 "N" */ CWORD_CWORD_CWORD_CWORD,
2989 /* 79 "O" */ CWORD_CWORD_CWORD_CWORD,
2990 /* 80 "P" */ CWORD_CWORD_CWORD_CWORD,
2991 /* 81 "Q" */ CWORD_CWORD_CWORD_CWORD,
2992 /* 82 "R" */ CWORD_CWORD_CWORD_CWORD,
2993 /* 83 "S" */ CWORD_CWORD_CWORD_CWORD,
2994 /* 84 "T" */ CWORD_CWORD_CWORD_CWORD,
2995 /* 85 "U" */ CWORD_CWORD_CWORD_CWORD,
2996 /* 86 "V" */ CWORD_CWORD_CWORD_CWORD,
2997 /* 87 "W" */ CWORD_CWORD_CWORD_CWORD,
2998 /* 88 "X" */ CWORD_CWORD_CWORD_CWORD,
2999 /* 89 "Y" */ CWORD_CWORD_CWORD_CWORD,
3000 /* 90 "Z" */ CWORD_CWORD_CWORD_CWORD,
3001 /* 91 "[" */ CWORD_CCTL_CCTL_CWORD,
3002 /* 92 "\" */ CBACK_CBACK_CCTL_CBACK,
3003 /* 93 "]" */ CWORD_CCTL_CCTL_CWORD,
3004 /* 94 "^" */ CWORD_CWORD_CWORD_CWORD,
3005 /* 95 "_" */ CWORD_CWORD_CWORD_CWORD,
3006 /* 96 "`" */ CBQUOTE_CBQUOTE_CWORD_CBQUOTE,
3007 /* 97 "a" */ CWORD_CWORD_CWORD_CWORD,
3008 /* 98 "b" */ CWORD_CWORD_CWORD_CWORD,
3009 /* 99 "c" */ CWORD_CWORD_CWORD_CWORD,
3010 /* 100 "d" */ CWORD_CWORD_CWORD_CWORD,
3011 /* 101 "e" */ CWORD_CWORD_CWORD_CWORD,
3012 /* 102 "f" */ CWORD_CWORD_CWORD_CWORD,
3013 /* 103 "g" */ CWORD_CWORD_CWORD_CWORD,
3014 /* 104 "h" */ CWORD_CWORD_CWORD_CWORD,
3015 /* 105 "i" */ CWORD_CWORD_CWORD_CWORD,
3016 /* 106 "j" */ CWORD_CWORD_CWORD_CWORD,
3017 /* 107 "k" */ CWORD_CWORD_CWORD_CWORD,
3018 /* 108 "l" */ CWORD_CWORD_CWORD_CWORD,
3019 /* 109 "m" */ CWORD_CWORD_CWORD_CWORD,
3020 /* 110 "n" */ CWORD_CWORD_CWORD_CWORD,
3021 /* 111 "o" */ CWORD_CWORD_CWORD_CWORD,
3022 /* 112 "p" */ CWORD_CWORD_CWORD_CWORD,
3023 /* 113 "q" */ CWORD_CWORD_CWORD_CWORD,
3024 /* 114 "r" */ CWORD_CWORD_CWORD_CWORD,
3025 /* 115 "s" */ CWORD_CWORD_CWORD_CWORD,
3026 /* 116 "t" */ CWORD_CWORD_CWORD_CWORD,
3027 /* 117 "u" */ CWORD_CWORD_CWORD_CWORD,
3028 /* 118 "v" */ CWORD_CWORD_CWORD_CWORD,
3029 /* 119 "w" */ CWORD_CWORD_CWORD_CWORD,
3030 /* 120 "x" */ CWORD_CWORD_CWORD_CWORD,
3031 /* 121 "y" */ CWORD_CWORD_CWORD_CWORD,
3032 /* 122 "z" */ CWORD_CWORD_CWORD_CWORD,
3033 /* 123 "{" */ CWORD_CWORD_CWORD_CWORD,
3034 /* 124 "|" */ CSPCL_CWORD_CWORD_CWORD,
3035 /* 125 "}" */ CENDVAR_CENDVAR_CWORD_CENDVAR,
3036 /* 126 "~" */ CWORD_CCTL_CCTL_CWORD,
3037 /* 127 del */ CWORD_CWORD_CWORD_CWORD,
3038 /* 128 0x80 */ CWORD_CWORD_CWORD_CWORD,
3039 /* 129 CTLESC */ CCTL_CCTL_CCTL_CCTL,
3040 /* 130 CTLVAR */ CCTL_CCTL_CCTL_CCTL,
3041 /* 131 CTLENDVAR */ CCTL_CCTL_CCTL_CCTL,
3042 /* 132 CTLBACKQ */ CCTL_CCTL_CCTL_CCTL,
3043 /* 133 CTLQUOTE */ CCTL_CCTL_CCTL_CCTL,
3044 /* 134 CTLARI */ CCTL_CCTL_CCTL_CCTL,
3045 /* 135 CTLENDARI */ CCTL_CCTL_CCTL_CCTL,
3046 /* 136 CTLQUOTEMARK */ CCTL_CCTL_CCTL_CCTL,
3047 /* 137 */ CWORD_CWORD_CWORD_CWORD,
3048 /* 138 */ CWORD_CWORD_CWORD_CWORD,
3049 /* 139 */ CWORD_CWORD_CWORD_CWORD,
3050 /* 140 */ CWORD_CWORD_CWORD_CWORD,
3051 /* 141 */ CWORD_CWORD_CWORD_CWORD,
3052 /* 142 */ CWORD_CWORD_CWORD_CWORD,
3053 /* 143 */ CWORD_CWORD_CWORD_CWORD,
3054 /* 144 */ CWORD_CWORD_CWORD_CWORD,
3055 /* 145 */ CWORD_CWORD_CWORD_CWORD,
3056 /* 146 */ CWORD_CWORD_CWORD_CWORD,
3057 /* 147 */ CWORD_CWORD_CWORD_CWORD,
3058 /* 148 */ CWORD_CWORD_CWORD_CWORD,
3059 /* 149 */ CWORD_CWORD_CWORD_CWORD,
3060 /* 150 */ CWORD_CWORD_CWORD_CWORD,
3061 /* 151 */ CWORD_CWORD_CWORD_CWORD,
3062 /* 152 */ CWORD_CWORD_CWORD_CWORD,
3063 /* 153 */ CWORD_CWORD_CWORD_CWORD,
3064 /* 154 */ CWORD_CWORD_CWORD_CWORD,
3065 /* 155 */ CWORD_CWORD_CWORD_CWORD,
3066 /* 156 */ CWORD_CWORD_CWORD_CWORD,
3067 /* 157 */ CWORD_CWORD_CWORD_CWORD,
3068 /* 158 */ CWORD_CWORD_CWORD_CWORD,
3069 /* 159 */ CWORD_CWORD_CWORD_CWORD,
3070 /* 160 */ CWORD_CWORD_CWORD_CWORD,
3071 /* 161 */ CWORD_CWORD_CWORD_CWORD,
3072 /* 162 */ CWORD_CWORD_CWORD_CWORD,
3073 /* 163 */ CWORD_CWORD_CWORD_CWORD,
3074 /* 164 */ CWORD_CWORD_CWORD_CWORD,
3075 /* 165 */ CWORD_CWORD_CWORD_CWORD,
3076 /* 166 */ CWORD_CWORD_CWORD_CWORD,
3077 /* 167 */ CWORD_CWORD_CWORD_CWORD,
3078 /* 168 */ CWORD_CWORD_CWORD_CWORD,
3079 /* 169 */ CWORD_CWORD_CWORD_CWORD,
3080 /* 170 */ CWORD_CWORD_CWORD_CWORD,
3081 /* 171 */ CWORD_CWORD_CWORD_CWORD,
3082 /* 172 */ CWORD_CWORD_CWORD_CWORD,
3083 /* 173 */ CWORD_CWORD_CWORD_CWORD,
3084 /* 174 */ CWORD_CWORD_CWORD_CWORD,
3085 /* 175 */ CWORD_CWORD_CWORD_CWORD,
3086 /* 176 */ CWORD_CWORD_CWORD_CWORD,
3087 /* 177 */ CWORD_CWORD_CWORD_CWORD,
3088 /* 178 */ CWORD_CWORD_CWORD_CWORD,
3089 /* 179 */ CWORD_CWORD_CWORD_CWORD,
3090 /* 180 */ CWORD_CWORD_CWORD_CWORD,
3091 /* 181 */ CWORD_CWORD_CWORD_CWORD,
3092 /* 182 */ CWORD_CWORD_CWORD_CWORD,
3093 /* 183 */ CWORD_CWORD_CWORD_CWORD,
3094 /* 184 */ CWORD_CWORD_CWORD_CWORD,
3095 /* 185 */ CWORD_CWORD_CWORD_CWORD,
3096 /* 186 */ CWORD_CWORD_CWORD_CWORD,
3097 /* 187 */ CWORD_CWORD_CWORD_CWORD,
3098 /* 188 */ CWORD_CWORD_CWORD_CWORD,
3099 /* 189 */ CWORD_CWORD_CWORD_CWORD,
3100 /* 190 */ CWORD_CWORD_CWORD_CWORD,
3101 /* 191 */ CWORD_CWORD_CWORD_CWORD,
3102 /* 192 */ CWORD_CWORD_CWORD_CWORD,
3103 /* 193 */ CWORD_CWORD_CWORD_CWORD,
3104 /* 194 */ CWORD_CWORD_CWORD_CWORD,
3105 /* 195 */ CWORD_CWORD_CWORD_CWORD,
3106 /* 196 */ CWORD_CWORD_CWORD_CWORD,
3107 /* 197 */ CWORD_CWORD_CWORD_CWORD,
3108 /* 198 */ CWORD_CWORD_CWORD_CWORD,
3109 /* 199 */ CWORD_CWORD_CWORD_CWORD,
3110 /* 200 */ CWORD_CWORD_CWORD_CWORD,
3111 /* 201 */ CWORD_CWORD_CWORD_CWORD,
3112 /* 202 */ CWORD_CWORD_CWORD_CWORD,
3113 /* 203 */ CWORD_CWORD_CWORD_CWORD,
3114 /* 204 */ CWORD_CWORD_CWORD_CWORD,
3115 /* 205 */ CWORD_CWORD_CWORD_CWORD,
3116 /* 206 */ CWORD_CWORD_CWORD_CWORD,
3117 /* 207 */ CWORD_CWORD_CWORD_CWORD,
3118 /* 208 */ CWORD_CWORD_CWORD_CWORD,
3119 /* 209 */ CWORD_CWORD_CWORD_CWORD,
3120 /* 210 */ CWORD_CWORD_CWORD_CWORD,
3121 /* 211 */ CWORD_CWORD_CWORD_CWORD,
3122 /* 212 */ CWORD_CWORD_CWORD_CWORD,
3123 /* 213 */ CWORD_CWORD_CWORD_CWORD,
3124 /* 214 */ CWORD_CWORD_CWORD_CWORD,
3125 /* 215 */ CWORD_CWORD_CWORD_CWORD,
3126 /* 216 */ CWORD_CWORD_CWORD_CWORD,
3127 /* 217 */ CWORD_CWORD_CWORD_CWORD,
3128 /* 218 */ CWORD_CWORD_CWORD_CWORD,
3129 /* 219 */ CWORD_CWORD_CWORD_CWORD,
3130 /* 220 */ CWORD_CWORD_CWORD_CWORD,
3131 /* 221 */ CWORD_CWORD_CWORD_CWORD,
3132 /* 222 */ CWORD_CWORD_CWORD_CWORD,
3133 /* 223 */ CWORD_CWORD_CWORD_CWORD,
3134 /* 224 */ CWORD_CWORD_CWORD_CWORD,
3135 /* 225 */ CWORD_CWORD_CWORD_CWORD,
3136 /* 226 */ CWORD_CWORD_CWORD_CWORD,
3137 /* 227 */ CWORD_CWORD_CWORD_CWORD,
3138 /* 228 */ CWORD_CWORD_CWORD_CWORD,
3139 /* 229 */ CWORD_CWORD_CWORD_CWORD,
3140 /* 230 */ CWORD_CWORD_CWORD_CWORD,
3141 /* 231 */ CWORD_CWORD_CWORD_CWORD,
3142 /* 232 */ CWORD_CWORD_CWORD_CWORD,
3143 /* 233 */ CWORD_CWORD_CWORD_CWORD,
3144 /* 234 */ CWORD_CWORD_CWORD_CWORD,
3145 /* 235 */ CWORD_CWORD_CWORD_CWORD,
3146 /* 236 */ CWORD_CWORD_CWORD_CWORD,
3147 /* 237 */ CWORD_CWORD_CWORD_CWORD,
3148 /* 238 */ CWORD_CWORD_CWORD_CWORD,
3149 /* 239 */ CWORD_CWORD_CWORD_CWORD,
3150 /* 230 */ CWORD_CWORD_CWORD_CWORD,
3151 /* 241 */ CWORD_CWORD_CWORD_CWORD,
3152 /* 242 */ CWORD_CWORD_CWORD_CWORD,
3153 /* 243 */ CWORD_CWORD_CWORD_CWORD,
3154 /* 244 */ CWORD_CWORD_CWORD_CWORD,
3155 /* 245 */ CWORD_CWORD_CWORD_CWORD,
3156 /* 246 */ CWORD_CWORD_CWORD_CWORD,
3157 /* 247 */ CWORD_CWORD_CWORD_CWORD,
3158 /* 248 */ CWORD_CWORD_CWORD_CWORD,
3159 /* 249 */ CWORD_CWORD_CWORD_CWORD,
3160 /* 250 */ CWORD_CWORD_CWORD_CWORD,
3161 /* 251 */ CWORD_CWORD_CWORD_CWORD,
3162 /* 252 */ CWORD_CWORD_CWORD_CWORD,
3163 /* 253 */ CWORD_CWORD_CWORD_CWORD,
3164 /* 254 */ CWORD_CWORD_CWORD_CWORD,
3165 /* 255 */ CWORD_CWORD_CWORD_CWORD,
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01003166 /* PEOF */ CENDFILE_CENDFILE_CENDFILE_CENDFILE,
Denys Vlasenkocd716832009-11-28 22:14:02 +01003167# if ENABLE_ASH_ALIAS
3168 /* PEOA */ CSPCL_CIGN_CIGN_CIGN,
3169# endif
Eric Andersen2870d962001-07-02 17:27:21 +00003170};
3171
Denys Vlasenko2fe66b12016-12-12 17:39:12 +01003172#if 1
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01003173# define SIT(c, syntax) ((S_I_T[syntax_index_table[c]] >> ((syntax)*4)) & 0xf)
Denys Vlasenko2fe66b12016-12-12 17:39:12 +01003174#else /* debug version, caught one signed char bug */
3175# define SIT(c, syntax) \
3176 ({ \
3177 if ((c) < 0 || (c) > (PEOF + ENABLE_ASH_ALIAS)) \
3178 bb_error_msg_and_die("line:%d c:%d", __LINE__, (c)); \
Denys Vlasenko0b883582016-12-23 16:49:07 +01003179 if ((syntax) < 0 || (syntax) > (2 + ENABLE_FEATURE_SH_MATH)) \
Denys Vlasenko2fe66b12016-12-12 17:39:12 +01003180 bb_error_msg_and_die("line:%d c:%d", __LINE__, (c)); \
3181 ((S_I_T[syntax_index_table[c]] >> ((syntax)*4)) & 0xf); \
3182 })
3183#endif
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00003184
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01003185#endif /* !USE_SIT_FUNCTION */
Eric Andersenc470f442003-07-28 09:56:35 +00003186
Eric Andersen2870d962001-07-02 17:27:21 +00003187
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00003188/* ============ Alias handling */
Denis Vlasenkofc06f292007-02-23 21:09:35 +00003189
Denis Vlasenko131ae172007-02-18 13:00:19 +00003190#if ENABLE_ASH_ALIAS
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00003191
3192#define ALIASINUSE 1
3193#define ALIASDEAD 2
3194
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00003195struct alias {
3196 struct alias *next;
3197 char *name;
3198 char *val;
3199 int flag;
3200};
3201
Denis Vlasenko01631112007-12-16 17:20:38 +00003202
3203static struct alias **atab; // [ATABSIZE];
3204#define INIT_G_alias() do { \
3205 atab = xzalloc(ATABSIZE * sizeof(atab[0])); \
3206} while (0)
3207
Eric Andersen2870d962001-07-02 17:27:21 +00003208
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00003209static struct alias **
Denys Vlasenko37dc08b2016-10-02 04:38:07 +02003210__lookupalias(const char *name)
3211{
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00003212 unsigned int hashval;
3213 struct alias **app;
3214 const char *p;
3215 unsigned int ch;
3216
3217 p = name;
3218
3219 ch = (unsigned char)*p;
3220 hashval = ch << 4;
3221 while (ch) {
3222 hashval += ch;
3223 ch = (unsigned char)*++p;
3224 }
3225 app = &atab[hashval % ATABSIZE];
3226
3227 for (; *app; app = &(*app)->next) {
3228 if (strcmp(name, (*app)->name) == 0) {
3229 break;
3230 }
3231 }
3232
3233 return app;
3234}
3235
3236static struct alias *
3237lookupalias(const char *name, int check)
3238{
3239 struct alias *ap = *__lookupalias(name);
3240
3241 if (check && ap && (ap->flag & ALIASINUSE))
3242 return NULL;
3243 return ap;
3244}
3245
3246static struct alias *
3247freealias(struct alias *ap)
3248{
3249 struct alias *next;
3250
3251 if (ap->flag & ALIASINUSE) {
3252 ap->flag |= ALIASDEAD;
3253 return ap;
3254 }
3255
3256 next = ap->next;
3257 free(ap->name);
3258 free(ap->val);
3259 free(ap);
3260 return next;
3261}
Eric Andersencb57d552001-06-28 07:25:16 +00003262
Eric Andersenc470f442003-07-28 09:56:35 +00003263static void
3264setalias(const char *name, const char *val)
Eric Andersencb57d552001-06-28 07:25:16 +00003265{
3266 struct alias *ap, **app;
3267
3268 app = __lookupalias(name);
3269 ap = *app;
Denis Vlasenkob012b102007-02-19 22:43:01 +00003270 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +00003271 if (ap) {
3272 if (!(ap->flag & ALIASINUSE)) {
Denis Vlasenkob012b102007-02-19 22:43:01 +00003273 free(ap->val);
Eric Andersencb57d552001-06-28 07:25:16 +00003274 }
Denis Vlasenko0c032a42007-02-23 01:03:40 +00003275 ap->val = ckstrdup(val);
Eric Andersencb57d552001-06-28 07:25:16 +00003276 ap->flag &= ~ALIASDEAD;
3277 } else {
3278 /* not found */
Denis Vlasenko597906c2008-02-20 16:38:54 +00003279 ap = ckzalloc(sizeof(struct alias));
Denis Vlasenko0c032a42007-02-23 01:03:40 +00003280 ap->name = ckstrdup(name);
3281 ap->val = ckstrdup(val);
Denis Vlasenko597906c2008-02-20 16:38:54 +00003282 /*ap->flag = 0; - ckzalloc did it */
3283 /*ap->next = NULL;*/
Eric Andersencb57d552001-06-28 07:25:16 +00003284 *app = ap;
3285 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00003286 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +00003287}
3288
Eric Andersenc470f442003-07-28 09:56:35 +00003289static int
3290unalias(const char *name)
Eric Andersen2870d962001-07-02 17:27:21 +00003291{
Eric Andersencb57d552001-06-28 07:25:16 +00003292 struct alias **app;
3293
3294 app = __lookupalias(name);
3295
3296 if (*app) {
Denis Vlasenkob012b102007-02-19 22:43:01 +00003297 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +00003298 *app = freealias(*app);
Denis Vlasenkob012b102007-02-19 22:43:01 +00003299 INT_ON;
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003300 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003301 }
3302
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003303 return 1;
Eric Andersencb57d552001-06-28 07:25:16 +00003304}
3305
Eric Andersenc470f442003-07-28 09:56:35 +00003306static void
3307rmaliases(void)
Eric Andersen2870d962001-07-02 17:27:21 +00003308{
Eric Andersencb57d552001-06-28 07:25:16 +00003309 struct alias *ap, **app;
3310 int i;
3311
Denis Vlasenkob012b102007-02-19 22:43:01 +00003312 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +00003313 for (i = 0; i < ATABSIZE; i++) {
3314 app = &atab[i];
3315 for (ap = *app; ap; ap = *app) {
3316 *app = freealias(*app);
3317 if (ap == *app) {
3318 app = &ap->next;
3319 }
3320 }
3321 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00003322 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +00003323}
3324
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00003325static void
3326printalias(const struct alias *ap)
3327{
3328 out1fmt("%s=%s\n", ap->name, single_quote(ap->val));
3329}
3330
Eric Andersencb57d552001-06-28 07:25:16 +00003331/*
3332 * TODO - sort output
3333 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02003334static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003335aliascmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003336{
3337 char *n, *v;
3338 int ret = 0;
3339 struct alias *ap;
3340
Denis Vlasenko68404f12008-03-17 09:00:54 +00003341 if (!argv[1]) {
Eric Andersencb57d552001-06-28 07:25:16 +00003342 int i;
3343
Denis Vlasenko68404f12008-03-17 09:00:54 +00003344 for (i = 0; i < ATABSIZE; i++) {
Eric Andersencb57d552001-06-28 07:25:16 +00003345 for (ap = atab[i]; ap; ap = ap->next) {
3346 printalias(ap);
3347 }
Denis Vlasenko68404f12008-03-17 09:00:54 +00003348 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003349 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003350 }
3351 while ((n = *++argv) != NULL) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +00003352 v = strchr(n+1, '=');
3353 if (v == NULL) { /* n+1: funny ksh stuff */
3354 ap = *__lookupalias(n);
3355 if (ap == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00003356 fprintf(stderr, "%s: %s not found\n", "alias", n);
Eric Andersencb57d552001-06-28 07:25:16 +00003357 ret = 1;
3358 } else
3359 printalias(ap);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003360 } else {
Eric Andersencb57d552001-06-28 07:25:16 +00003361 *v++ = '\0';
3362 setalias(n, v);
3363 }
3364 }
3365
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003366 return ret;
Eric Andersencb57d552001-06-28 07:25:16 +00003367}
3368
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02003369static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003370unaliascmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +00003371{
3372 int i;
3373
Denys Vlasenko6c149f42017-04-12 21:31:32 +02003374 while (nextopt("a") != '\0') {
3375 rmaliases();
3376 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003377 }
3378 for (i = 0; *argptr; argptr++) {
3379 if (unalias(*argptr)) {
Eric Andersenc470f442003-07-28 09:56:35 +00003380 fprintf(stderr, "%s: %s not found\n", "unalias", *argptr);
Eric Andersencb57d552001-06-28 07:25:16 +00003381 i = 1;
3382 }
3383 }
3384
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003385 return i;
Eric Andersencb57d552001-06-28 07:25:16 +00003386}
Denis Vlasenkofc06f292007-02-23 21:09:35 +00003387
Denis Vlasenko131ae172007-02-18 13:00:19 +00003388#endif /* ASH_ALIAS */
Eric Andersencb57d552001-06-28 07:25:16 +00003389
Eric Andersenc470f442003-07-28 09:56:35 +00003390
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003391/* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */
Denys Vlasenko285ad152009-12-04 23:02:27 +01003392#define FORK_FG 0
3393#define FORK_BG 1
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003394#define FORK_NOJOB 2
3395
3396/* mode flags for showjob(s) */
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02003397#define SHOW_ONLY_PGID 0x01 /* show only pgid (jobs -p) */
3398#define SHOW_PIDS 0x02 /* show individual pids, not just one line per job */
3399#define SHOW_CHANGED 0x04 /* only jobs whose state has changed */
Denys Vlasenko9c541002015-10-07 15:44:36 +02003400#define SHOW_STDERR 0x08 /* print to stderr (else stdout) */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003401
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003402/*
3403 * A job structure contains information about a job. A job is either a
3404 * single process or a set of processes contained in a pipeline. In the
3405 * latter case, pidlist will be non-NULL, and will point to a -1 terminated
3406 * array of pids.
3407 */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003408struct procstat {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003409 pid_t ps_pid; /* process id */
3410 int ps_status; /* last process status from wait() */
3411 char *ps_cmd; /* text of command being run */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003412};
3413
3414struct job {
3415 struct procstat ps0; /* status of process */
3416 struct procstat *ps; /* status or processes when more than one */
3417#if JOBS
3418 int stopstatus; /* status of a stopped job */
3419#endif
Denys Vlasenko4c179372017-01-11 18:44:15 +01003420 unsigned nprocs; /* number of processes */
3421
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003422#define JOBRUNNING 0 /* at least one proc running */
3423#define JOBSTOPPED 1 /* all procs are stopped */
3424#define JOBDONE 2 /* all procs are completed */
Denys Vlasenko4c179372017-01-11 18:44:15 +01003425 unsigned
3426 state: 8,
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003427#if JOBS
3428 sigint: 1, /* job was killed by SIGINT */
3429 jobctl: 1, /* job running under job control */
3430#endif
3431 waited: 1, /* true if this entry has been waited for */
3432 used: 1, /* true if this entry is in used */
3433 changed: 1; /* true if status has changed */
3434 struct job *prev_job; /* previous job */
3435};
3436
Denis Vlasenko68404f12008-03-17 09:00:54 +00003437static struct job *makejob(/*union node *,*/ int);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003438static int forkshell(struct job *, union node *, int);
3439static int waitforjob(struct job *);
3440
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00003441#if !JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +00003442enum { doing_jobctl = 0 };
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00003443#define setjobctl(on) do {} while (0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003444#else
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003445static smallint doing_jobctl; //references:8
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003446static void setjobctl(int);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003447#endif
3448
3449/*
Denis Vlasenko4b875702009-03-19 13:30:04 +00003450 * Ignore a signal.
3451 */
3452static void
3453ignoresig(int signo)
3454{
3455 /* Avoid unnecessary system calls. Is it already SIG_IGNed? */
3456 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
3457 /* No, need to do it */
3458 signal(signo, SIG_IGN);
3459 }
3460 sigmode[signo - 1] = S_HARD_IGN;
3461}
3462
3463/*
Denys Vlasenko238bf182010-05-18 15:49:07 +02003464 * Only one usage site - in setsignal()
Denis Vlasenko4b875702009-03-19 13:30:04 +00003465 */
3466static void
Denys Vlasenko238bf182010-05-18 15:49:07 +02003467signal_handler(int signo)
Denis Vlasenko4b875702009-03-19 13:30:04 +00003468{
Denys Vlasenko458c1f22016-10-27 23:51:19 +02003469 if (signo == SIGCHLD) {
3470 got_sigchld = 1;
3471 if (!trap[SIGCHLD])
3472 return;
3473 }
3474
Denis Vlasenko4b875702009-03-19 13:30:04 +00003475 gotsig[signo - 1] = 1;
Denys Vlasenko458c1f22016-10-27 23:51:19 +02003476 pending_sig = signo;
Denis Vlasenko4b875702009-03-19 13:30:04 +00003477
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02003478 if (signo == SIGINT && !trap[SIGINT]) {
3479 if (!suppress_int) {
3480 pending_sig = 0;
Denis Vlasenko4b875702009-03-19 13:30:04 +00003481 raise_interrupt(); /* does not return */
3482 }
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02003483 pending_int = 1;
Denis Vlasenko4b875702009-03-19 13:30:04 +00003484 }
3485}
3486
3487/*
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003488 * Set the signal handler for the specified signal. The routine figures
3489 * out what it should be set to.
3490 */
3491static void
3492setsignal(int signo)
3493{
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003494 char *t;
3495 char cur_act, new_act;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003496 struct sigaction act;
3497
3498 t = trap[signo];
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003499 new_act = S_DFL;
3500 if (t != NULL) { /* trap for this sig is set */
3501 new_act = S_CATCH;
3502 if (t[0] == '\0') /* trap is "": ignore this sig */
3503 new_act = S_IGN;
3504 }
3505
3506 if (rootshell && new_act == S_DFL) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003507 switch (signo) {
3508 case SIGINT:
3509 if (iflag || minusc || sflag == 0)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003510 new_act = S_CATCH;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003511 break;
3512 case SIGQUIT:
3513#if DEBUG
3514 if (debug)
3515 break;
3516#endif
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003517 /* man bash:
3518 * "In all cases, bash ignores SIGQUIT. Non-builtin
3519 * commands run by bash have signal handlers
3520 * set to the values inherited by the shell
3521 * from its parent". */
3522 new_act = S_IGN;
3523 break;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003524 case SIGTERM:
3525 if (iflag)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003526 new_act = S_IGN;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003527 break;
3528#if JOBS
3529 case SIGTSTP:
3530 case SIGTTOU:
3531 if (mflag)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003532 new_act = S_IGN;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003533 break;
3534#endif
3535 }
3536 }
Denys Vlasenko49e6bf22017-08-04 14:28:16 +02003537 /* if !rootshell, we reset SIGQUIT to DFL,
3538 * whereas we have to restore it to what shell got on entry.
3539 * This is handled by the fact that if signal was IGNored on entry,
3540 * then cur_act is S_HARD_IGN and we never change its sigaction
3541 * (see code below).
3542 */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003543
Denys Vlasenko458c1f22016-10-27 23:51:19 +02003544 if (signo == SIGCHLD)
3545 new_act = S_CATCH;
3546
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003547 t = &sigmode[signo - 1];
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003548 cur_act = *t;
3549 if (cur_act == 0) {
3550 /* current setting is not yet known */
3551 if (sigaction(signo, NULL, &act)) {
3552 /* pretend it worked; maybe we should give a warning,
3553 * but other shells don't. We don't alter sigmode,
3554 * so we retry every time.
3555 * btw, in Linux it never fails. --vda */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003556 return;
3557 }
3558 if (act.sa_handler == SIG_IGN) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003559 cur_act = S_HARD_IGN;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003560 if (mflag
3561 && (signo == SIGTSTP || signo == SIGTTIN || signo == SIGTTOU)
3562 ) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003563 cur_act = S_IGN; /* don't hard ignore these */
Denis Vlasenko991a1da2008-02-10 19:02:53 +00003564 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003565 }
Denys Vlasenko0f14f412017-08-06 20:06:19 +02003566 if (act.sa_handler == SIG_DFL && new_act == S_DFL) {
3567 /* installing SIG_DFL over SIG_DFL is a no-op */
3568 /* saves one sigaction call in each "sh -c SCRIPT" invocation */
3569 *t = S_DFL;
3570 return;
3571 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003572 }
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003573 if (cur_act == S_HARD_IGN || cur_act == new_act)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003574 return;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003575
Denys Vlasenko49e6bf22017-08-04 14:28:16 +02003576 *t = new_act;
3577
Denis Vlasenko991a1da2008-02-10 19:02:53 +00003578 act.sa_handler = SIG_DFL;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003579 switch (new_act) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003580 case S_CATCH:
Denys Vlasenko238bf182010-05-18 15:49:07 +02003581 act.sa_handler = signal_handler;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003582 break;
3583 case S_IGN:
3584 act.sa_handler = SIG_IGN;
3585 break;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003586 }
Ian Wienand89b3cba2011-04-16 20:05:14 +02003587 /* flags and mask matter only if !DFL and !IGN, but we do it
3588 * for all cases for more deterministic behavior:
3589 */
Denys Vlasenko49e6bf22017-08-04 14:28:16 +02003590 act.sa_flags = 0; //TODO: why not SA_RESTART?
Ian Wienand89b3cba2011-04-16 20:05:14 +02003591 sigfillset(&act.sa_mask);
3592
Denis Vlasenko8e2cfec2008-03-12 23:19:35 +00003593 sigaction_set(signo, &act);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003594}
3595
3596/* mode flags for set_curjob */
3597#define CUR_DELETE 2
3598#define CUR_RUNNING 1
3599#define CUR_STOPPED 0
3600
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003601#if JOBS
3602/* pgrp of shell on invocation */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003603static int initialpgrp; //references:2
3604static int ttyfd = -1; //5
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003605#endif
3606/* array of jobs */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003607static struct job *jobtab; //5
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003608/* size of array */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003609static unsigned njobs; //4
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003610/* current job */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003611static struct job *curjob; //lots
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003612/* number of presumed living untracked jobs */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003613static int jobless; //4
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003614
Denys Vlasenko098b7132017-01-11 19:59:03 +01003615#if 0
3616/* Bash has a feature: it restores termios after a successful wait for
3617 * a foreground job which had at least one stopped or sigkilled member.
3618 * The probable rationale is that SIGSTOP and SIGKILL can preclude task from
3619 * properly restoring tty state. Should we do this too?
3620 * A reproducer: ^Z an interactive python:
3621 *
3622 * # python
3623 * Python 2.7.12 (...)
3624 * >>> ^Z
3625 * { python leaves tty in -icanon -echo state. We do survive that... }
3626 * [1]+ Stopped python
3627 * { ...however, next program (python #2) does not survive it well: }
3628 * # python
3629 * Python 2.7.12 (...)
3630 * >>> Traceback (most recent call last):
3631 * { above, I typed "qwerty<CR>", but -echo state is still in effect }
3632 * File "<stdin>", line 1, in <module>
3633 * NameError: name 'qwerty' is not defined
3634 *
3635 * The implementation below is modeled on bash code and seems to work.
3636 * However, I'm not sure we should do this. For one: what if I'd fg
3637 * the stopped python instead? It'll be confused by "restored" tty state.
3638 */
3639static struct termios shell_tty_info;
3640static void
3641get_tty_state(void)
3642{
3643 if (rootshell && ttyfd >= 0)
3644 tcgetattr(ttyfd, &shell_tty_info);
3645}
3646static void
3647set_tty_state(void)
3648{
3649 /* if (rootshell) - caller ensures this */
3650 if (ttyfd >= 0)
3651 tcsetattr(ttyfd, TCSADRAIN, &shell_tty_info);
3652}
3653static int
3654job_signal_status(struct job *jp)
3655{
3656 int status;
3657 unsigned i;
3658 struct procstat *ps = jp->ps;
3659 for (i = 0; i < jp->nprocs; i++) {
3660 status = ps[i].ps_status;
3661 if (WIFSIGNALED(status) || WIFSTOPPED(status))
3662 return status;
3663 }
3664 return 0;
3665}
3666static void
3667restore_tty_if_stopped_or_signaled(struct job *jp)
3668{
3669//TODO: check what happens if we come from waitforjob() in expbackq()
3670 if (rootshell) {
3671 int s = job_signal_status(jp);
3672 if (s) /* WIFSIGNALED(s) || WIFSTOPPED(s) */
3673 set_tty_state();
3674 }
3675}
3676#else
3677# define get_tty_state() ((void)0)
3678# define restore_tty_if_stopped_or_signaled(jp) ((void)0)
3679#endif
3680
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003681static void
3682set_curjob(struct job *jp, unsigned mode)
3683{
3684 struct job *jp1;
3685 struct job **jpp, **curp;
3686
3687 /* first remove from list */
3688 jpp = curp = &curjob;
Denys Vlasenko940c7202011-03-02 04:07:14 +01003689 while (1) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003690 jp1 = *jpp;
3691 if (jp1 == jp)
3692 break;
3693 jpp = &jp1->prev_job;
Denys Vlasenko940c7202011-03-02 04:07:14 +01003694 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003695 *jpp = jp1->prev_job;
3696
3697 /* Then re-insert in correct position */
3698 jpp = curp;
3699 switch (mode) {
3700 default:
3701#if DEBUG
3702 abort();
3703#endif
3704 case CUR_DELETE:
3705 /* job being deleted */
3706 break;
3707 case CUR_RUNNING:
3708 /* newly created job or backgrounded job,
Denys Vlasenko60cb48c2013-01-14 15:57:44 +01003709 * put after all stopped jobs.
3710 */
Denys Vlasenko940c7202011-03-02 04:07:14 +01003711 while (1) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003712 jp1 = *jpp;
3713#if JOBS
3714 if (!jp1 || jp1->state != JOBSTOPPED)
3715#endif
3716 break;
3717 jpp = &jp1->prev_job;
Denys Vlasenko940c7202011-03-02 04:07:14 +01003718 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003719 /* FALLTHROUGH */
3720#if JOBS
3721 case CUR_STOPPED:
3722#endif
3723 /* newly stopped job - becomes curjob */
3724 jp->prev_job = *jpp;
3725 *jpp = jp;
3726 break;
3727 }
3728}
3729
3730#if JOBS || DEBUG
3731static int
3732jobno(const struct job *jp)
3733{
3734 return jp - jobtab + 1;
3735}
3736#endif
3737
3738/*
3739 * Convert a job name to a job structure.
3740 */
Denis Vlasenko85c24712008-03-17 09:04:04 +00003741#if !JOBS
3742#define getjob(name, getctl) getjob(name)
3743#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003744static struct job *
3745getjob(const char *name, int getctl)
3746{
3747 struct job *jp;
3748 struct job *found;
Denys Vlasenkoffc39202009-08-17 02:12:20 +02003749 const char *err_msg = "%s: no such job";
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003750 unsigned num;
3751 int c;
3752 const char *p;
3753 char *(*match)(const char *, const char *);
3754
3755 jp = curjob;
3756 p = name;
3757 if (!p)
3758 goto currentjob;
3759
3760 if (*p != '%')
3761 goto err;
3762
3763 c = *++p;
3764 if (!c)
3765 goto currentjob;
3766
3767 if (!p[1]) {
3768 if (c == '+' || c == '%') {
3769 currentjob:
3770 err_msg = "No current job";
3771 goto check;
3772 }
3773 if (c == '-') {
3774 if (jp)
3775 jp = jp->prev_job;
3776 err_msg = "No previous job";
3777 check:
3778 if (!jp)
3779 goto err;
3780 goto gotit;
3781 }
3782 }
3783
3784 if (is_number(p)) {
3785 num = atoi(p);
Denys Vlasenko46a45ce2016-09-29 01:10:08 +02003786 if (num > 0 && num <= njobs) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003787 jp = jobtab + num - 1;
3788 if (jp->used)
3789 goto gotit;
3790 goto err;
3791 }
3792 }
3793
3794 match = prefix;
3795 if (*p == '?') {
3796 match = strstr;
3797 p++;
3798 }
3799
Denys Vlasenkoffc39202009-08-17 02:12:20 +02003800 found = NULL;
3801 while (jp) {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003802 if (match(jp->ps[0].ps_cmd, p)) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003803 if (found)
3804 goto err;
3805 found = jp;
3806 err_msg = "%s: ambiguous";
3807 }
3808 jp = jp->prev_job;
3809 }
Denys Vlasenkoffc39202009-08-17 02:12:20 +02003810 if (!found)
3811 goto err;
3812 jp = found;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003813
3814 gotit:
3815#if JOBS
3816 err_msg = "job %s not created under job control";
3817 if (getctl && jp->jobctl == 0)
3818 goto err;
3819#endif
3820 return jp;
3821 err:
3822 ash_msg_and_raise_error(err_msg, name);
3823}
3824
3825/*
3826 * Mark a job structure as unused.
3827 */
3828static void
3829freejob(struct job *jp)
3830{
3831 struct procstat *ps;
3832 int i;
3833
3834 INT_OFF;
3835 for (i = jp->nprocs, ps = jp->ps; --i >= 0; ps++) {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003836 if (ps->ps_cmd != nullstr)
3837 free(ps->ps_cmd);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003838 }
3839 if (jp->ps != &jp->ps0)
3840 free(jp->ps);
3841 jp->used = 0;
3842 set_curjob(jp, CUR_DELETE);
3843 INT_ON;
3844}
3845
3846#if JOBS
3847static void
3848xtcsetpgrp(int fd, pid_t pgrp)
3849{
3850 if (tcsetpgrp(fd, pgrp))
Ron Yorstonbe366e52017-07-27 13:53:39 +01003851 ash_msg_and_raise_perror("can't set tty process group");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003852}
3853
3854/*
3855 * Turn job control on and off.
3856 *
3857 * Note: This code assumes that the third arg to ioctl is a character
3858 * pointer, which is true on Berkeley systems but not System V. Since
3859 * System V doesn't have job control yet, this isn't a problem now.
3860 *
3861 * Called with interrupts off.
3862 */
3863static void
3864setjobctl(int on)
3865{
3866 int fd;
3867 int pgrp;
3868
Denis Vlasenkob07a4962008-06-22 13:16:23 +00003869 if (on == doing_jobctl || rootshell == 0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003870 return;
3871 if (on) {
3872 int ofd;
3873 ofd = fd = open(_PATH_TTY, O_RDWR);
3874 if (fd < 0) {
3875 /* BTW, bash will try to open(ttyname(0)) if open("/dev/tty") fails.
3876 * That sometimes helps to acquire controlling tty.
3877 * Obviously, a workaround for bugs when someone
3878 * failed to provide a controlling tty to bash! :) */
Denis Vlasenkoed270a52007-11-26 05:37:07 +00003879 fd = 2;
3880 while (!isatty(fd))
3881 if (--fd < 0)
3882 goto out;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003883 }
Denys Vlasenko64774602016-10-26 15:24:30 +02003884 /* fd is a tty at this point */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003885 fd = fcntl(fd, F_DUPFD, 10);
Denys Vlasenko10ad6222017-04-17 16:13:32 +02003886 if (ofd >= 0) /* if it is "/dev/tty", close. If 0/1/2, don't */
Denis Vlasenkoed270a52007-11-26 05:37:07 +00003887 close(ofd);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003888 if (fd < 0)
Denys Vlasenko64774602016-10-26 15:24:30 +02003889 goto out; /* F_DUPFD failed */
Denis Vlasenko96e1b382007-09-30 23:50:48 +00003890 close_on_exec_on(fd);
Denys Vlasenko940c7202011-03-02 04:07:14 +01003891 while (1) { /* while we are in the background */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003892 pgrp = tcgetpgrp(fd);
3893 if (pgrp < 0) {
3894 out:
3895 ash_msg("can't access tty; job control turned off");
3896 mflag = on = 0;
3897 goto close;
3898 }
3899 if (pgrp == getpgrp())
3900 break;
3901 killpg(0, SIGTTIN);
Denys Vlasenko940c7202011-03-02 04:07:14 +01003902 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003903 initialpgrp = pgrp;
3904
3905 setsignal(SIGTSTP);
3906 setsignal(SIGTTOU);
3907 setsignal(SIGTTIN);
3908 pgrp = rootpid;
3909 setpgid(0, pgrp);
3910 xtcsetpgrp(fd, pgrp);
3911 } else {
3912 /* turning job control off */
3913 fd = ttyfd;
3914 pgrp = initialpgrp;
Denis Vlasenko08c8c1d2007-04-28 22:39:02 +00003915 /* was xtcsetpgrp, but this can make exiting ash
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00003916 * loop forever if pty is already deleted */
Denis Vlasenko08c8c1d2007-04-28 22:39:02 +00003917 tcsetpgrp(fd, pgrp);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003918 setpgid(0, pgrp);
3919 setsignal(SIGTSTP);
3920 setsignal(SIGTTOU);
3921 setsignal(SIGTTIN);
3922 close:
Denis Vlasenkoed270a52007-11-26 05:37:07 +00003923 if (fd >= 0)
3924 close(fd);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003925 fd = -1;
3926 }
3927 ttyfd = fd;
Denis Vlasenkob07a4962008-06-22 13:16:23 +00003928 doing_jobctl = on;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003929}
3930
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02003931static int FAST_FUNC
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003932killcmd(int argc, char **argv)
3933{
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003934 if (argv[1] && strcmp(argv[1], "-l") != 0) {
Denys Vlasenkob12553f2011-02-21 03:22:20 +01003935 int i = 1;
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003936 do {
3937 if (argv[i][0] == '%') {
Denys Vlasenkob12553f2011-02-21 03:22:20 +01003938 /*
3939 * "kill %N" - job kill
3940 * Converting to pgrp / pid kill
3941 */
3942 struct job *jp;
3943 char *dst;
3944 int j, n;
3945
3946 jp = getjob(argv[i], 0);
3947 /*
3948 * In jobs started under job control, we signal
3949 * entire process group by kill -PGRP_ID.
3950 * This happens, f.e., in interactive shell.
3951 *
3952 * Otherwise, we signal each child via
3953 * kill PID1 PID2 PID3.
3954 * Testcases:
3955 * sh -c 'sleep 1|sleep 1 & kill %1'
3956 * sh -c 'true|sleep 2 & sleep 1; kill %1'
3957 * sh -c 'true|sleep 1 & sleep 2; kill %1'
3958 */
3959 n = jp->nprocs; /* can't be 0 (I hope) */
3960 if (jp->jobctl)
3961 n = 1;
3962 dst = alloca(n * sizeof(int)*4);
3963 argv[i] = dst;
3964 for (j = 0; j < n; j++) {
3965 struct procstat *ps = &jp->ps[j];
3966 /* Skip non-running and not-stopped members
3967 * (i.e. dead members) of the job
3968 */
3969 if (ps->ps_status != -1 && !WIFSTOPPED(ps->ps_status))
3970 continue;
3971 /*
3972 * kill_main has matching code to expect
3973 * leading space. Needed to not confuse
3974 * negative pids with "kill -SIGNAL_NO" syntax
3975 */
3976 dst += sprintf(dst, jp->jobctl ? " -%u" : " %u", (int)ps->ps_pid);
3977 }
3978 *dst = '\0';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003979 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003980 } while (argv[++i]);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003981 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003982 return kill_main(argc, argv);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003983}
3984
3985static void
Denys Vlasenko285ad152009-12-04 23:02:27 +01003986showpipe(struct job *jp /*, FILE *out*/)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003987{
Denys Vlasenko285ad152009-12-04 23:02:27 +01003988 struct procstat *ps;
3989 struct procstat *psend;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003990
Denys Vlasenko285ad152009-12-04 23:02:27 +01003991 psend = jp->ps + jp->nprocs;
3992 for (ps = jp->ps + 1; ps < psend; ps++)
3993 printf(" | %s", ps->ps_cmd);
Denys Vlasenko9c541002015-10-07 15:44:36 +02003994 newline_and_flush(stdout);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003995 flush_stdout_stderr();
3996}
3997
3998
3999static int
4000restartjob(struct job *jp, int mode)
4001{
4002 struct procstat *ps;
4003 int i;
4004 int status;
4005 pid_t pgid;
4006
4007 INT_OFF;
4008 if (jp->state == JOBDONE)
4009 goto out;
4010 jp->state = JOBRUNNING;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004011 pgid = jp->ps[0].ps_pid;
Denys Vlasenko098b7132017-01-11 19:59:03 +01004012 if (mode == FORK_FG) {
4013 get_tty_state();
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004014 xtcsetpgrp(ttyfd, pgid);
Denys Vlasenko098b7132017-01-11 19:59:03 +01004015 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004016 killpg(pgid, SIGCONT);
4017 ps = jp->ps;
4018 i = jp->nprocs;
4019 do {
Denys Vlasenko285ad152009-12-04 23:02:27 +01004020 if (WIFSTOPPED(ps->ps_status)) {
4021 ps->ps_status = -1;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004022 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00004023 ps++;
4024 } while (--i);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004025 out:
4026 status = (mode == FORK_FG) ? waitforjob(jp) : 0;
4027 INT_ON;
4028 return status;
4029}
4030
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02004031static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00004032fg_bgcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004033{
4034 struct job *jp;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004035 int mode;
4036 int retval;
4037
4038 mode = (**argv == 'f') ? FORK_FG : FORK_BG;
4039 nextopt(nullstr);
4040 argv = argptr;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004041 do {
4042 jp = getjob(*argv, 1);
4043 if (mode == FORK_BG) {
4044 set_curjob(jp, CUR_RUNNING);
Denys Vlasenko285ad152009-12-04 23:02:27 +01004045 printf("[%d] ", jobno(jp));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004046 }
Denys Vlasenko285ad152009-12-04 23:02:27 +01004047 out1str(jp->ps[0].ps_cmd);
4048 showpipe(jp /*, stdout*/);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004049 retval = restartjob(jp, mode);
4050 } while (*argv && *++argv);
4051 return retval;
4052}
4053#endif
4054
4055static int
Denys Vlasenko9c541002015-10-07 15:44:36 +02004056sprint_status48(char *s, int status, int sigonly)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004057{
4058 int col;
4059 int st;
4060
4061 col = 0;
4062 if (!WIFEXITED(status)) {
Johannes Schindelin9d4dc842017-07-14 22:25:58 +02004063#if JOBS
4064 if (WIFSTOPPED(status))
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004065 st = WSTOPSIG(status);
4066 else
Johannes Schindelin9d4dc842017-07-14 22:25:58 +02004067#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004068 st = WTERMSIG(status);
4069 if (sigonly) {
4070 if (st == SIGINT || st == SIGPIPE)
4071 goto out;
Johannes Schindelin9d4dc842017-07-14 22:25:58 +02004072#if JOBS
4073 if (WIFSTOPPED(status))
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004074 goto out;
Johannes Schindelin9d4dc842017-07-14 22:25:58 +02004075#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004076 }
4077 st &= 0x7f;
Denys Vlasenko7c6f2462011-02-14 17:17:10 +01004078//TODO: use bbox's get_signame? strsignal adds ~600 bytes to text+rodata
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004079 col = fmtstr(s, 32, strsignal(st));
4080 if (WCOREDUMP(status)) {
Denys Vlasenko9c541002015-10-07 15:44:36 +02004081 strcpy(s + col, " (core dumped)");
4082 col += sizeof(" (core dumped)")-1;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004083 }
4084 } else if (!sigonly) {
4085 st = WEXITSTATUS(status);
Denys Vlasenko9c541002015-10-07 15:44:36 +02004086 col = fmtstr(s, 16, (st ? "Done(%d)" : "Done"), st);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004087 }
4088 out:
4089 return col;
4090}
4091
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004092static int
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004093wait_block_or_sig(int *status)
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004094{
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004095 int pid;
4096
4097 do {
Denys Vlasenko1ab7c2f2016-11-03 20:17:23 +01004098 sigset_t mask;
4099
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004100 /* Poll all children for changes in their state */
4101 got_sigchld = 0;
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004102 /* if job control is active, accept stopped processes too */
4103 pid = waitpid(-1, status, doing_jobctl ? (WNOHANG|WUNTRACED) : WNOHANG);
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004104 if (pid != 0)
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004105 break; /* Error (e.g. EINTR, ECHILD) or pid */
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004106
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004107 /* Children exist, but none are ready. Sleep until interesting signal */
Denys Vlasenko1ab7c2f2016-11-03 20:17:23 +01004108#if 1
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004109 sigfillset(&mask);
4110 sigprocmask(SIG_SETMASK, &mask, &mask);
4111 while (!got_sigchld && !pending_sig)
4112 sigsuspend(&mask);
4113 sigprocmask(SIG_SETMASK, &mask, NULL);
Denys Vlasenko1ab7c2f2016-11-03 20:17:23 +01004114#else /* unsafe: a signal can set pending_sig after check, but before pause() */
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004115 while (!got_sigchld && !pending_sig)
4116 pause();
4117#endif
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004118
4119 /* If it was SIGCHLD, poll children again */
4120 } while (got_sigchld);
4121
4122 return pid;
4123}
4124
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004125#define DOWAIT_NONBLOCK 0
4126#define DOWAIT_BLOCK 1
4127#define DOWAIT_BLOCK_OR_SIG 2
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004128
4129static int
Denys Vlasenkob543bda2016-10-27 20:08:28 +02004130dowait(int block, struct job *job)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004131{
4132 int pid;
4133 int status;
4134 struct job *jp;
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004135 struct job *thisjob = NULL;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004136
Denys Vlasenkob543bda2016-10-27 20:08:28 +02004137 TRACE(("dowait(0x%x) called\n", block));
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +00004138
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004139 /* It's wrong to call waitpid() outside of INT_OFF region:
4140 * signal can arrive just after syscall return and handler can
4141 * longjmp away, losing stop/exit notification processing.
4142 * Thus, for "jobs" builtin, and for waiting for a fg job,
4143 * we call waitpid() (blocking or non-blocking) inside INT_OFF.
4144 *
4145 * However, for "wait" builtin it is wrong to simply call waitpid()
4146 * in INT_OFF region: "wait" needs to wait for any running job
4147 * to change state, but should exit on any trap too.
4148 * In INT_OFF region, a signal just before syscall entry can set
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004149 * pending_sig variables, but we can't check them, and we would
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004150 * either enter a sleeping waitpid() (BUG), or need to busy-loop.
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004151 *
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004152 * Because of this, we run inside INT_OFF, but use a special routine
Denys Vlasenko1ab7c2f2016-11-03 20:17:23 +01004153 * which combines waitpid() and sigsuspend().
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004154 * This is the reason why we need to have a handler for SIGCHLD:
Denys Vlasenko1ab7c2f2016-11-03 20:17:23 +01004155 * SIG_DFL handler does not wake sigsuspend().
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004156 */
4157 INT_OFF;
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004158 if (block == DOWAIT_BLOCK_OR_SIG) {
4159 pid = wait_block_or_sig(&status);
4160 } else {
4161 int wait_flags = 0;
4162 if (block == DOWAIT_NONBLOCK)
4163 wait_flags = WNOHANG;
4164 /* if job control is active, accept stopped processes too */
4165 if (doing_jobctl)
4166 wait_flags |= WUNTRACED;
4167 /* NB: _not_ safe_waitpid, we need to detect EINTR */
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004168 pid = waitpid(-1, &status, wait_flags);
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004169 }
Denis Vlasenkob21f3792009-03-19 23:09:58 +00004170 TRACE(("wait returns pid=%d, status=0x%x, errno=%d(%s)\n",
4171 pid, status, errno, strerror(errno)));
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004172 if (pid <= 0)
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004173 goto out;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004174
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004175 thisjob = NULL;
4176 for (jp = curjob; jp; jp = jp->prev_job) {
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004177 int jobstate;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004178 struct procstat *ps;
4179 struct procstat *psend;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004180 if (jp->state == JOBDONE)
4181 continue;
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004182 jobstate = JOBDONE;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004183 ps = jp->ps;
4184 psend = ps + jp->nprocs;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004185 do {
Denys Vlasenko285ad152009-12-04 23:02:27 +01004186 if (ps->ps_pid == pid) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004187 TRACE(("Job %d: changing status of proc %d "
4188 "from 0x%x to 0x%x\n",
Denys Vlasenko285ad152009-12-04 23:02:27 +01004189 jobno(jp), pid, ps->ps_status, status));
4190 ps->ps_status = status;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004191 thisjob = jp;
4192 }
Denys Vlasenko285ad152009-12-04 23:02:27 +01004193 if (ps->ps_status == -1)
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004194 jobstate = JOBRUNNING;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004195#if JOBS
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004196 if (jobstate == JOBRUNNING)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004197 continue;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004198 if (WIFSTOPPED(ps->ps_status)) {
4199 jp->stopstatus = ps->ps_status;
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004200 jobstate = JOBSTOPPED;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004201 }
4202#endif
Denys Vlasenko285ad152009-12-04 23:02:27 +01004203 } while (++ps < psend);
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004204 if (!thisjob)
4205 continue;
4206
4207 /* Found the job where one of its processes changed its state.
4208 * Is there at least one live and running process in this job? */
4209 if (jobstate != JOBRUNNING) {
4210 /* No. All live processes in the job are stopped
4211 * (JOBSTOPPED) or there are no live processes (JOBDONE)
4212 */
4213 thisjob->changed = 1;
4214 if (thisjob->state != jobstate) {
4215 TRACE(("Job %d: changing state from %d to %d\n",
4216 jobno(thisjob), thisjob->state, jobstate));
4217 thisjob->state = jobstate;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004218#if JOBS
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004219 if (jobstate == JOBSTOPPED)
4220 set_curjob(thisjob, CUR_STOPPED);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004221#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004222 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004223 }
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004224 goto out;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004225 }
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004226 /* The process wasn't found in job list */
Johannes Schindelin9d4dc842017-07-14 22:25:58 +02004227#if JOBS
4228 if (!WIFSTOPPED(status))
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004229 jobless--;
Johannes Schindelin9d4dc842017-07-14 22:25:58 +02004230#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004231 out:
4232 INT_ON;
4233
4234 if (thisjob && thisjob == job) {
4235 char s[48 + 1];
4236 int len;
4237
Denys Vlasenko9c541002015-10-07 15:44:36 +02004238 len = sprint_status48(s, status, 1);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004239 if (len) {
4240 s[len] = '\n';
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004241 s[len + 1] = '\0';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004242 out2str(s);
4243 }
4244 }
4245 return pid;
4246}
4247
4248#if JOBS
4249static void
Denys Vlasenko9c541002015-10-07 15:44:36 +02004250showjob(struct job *jp, int mode)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004251{
4252 struct procstat *ps;
4253 struct procstat *psend;
4254 int col;
Denis Vlasenko40ba9982007-07-14 00:48:29 +00004255 int indent_col;
Denys Vlasenko9c541002015-10-07 15:44:36 +02004256 char s[16 + 16 + 48];
4257 FILE *out = (mode & SHOW_STDERR ? stderr : stdout);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004258
4259 ps = jp->ps;
4260
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004261 if (mode & SHOW_ONLY_PGID) { /* jobs -p */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004262 /* just output process (group) id of pipeline */
Denys Vlasenko285ad152009-12-04 23:02:27 +01004263 fprintf(out, "%d\n", ps->ps_pid);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004264 return;
4265 }
4266
4267 col = fmtstr(s, 16, "[%d] ", jobno(jp));
Denis Vlasenko40ba9982007-07-14 00:48:29 +00004268 indent_col = col;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004269
4270 if (jp == curjob)
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004271 s[col - 3] = '+';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004272 else if (curjob && jp == curjob->prev_job)
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004273 s[col - 3] = '-';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004274
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004275 if (mode & SHOW_PIDS)
Denys Vlasenko285ad152009-12-04 23:02:27 +01004276 col += fmtstr(s + col, 16, "%d ", ps->ps_pid);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004277
4278 psend = ps + jp->nprocs;
4279
4280 if (jp->state == JOBRUNNING) {
4281 strcpy(s + col, "Running");
4282 col += sizeof("Running") - 1;
4283 } else {
Denys Vlasenko285ad152009-12-04 23:02:27 +01004284 int status = psend[-1].ps_status;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004285 if (jp->state == JOBSTOPPED)
4286 status = jp->stopstatus;
Denys Vlasenko9c541002015-10-07 15:44:36 +02004287 col += sprint_status48(s + col, status, 0);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004288 }
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004289 /* By now, "[JOBID]* [maybe PID] STATUS" is printed */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004290
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004291 /* This loop either prints "<cmd1> | <cmd2> | <cmd3>" line
4292 * or prints several "PID | <cmdN>" lines,
4293 * depending on SHOW_PIDS bit.
4294 * We do not print status of individual processes
4295 * between PID and <cmdN>. bash does it, but not very well:
4296 * first line shows overall job status, not process status,
4297 * making it impossible to know 1st process status.
4298 */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004299 goto start;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004300 do {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004301 /* for each process */
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004302 s[0] = '\0';
4303 col = 33;
4304 if (mode & SHOW_PIDS)
Denys Vlasenko285ad152009-12-04 23:02:27 +01004305 col = fmtstr(s, 48, "\n%*c%d ", indent_col, ' ', ps->ps_pid) - 1;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004306 start:
Denys Vlasenko285ad152009-12-04 23:02:27 +01004307 fprintf(out, "%s%*c%s%s",
4308 s,
4309 33 - col >= 0 ? 33 - col : 0, ' ',
4310 ps == jp->ps ? "" : "| ",
4311 ps->ps_cmd
4312 );
4313 } while (++ps != psend);
Denys Vlasenko9c541002015-10-07 15:44:36 +02004314 newline_and_flush(out);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004315
4316 jp->changed = 0;
4317
4318 if (jp->state == JOBDONE) {
4319 TRACE(("showjob: freeing job %d\n", jobno(jp)));
4320 freejob(jp);
4321 }
4322}
4323
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004324/*
4325 * Print a list of jobs. If "change" is nonzero, only print jobs whose
4326 * statuses have changed since the last call to showjobs.
4327 */
4328static void
Denys Vlasenko9c541002015-10-07 15:44:36 +02004329showjobs(int mode)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004330{
4331 struct job *jp;
4332
Denys Vlasenko883cea42009-07-11 15:31:59 +02004333 TRACE(("showjobs(0x%x) called\n", mode));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004334
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004335 /* Handle all finished jobs */
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004336 while (dowait(DOWAIT_NONBLOCK, NULL) > 0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004337 continue;
4338
4339 for (jp = curjob; jp; jp = jp->prev_job) {
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004340 if (!(mode & SHOW_CHANGED) || jp->changed) {
Denys Vlasenko9c541002015-10-07 15:44:36 +02004341 showjob(jp, mode);
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004342 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004343 }
4344}
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004345
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02004346static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00004347jobscmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004348{
4349 int mode, m;
4350
4351 mode = 0;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02004352 while ((m = nextopt("lp")) != '\0') {
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004353 if (m == 'l')
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004354 mode |= SHOW_PIDS;
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004355 else
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004356 mode |= SHOW_ONLY_PGID;
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004357 }
4358
4359 argv = argptr;
4360 if (*argv) {
4361 do
Denys Vlasenko9c541002015-10-07 15:44:36 +02004362 showjob(getjob(*argv, 0), mode);
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004363 while (*++argv);
Denys Vlasenko285ad152009-12-04 23:02:27 +01004364 } else {
Denys Vlasenko9c541002015-10-07 15:44:36 +02004365 showjobs(mode);
Denys Vlasenko285ad152009-12-04 23:02:27 +01004366 }
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004367
4368 return 0;
4369}
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004370#endif /* JOBS */
4371
Michael Abbott359da5e2009-12-04 23:03:29 +01004372/* Called only on finished or stopped jobs (no members are running) */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004373static int
4374getstatus(struct job *job)
4375{
4376 int status;
4377 int retval;
Michael Abbott359da5e2009-12-04 23:03:29 +01004378 struct procstat *ps;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004379
Michael Abbott359da5e2009-12-04 23:03:29 +01004380 /* Fetch last member's status */
4381 ps = job->ps + job->nprocs - 1;
4382 status = ps->ps_status;
4383 if (pipefail) {
4384 /* "set -o pipefail" mode: use last _nonzero_ status */
4385 while (status == 0 && --ps >= job->ps)
4386 status = ps->ps_status;
4387 }
4388
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004389 retval = WEXITSTATUS(status);
4390 if (!WIFEXITED(status)) {
4391#if JOBS
4392 retval = WSTOPSIG(status);
4393 if (!WIFSTOPPED(status))
4394#endif
4395 {
4396 /* XXX: limits number of signals */
4397 retval = WTERMSIG(status);
4398#if JOBS
4399 if (retval == SIGINT)
4400 job->sigint = 1;
4401#endif
4402 }
4403 retval += 128;
4404 }
Denys Vlasenko883cea42009-07-11 15:31:59 +02004405 TRACE(("getstatus: job %d, nproc %d, status 0x%x, retval 0x%x\n",
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004406 jobno(job), job->nprocs, status, retval));
4407 return retval;
4408}
4409
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02004410static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00004411waitcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004412{
4413 struct job *job;
4414 int retval;
4415 struct job *jp;
4416
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004417 nextopt(nullstr);
4418 retval = 0;
4419
4420 argv = argptr;
4421 if (!*argv) {
4422 /* wait for all jobs */
4423 for (;;) {
4424 jp = curjob;
4425 while (1) {
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004426 if (!jp) /* no running procs */
4427 goto ret;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004428 if (jp->state == JOBRUNNING)
4429 break;
4430 jp->waited = 1;
4431 jp = jp->prev_job;
4432 }
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004433 /* man bash:
4434 * "When bash is waiting for an asynchronous command via
4435 * the wait builtin, the reception of a signal for which a trap
4436 * has been set will cause the wait builtin to return immediately
4437 * with an exit status greater than 128, immediately after which
4438 * the trap is executed."
Denys Vlasenko69188112016-10-27 20:18:18 +02004439 */
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004440 dowait(DOWAIT_BLOCK_OR_SIG, NULL);
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02004441 /* if child sends us a signal *and immediately exits*,
4442 * dowait() returns pid > 0. Check this case,
4443 * not "if (dowait() < 0)"!
4444 */
Denys Vlasenko7c1ed9f2010-05-17 04:42:40 +02004445 if (pending_sig)
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02004446 goto sigout;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004447 }
4448 }
4449
4450 retval = 127;
4451 do {
4452 if (**argv != '%') {
4453 pid_t pid = number(*argv);
4454 job = curjob;
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004455 while (1) {
4456 if (!job)
4457 goto repeat;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004458 if (job->ps[job->nprocs - 1].ps_pid == pid)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004459 break;
4460 job = job->prev_job;
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004461 }
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004462 } else {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004463 job = getjob(*argv, 0);
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004464 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004465 /* loop until process terminated or stopped */
Denys Vlasenko69188112016-10-27 20:18:18 +02004466 while (job->state == JOBRUNNING) {
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004467 dowait(DOWAIT_BLOCK_OR_SIG, NULL);
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02004468 if (pending_sig)
4469 goto sigout;
Denys Vlasenko69188112016-10-27 20:18:18 +02004470 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004471 job->waited = 1;
4472 retval = getstatus(job);
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004473 repeat: ;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004474 } while (*++argv);
4475
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004476 ret:
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004477 return retval;
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02004478 sigout:
4479 retval = 128 + pending_sig;
4480 return retval;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004481}
4482
4483static struct job *
4484growjobtab(void)
4485{
4486 size_t len;
4487 ptrdiff_t offset;
4488 struct job *jp, *jq;
4489
4490 len = njobs * sizeof(*jp);
4491 jq = jobtab;
4492 jp = ckrealloc(jq, len + 4 * sizeof(*jp));
4493
4494 offset = (char *)jp - (char *)jq;
4495 if (offset) {
4496 /* Relocate pointers */
4497 size_t l = len;
4498
4499 jq = (struct job *)((char *)jq + l);
4500 while (l) {
4501 l -= sizeof(*jp);
4502 jq--;
4503#define joff(p) ((struct job *)((char *)(p) + l))
4504#define jmove(p) (p) = (void *)((char *)(p) + offset)
4505 if (joff(jp)->ps == &jq->ps0)
4506 jmove(joff(jp)->ps);
4507 if (joff(jp)->prev_job)
4508 jmove(joff(jp)->prev_job);
4509 }
4510 if (curjob)
4511 jmove(curjob);
4512#undef joff
4513#undef jmove
4514 }
4515
4516 njobs += 4;
4517 jobtab = jp;
4518 jp = (struct job *)((char *)jp + len);
4519 jq = jp + 3;
4520 do {
4521 jq->used = 0;
4522 } while (--jq >= jp);
4523 return jp;
4524}
4525
4526/*
4527 * Return a new job structure.
4528 * Called with interrupts off.
4529 */
4530static struct job *
Denis Vlasenko68404f12008-03-17 09:00:54 +00004531makejob(/*union node *node,*/ int nprocs)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004532{
4533 int i;
4534 struct job *jp;
4535
4536 for (i = njobs, jp = jobtab; ; jp++) {
4537 if (--i < 0) {
4538 jp = growjobtab();
4539 break;
4540 }
4541 if (jp->used == 0)
4542 break;
4543 if (jp->state != JOBDONE || !jp->waited)
4544 continue;
4545#if JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +00004546 if (doing_jobctl)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004547 continue;
4548#endif
4549 freejob(jp);
4550 break;
4551 }
4552 memset(jp, 0, sizeof(*jp));
4553#if JOBS
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004554 /* jp->jobctl is a bitfield.
Denys Vlasenko098b7132017-01-11 19:59:03 +01004555 * "jp->jobctl |= doing_jobctl" likely to give awful code */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00004556 if (doing_jobctl)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004557 jp->jobctl = 1;
4558#endif
4559 jp->prev_job = curjob;
4560 curjob = jp;
4561 jp->used = 1;
4562 jp->ps = &jp->ps0;
4563 if (nprocs > 1) {
4564 jp->ps = ckmalloc(nprocs * sizeof(struct procstat));
4565 }
Denis Vlasenko68404f12008-03-17 09:00:54 +00004566 TRACE(("makejob(%d) returns %%%d\n", nprocs,
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004567 jobno(jp)));
4568 return jp;
4569}
4570
4571#if JOBS
4572/*
4573 * Return a string identifying a command (to be printed by the
4574 * jobs command).
4575 */
4576static char *cmdnextc;
4577
4578static void
4579cmdputs(const char *s)
4580{
Denis Vlasenko92e13c22008-03-25 01:17:40 +00004581 static const char vstype[VSTYPE + 1][3] = {
4582 "", "}", "-", "+", "?", "=",
4583 "%", "%%", "#", "##"
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01004584 IF_BASH_SUBSTR(, ":")
4585 IF_BASH_PATTERN_SUBST(, "/", "//")
Denis Vlasenko92e13c22008-03-25 01:17:40 +00004586 };
4587
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004588 const char *p, *str;
Denys Vlasenko46a14772009-12-10 21:27:13 +01004589 char cc[2];
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004590 char *nextc;
Denys Vlasenkocd716832009-11-28 22:14:02 +01004591 unsigned char c;
4592 unsigned char subtype = 0;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004593 int quoted = 0;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004594
Denys Vlasenko46a14772009-12-10 21:27:13 +01004595 cc[1] = '\0';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004596 nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
4597 p = s;
Denys Vlasenko46a14772009-12-10 21:27:13 +01004598 while ((c = *p++) != '\0') {
Denis Vlasenkoef527f52008-06-23 01:52:30 +00004599 str = NULL;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004600 switch (c) {
4601 case CTLESC:
4602 c = *p++;
4603 break;
4604 case CTLVAR:
4605 subtype = *p++;
4606 if ((subtype & VSTYPE) == VSLENGTH)
4607 str = "${#";
4608 else
4609 str = "${";
Ron Yorston549deab2015-05-18 09:57:51 +02004610 goto dostr;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004611 case CTLENDVAR:
4612 str = "\"}" + !(quoted & 1);
4613 quoted >>= 1;
4614 subtype = 0;
4615 goto dostr;
4616 case CTLBACKQ:
4617 str = "$(...)";
4618 goto dostr;
Denys Vlasenko0b883582016-12-23 16:49:07 +01004619#if ENABLE_FEATURE_SH_MATH
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004620 case CTLARI:
4621 str = "$((";
4622 goto dostr;
4623 case CTLENDARI:
4624 str = "))";
4625 goto dostr;
4626#endif
4627 case CTLQUOTEMARK:
4628 quoted ^= 1;
4629 c = '"';
4630 break;
4631 case '=':
4632 if (subtype == 0)
4633 break;
4634 if ((subtype & VSTYPE) != VSNORMAL)
4635 quoted <<= 1;
4636 str = vstype[subtype & VSTYPE];
4637 if (subtype & VSNUL)
4638 c = ':';
4639 else
4640 goto checkstr;
4641 break;
4642 case '\'':
4643 case '\\':
4644 case '"':
4645 case '$':
4646 /* These can only happen inside quotes */
4647 cc[0] = c;
4648 str = cc;
Denys Vlasenkod0fff912017-07-31 14:32:18 +02004649//FIXME:
4650// $ true $$ &
4651// $ <cr>
4652// [1]+ Done true ${\$} <<=== BUG: ${\$} is not a valid way to write $$ (${$} would be ok)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004653 c = '\\';
4654 break;
4655 default:
4656 break;
4657 }
4658 USTPUTC(c, nextc);
4659 checkstr:
4660 if (!str)
4661 continue;
4662 dostr:
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02004663 while ((c = *str++) != '\0') {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004664 USTPUTC(c, nextc);
4665 }
Denys Vlasenko46a14772009-12-10 21:27:13 +01004666 } /* while *p++ not NUL */
4667
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004668 if (quoted & 1) {
4669 USTPUTC('"', nextc);
4670 }
4671 *nextc = 0;
4672 cmdnextc = nextc;
4673}
4674
4675/* cmdtxt() and cmdlist() call each other */
4676static void cmdtxt(union node *n);
4677
4678static void
4679cmdlist(union node *np, int sep)
4680{
4681 for (; np; np = np->narg.next) {
4682 if (!sep)
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00004683 cmdputs(" ");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004684 cmdtxt(np);
4685 if (sep && np->narg.next)
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00004686 cmdputs(" ");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004687 }
4688}
4689
4690static void
4691cmdtxt(union node *n)
4692{
4693 union node *np;
4694 struct nodelist *lp;
4695 const char *p;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004696
4697 if (!n)
4698 return;
4699 switch (n->type) {
4700 default:
4701#if DEBUG
4702 abort();
4703#endif
4704 case NPIPE:
4705 lp = n->npipe.cmdlist;
4706 for (;;) {
4707 cmdtxt(lp->n);
4708 lp = lp->next;
4709 if (!lp)
4710 break;
4711 cmdputs(" | ");
4712 }
4713 break;
4714 case NSEMI:
4715 p = "; ";
4716 goto binop;
4717 case NAND:
4718 p = " && ";
4719 goto binop;
4720 case NOR:
4721 p = " || ";
4722 binop:
4723 cmdtxt(n->nbinary.ch1);
4724 cmdputs(p);
4725 n = n->nbinary.ch2;
4726 goto donode;
4727 case NREDIR:
4728 case NBACKGND:
4729 n = n->nredir.n;
4730 goto donode;
4731 case NNOT:
4732 cmdputs("!");
4733 n = n->nnot.com;
4734 donode:
4735 cmdtxt(n);
4736 break;
4737 case NIF:
4738 cmdputs("if ");
4739 cmdtxt(n->nif.test);
4740 cmdputs("; then ");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004741 if (n->nif.elsepart) {
Denys Vlasenko7cee00e2009-07-24 01:08:03 +02004742 cmdtxt(n->nif.ifpart);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004743 cmdputs("; else ");
4744 n = n->nif.elsepart;
Denys Vlasenko7cee00e2009-07-24 01:08:03 +02004745 } else {
4746 n = n->nif.ifpart;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004747 }
4748 p = "; fi";
4749 goto dotail;
4750 case NSUBSHELL:
4751 cmdputs("(");
4752 n = n->nredir.n;
4753 p = ")";
4754 goto dotail;
4755 case NWHILE:
4756 p = "while ";
4757 goto until;
4758 case NUNTIL:
4759 p = "until ";
4760 until:
4761 cmdputs(p);
4762 cmdtxt(n->nbinary.ch1);
4763 n = n->nbinary.ch2;
4764 p = "; done";
4765 dodo:
4766 cmdputs("; do ");
4767 dotail:
4768 cmdtxt(n);
4769 goto dotail2;
4770 case NFOR:
4771 cmdputs("for ");
4772 cmdputs(n->nfor.var);
4773 cmdputs(" in ");
4774 cmdlist(n->nfor.args, 1);
4775 n = n->nfor.body;
4776 p = "; done";
4777 goto dodo;
4778 case NDEFUN:
4779 cmdputs(n->narg.text);
4780 p = "() { ... }";
4781 goto dotail2;
4782 case NCMD:
4783 cmdlist(n->ncmd.args, 1);
4784 cmdlist(n->ncmd.redirect, 0);
4785 break;
4786 case NARG:
4787 p = n->narg.text;
4788 dotail2:
4789 cmdputs(p);
4790 break;
4791 case NHERE:
4792 case NXHERE:
4793 p = "<<...";
4794 goto dotail2;
4795 case NCASE:
4796 cmdputs("case ");
4797 cmdputs(n->ncase.expr->narg.text);
4798 cmdputs(" in ");
4799 for (np = n->ncase.cases; np; np = np->nclist.next) {
4800 cmdtxt(np->nclist.pattern);
4801 cmdputs(") ");
4802 cmdtxt(np->nclist.body);
4803 cmdputs(";; ");
4804 }
4805 p = "esac";
4806 goto dotail2;
4807 case NTO:
4808 p = ">";
4809 goto redir;
4810 case NCLOBBER:
4811 p = ">|";
4812 goto redir;
4813 case NAPPEND:
4814 p = ">>";
4815 goto redir;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01004816#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00004817 case NTO2:
4818#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004819 case NTOFD:
4820 p = ">&";
4821 goto redir;
4822 case NFROM:
4823 p = "<";
4824 goto redir;
4825 case NFROMFD:
4826 p = "<&";
4827 goto redir;
4828 case NFROMTO:
4829 p = "<>";
4830 redir:
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00004831 cmdputs(utoa(n->nfile.fd));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004832 cmdputs(p);
4833 if (n->type == NTOFD || n->type == NFROMFD) {
Denys Vlasenkod0fff912017-07-31 14:32:18 +02004834 if (n->ndup.dupfd >= 0)
4835 cmdputs(utoa(n->ndup.dupfd));
4836 else
4837 cmdputs("-");
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00004838 break;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004839 }
4840 n = n->nfile.fname;
4841 goto donode;
4842 }
4843}
4844
4845static char *
4846commandtext(union node *n)
4847{
4848 char *name;
4849
4850 STARTSTACKSTR(cmdnextc);
4851 cmdtxt(n);
4852 name = stackblock();
Denys Vlasenko6a94cee2016-10-25 17:40:25 +02004853 TRACE(("commandtext: name %p, end %p\n", name, cmdnextc));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004854 return ckstrdup(name);
4855}
4856#endif /* JOBS */
4857
4858/*
4859 * Fork off a subshell. If we are doing job control, give the subshell its
4860 * own process group. Jp is a job structure that the job is to be added to.
4861 * N is the command that will be evaluated by the child. Both jp and n may
4862 * be NULL. The mode parameter can be one of the following:
4863 * FORK_FG - Fork off a foreground process.
4864 * FORK_BG - Fork off a background process.
4865 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
4866 * process group even if job control is on.
4867 *
4868 * When job control is turned off, background processes have their standard
4869 * input redirected to /dev/null (except for the second and later processes
4870 * in a pipeline).
4871 *
4872 * Called with interrupts off.
4873 */
4874/*
4875 * Clear traps on a fork.
4876 */
4877static void
4878clear_traps(void)
4879{
4880 char **tp;
4881
Denys Vlasenkob4f51d32016-10-27 12:55:09 +02004882 INT_OFF;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004883 for (tp = trap; tp < &trap[NSIG]; tp++) {
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004884 if (*tp && **tp) { /* trap not NULL or "" (SIG_IGN) */
Denys Vlasenkoe305c282009-09-25 02:12:27 +02004885 if (trap_ptr == trap)
4886 free(*tp);
4887 /* else: it "belongs" to trap_ptr vector, don't free */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004888 *tp = NULL;
Denys Vlasenko0800e3a2009-09-24 03:09:26 +02004889 if ((tp - trap) != 0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004890 setsignal(tp - trap);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004891 }
4892 }
Alexander Shishkinccb97712010-07-25 13:07:39 +02004893 may_have_traps = 0;
Denys Vlasenkob4f51d32016-10-27 12:55:09 +02004894 INT_ON;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004895}
Denis Vlasenkobdc406d2007-07-15 01:13:25 +00004896
4897/* Lives far away from here, needed for forkchild */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004898static void closescript(void);
Denis Vlasenko41770222007-10-07 18:02:52 +00004899
Denis Vlasenkobdc406d2007-07-15 01:13:25 +00004900/* Called after fork(), in child */
Denys Vlasenko70392332016-10-27 02:31:55 +02004901/* jp and n are NULL when called by openhere() for heredoc support */
Denys Vlasenko21d87d42009-09-25 00:06:51 +02004902static NOINLINE void
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02004903forkchild(struct job *jp, union node *n, int mode)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004904{
4905 int oldlvl;
4906
4907 TRACE(("Child shell %d\n", getpid()));
4908 oldlvl = shlvl;
4909 shlvl++;
4910
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004911 /* man bash: "Non-builtin commands run by bash have signal handlers
4912 * set to the values inherited by the shell from its parent".
4913 * Do we do it correctly? */
4914
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004915 closescript();
Denys Vlasenko844f9902009-09-23 03:25:52 +02004916
4917 if (mode == FORK_NOJOB /* is it `xxx` ? */
4918 && n && n->type == NCMD /* is it single cmd? */
4919 /* && n->ncmd.args->type == NARG - always true? */
Denys Vlasenko74269202010-02-21 01:26:42 +01004920 && n->ncmd.args && strcmp(n->ncmd.args->narg.text, "trap") == 0
Denys Vlasenko844f9902009-09-23 03:25:52 +02004921 && n->ncmd.args->narg.next == NULL /* "trap" with no arguments */
4922 /* && n->ncmd.args->narg.backquote == NULL - do we need to check this? */
4923 ) {
4924 TRACE(("Trap hack\n"));
4925 /* Awful hack for `trap` or $(trap).
4926 *
4927 * http://www.opengroup.org/onlinepubs/009695399/utilities/trap.html
4928 * contains an example where "trap" is executed in a subshell:
4929 *
4930 * save_traps=$(trap)
4931 * ...
4932 * eval "$save_traps"
4933 *
4934 * Standard does not say that "trap" in subshell shall print
4935 * parent shell's traps. It only says that its output
4936 * must have suitable form, but then, in the above example
4937 * (which is not supposed to be normative), it implies that.
4938 *
4939 * bash (and probably other shell) does implement it
4940 * (traps are reset to defaults, but "trap" still shows them),
4941 * but as a result, "trap" logic is hopelessly messed up:
4942 *
4943 * # trap
4944 * trap -- 'echo Ho' SIGWINCH <--- we have a handler
4945 * # (trap) <--- trap is in subshell - no output (correct, traps are reset)
4946 * # true | trap <--- trap is in subshell - no output (ditto)
4947 * # echo `true | trap` <--- in subshell - output (but traps are reset!)
4948 * trap -- 'echo Ho' SIGWINCH
4949 * # echo `(trap)` <--- in subshell in subshell - output
4950 * trap -- 'echo Ho' SIGWINCH
4951 * # echo `true | (trap)` <--- in subshell in subshell in subshell - output!
4952 * trap -- 'echo Ho' SIGWINCH
4953 *
4954 * The rules when to forget and when to not forget traps
4955 * get really complex and nonsensical.
4956 *
4957 * Our solution: ONLY bare $(trap) or `trap` is special.
4958 */
Denys Vlasenko8f88d852009-09-25 12:12:53 +02004959 /* Save trap handler strings for trap builtin to print */
Ron Yorstond840c5d2015-07-19 23:05:20 +02004960 trap_ptr = xmemdup(trap, sizeof(trap));
Denys Vlasenko8f88d852009-09-25 12:12:53 +02004961 /* Fall through into clearing traps */
Denys Vlasenko844f9902009-09-23 03:25:52 +02004962 }
Denys Vlasenkoe305c282009-09-25 02:12:27 +02004963 clear_traps();
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004964#if JOBS
4965 /* do job control only in root shell */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00004966 doing_jobctl = 0;
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004967 if (mode != FORK_NOJOB && jp->jobctl && oldlvl == 0) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004968 pid_t pgrp;
4969
4970 if (jp->nprocs == 0)
4971 pgrp = getpid();
4972 else
Denys Vlasenko285ad152009-12-04 23:02:27 +01004973 pgrp = jp->ps[0].ps_pid;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004974 /* this can fail because we are doing it in the parent also */
4975 setpgid(0, pgrp);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004976 if (mode == FORK_FG)
4977 xtcsetpgrp(ttyfd, pgrp);
4978 setsignal(SIGTSTP);
4979 setsignal(SIGTTOU);
4980 } else
4981#endif
4982 if (mode == FORK_BG) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004983 /* man bash: "When job control is not in effect,
4984 * asynchronous commands ignore SIGINT and SIGQUIT" */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004985 ignoresig(SIGINT);
4986 ignoresig(SIGQUIT);
4987 if (jp->nprocs == 0) {
4988 close(0);
4989 if (open(bb_dev_null, O_RDONLY) != 0)
Denys Vlasenko12ffefb2017-08-23 14:52:56 +02004990 ash_msg_and_raise_perror("can't open '%s'", bb_dev_null);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004991 }
4992 }
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004993 if (oldlvl == 0) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004994 if (iflag) { /* why if iflag only? */
4995 setsignal(SIGINT);
4996 setsignal(SIGTERM);
4997 }
4998 /* man bash:
4999 * "In all cases, bash ignores SIGQUIT. Non-builtin
5000 * commands run by bash have signal handlers
5001 * set to the values inherited by the shell
5002 * from its parent".
5003 * Take care of the second rule: */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005004 setsignal(SIGQUIT);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005005 }
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02005006#if JOBS
Denys Vlasenko844f9902009-09-23 03:25:52 +02005007 if (n && n->type == NCMD
Denys Vlasenko74269202010-02-21 01:26:42 +01005008 && n->ncmd.args && strcmp(n->ncmd.args->narg.text, "jobs") == 0
Denys Vlasenko844f9902009-09-23 03:25:52 +02005009 ) {
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02005010 TRACE(("Job hack\n"));
Denys Vlasenko844f9902009-09-23 03:25:52 +02005011 /* "jobs": we do not want to clear job list for it,
5012 * instead we remove only _its_ own_ job from job list.
5013 * This makes "jobs .... | cat" more useful.
5014 */
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02005015 freejob(curjob);
5016 return;
5017 }
5018#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005019 for (jp = curjob; jp; jp = jp->prev_job)
5020 freejob(jp);
5021 jobless = 0;
5022}
5023
Denis Vlasenkobdc406d2007-07-15 01:13:25 +00005024/* Called after fork(), in parent */
Denis Vlasenko85c24712008-03-17 09:04:04 +00005025#if !JOBS
5026#define forkparent(jp, n, mode, pid) forkparent(jp, mode, pid)
5027#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005028static void
5029forkparent(struct job *jp, union node *n, int mode, pid_t pid)
5030{
5031 TRACE(("In parent shell: child = %d\n", pid));
5032 if (!jp) {
Denys Vlasenko70392332016-10-27 02:31:55 +02005033 /* jp is NULL when called by openhere() for heredoc support */
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00005034 while (jobless && dowait(DOWAIT_NONBLOCK, NULL) > 0)
5035 continue;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005036 jobless++;
5037 return;
5038 }
5039#if JOBS
5040 if (mode != FORK_NOJOB && jp->jobctl) {
5041 int pgrp;
5042
5043 if (jp->nprocs == 0)
5044 pgrp = pid;
5045 else
Denys Vlasenko285ad152009-12-04 23:02:27 +01005046 pgrp = jp->ps[0].ps_pid;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005047 /* This can fail because we are doing it in the child also */
5048 setpgid(pid, pgrp);
5049 }
5050#endif
5051 if (mode == FORK_BG) {
5052 backgndpid = pid; /* set $! */
5053 set_curjob(jp, CUR_RUNNING);
5054 }
5055 if (jp) {
5056 struct procstat *ps = &jp->ps[jp->nprocs++];
Denys Vlasenko285ad152009-12-04 23:02:27 +01005057 ps->ps_pid = pid;
5058 ps->ps_status = -1;
5059 ps->ps_cmd = nullstr;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005060#if JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +00005061 if (doing_jobctl && n)
Denys Vlasenko285ad152009-12-04 23:02:27 +01005062 ps->ps_cmd = commandtext(n);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005063#endif
5064 }
5065}
5066
Denys Vlasenko70392332016-10-27 02:31:55 +02005067/* jp and n are NULL when called by openhere() for heredoc support */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005068static int
5069forkshell(struct job *jp, union node *n, int mode)
5070{
5071 int pid;
5072
5073 TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
5074 pid = fork();
5075 if (pid < 0) {
5076 TRACE(("Fork failed, errno=%d", errno));
5077 if (jp)
5078 freejob(jp);
Denys Vlasenko12ffefb2017-08-23 14:52:56 +02005079 ash_msg_and_raise_perror("can't fork");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005080 }
Denys Vlasenko76ace252009-10-12 15:25:01 +02005081 if (pid == 0) {
5082 CLEAR_RANDOM_T(&random_gen); /* or else $RANDOM repeats in child */
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02005083 forkchild(jp, n, mode);
Denys Vlasenko76ace252009-10-12 15:25:01 +02005084 } else {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005085 forkparent(jp, n, mode, pid);
Denys Vlasenko76ace252009-10-12 15:25:01 +02005086 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005087 return pid;
5088}
5089
5090/*
5091 * Wait for job to finish.
5092 *
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005093 * Under job control we have the problem that while a child process
5094 * is running interrupts generated by the user are sent to the child
5095 * but not to the shell. This means that an infinite loop started by
5096 * an interactive user may be hard to kill. With job control turned off,
5097 * an interactive user may place an interactive program inside a loop.
5098 * If the interactive program catches interrupts, the user doesn't want
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005099 * these interrupts to also abort the loop. The approach we take here
5100 * is to have the shell ignore interrupt signals while waiting for a
5101 * foreground process to terminate, and then send itself an interrupt
5102 * signal if the child process was terminated by an interrupt signal.
5103 * Unfortunately, some programs want to do a bit of cleanup and then
5104 * exit on interrupt; unless these processes terminate themselves by
5105 * sending a signal to themselves (instead of calling exit) they will
5106 * confuse this approach.
5107 *
5108 * Called with interrupts off.
5109 */
5110static int
5111waitforjob(struct job *jp)
5112{
5113 int st;
5114
5115 TRACE(("waitforjob(%%%d) called\n", jobno(jp)));
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005116
5117 INT_OFF;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005118 while (jp->state == JOBRUNNING) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005119 /* In non-interactive shells, we _can_ get
5120 * a keyboard signal here and be EINTRed,
5121 * but we just loop back, waiting for command to complete.
5122 *
5123 * man bash:
5124 * "If bash is waiting for a command to complete and receives
5125 * a signal for which a trap has been set, the trap
5126 * will not be executed until the command completes."
5127 *
5128 * Reality is that even if trap is not set, bash
5129 * will not act on the signal until command completes.
5130 * Try this. sleep5intoff.c:
5131 * #include <signal.h>
5132 * #include <unistd.h>
5133 * int main() {
5134 * sigset_t set;
5135 * sigemptyset(&set);
5136 * sigaddset(&set, SIGINT);
5137 * sigaddset(&set, SIGQUIT);
5138 * sigprocmask(SIG_BLOCK, &set, NULL);
5139 * sleep(5);
5140 * return 0;
5141 * }
5142 * $ bash -c './sleep5intoff; echo hi'
5143 * ^C^C^C^C <--- pressing ^C once a second
5144 * $ _
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005145 * $ bash -c './sleep5intoff; echo hi'
5146 * ^\^\^\^\hi <--- pressing ^\ (SIGQUIT)
5147 * $ _
5148 */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005149 dowait(DOWAIT_BLOCK, jp);
5150 }
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005151 INT_ON;
5152
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005153 st = getstatus(jp);
5154#if JOBS
5155 if (jp->jobctl) {
5156 xtcsetpgrp(ttyfd, rootpid);
Denys Vlasenko098b7132017-01-11 19:59:03 +01005157 restore_tty_if_stopped_or_signaled(jp);
5158
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005159 /*
5160 * This is truly gross.
5161 * If we're doing job control, then we did a TIOCSPGRP which
5162 * caused us (the shell) to no longer be in the controlling
5163 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
5164 * intuit from the subprocess exit status whether a SIGINT
5165 * occurred, and if so interrupt ourselves. Yuck. - mycroft
5166 */
Denis Vlasenko991a1da2008-02-10 19:02:53 +00005167 if (jp->sigint) /* TODO: do the same with all signals */
5168 raise(SIGINT); /* ... by raise(jp->sig) instead? */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005169 }
5170 if (jp->state == JOBDONE)
5171#endif
5172 freejob(jp);
5173 return st;
5174}
5175
5176/*
5177 * return 1 if there are stopped jobs, otherwise 0
5178 */
5179static int
5180stoppedjobs(void)
5181{
5182 struct job *jp;
5183 int retval;
5184
5185 retval = 0;
5186 if (job_warning)
5187 goto out;
5188 jp = curjob;
5189 if (jp && jp->state == JOBSTOPPED) {
5190 out2str("You have stopped jobs.\n");
5191 job_warning = 2;
5192 retval++;
5193 }
5194 out:
5195 return retval;
5196}
5197
5198
Denys Vlasenko70392332016-10-27 02:31:55 +02005199/*
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005200 * Code for dealing with input/output redirection.
5201 */
5202
Denys Vlasenko8d0e0cd2011-01-25 23:21:46 +01005203#undef EMPTY
5204#undef CLOSED
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005205#define EMPTY -2 /* marks an unused slot in redirtab */
Denys Vlasenko035486c2017-07-31 04:09:19 +02005206#define CLOSED -1 /* marks a slot of previously-closed fd */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005207
5208/*
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005209 * Handle here documents. Normally we fork off a process to write the
5210 * data to a pipe. If the document is short, we can stuff the data in
5211 * the pipe without forking.
5212 */
5213/* openhere needs this forward reference */
5214static void expandhere(union node *arg, int fd);
5215static int
5216openhere(union node *redir)
5217{
5218 int pip[2];
5219 size_t len = 0;
5220
5221 if (pipe(pip) < 0)
Denys Vlasenko12ffefb2017-08-23 14:52:56 +02005222 ash_msg_and_raise_perror("can't create pipe");
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005223 if (redir->type == NHERE) {
5224 len = strlen(redir->nhere.doc->narg.text);
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005225 if (len <= PIPE_BUF) {
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005226 full_write(pip[1], redir->nhere.doc->narg.text, len);
5227 goto out;
5228 }
5229 }
5230 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
Denis Vlasenko0b769642008-07-24 07:54:57 +00005231 /* child */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005232 close(pip[0]);
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005233 ignoresig(SIGINT); //signal(SIGINT, SIG_IGN);
5234 ignoresig(SIGQUIT); //signal(SIGQUIT, SIG_IGN);
5235 ignoresig(SIGHUP); //signal(SIGHUP, SIG_IGN);
5236 ignoresig(SIGTSTP); //signal(SIGTSTP, SIG_IGN);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005237 signal(SIGPIPE, SIG_DFL);
5238 if (redir->type == NHERE)
5239 full_write(pip[1], redir->nhere.doc->narg.text, len);
Denis Vlasenko0b769642008-07-24 07:54:57 +00005240 else /* NXHERE */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005241 expandhere(redir->nhere.doc, pip[1]);
Bernhard Reutner-Fischer636a1f82008-05-19 09:29:47 +00005242 _exit(EXIT_SUCCESS);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005243 }
5244 out:
5245 close(pip[1]);
5246 return pip[0];
5247}
5248
5249static int
5250openredirect(union node *redir)
5251{
Denys Vlasenkof1a5cb02017-07-25 17:47:48 +02005252 struct stat sb;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005253 char *fname;
5254 int f;
5255
5256 switch (redir->nfile.type) {
Denys Vlasenko557482c2016-09-25 21:24:04 +02005257/* Can't happen, our single caller does this itself */
5258// case NTOFD:
5259// case NFROMFD:
5260// return -1;
5261 case NHERE:
5262 case NXHERE:
5263 return openhere(redir);
5264 }
5265
5266 /* For N[X]HERE, reading redir->nfile.expfname would touch beyond
5267 * allocated space. Do it only when we know it is safe.
5268 */
5269 fname = redir->nfile.expfname;
5270
5271 switch (redir->nfile.type) {
5272 default:
5273#if DEBUG
5274 abort();
5275#endif
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005276 case NFROM:
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005277 f = open(fname, O_RDONLY);
5278 if (f < 0)
5279 goto eopen;
5280 break;
5281 case NFROMTO:
Andreas Bühmannda75f442010-06-24 04:32:37 +02005282 f = open(fname, O_RDWR|O_CREAT, 0666);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005283 if (f < 0)
5284 goto ecreate;
5285 break;
5286 case NTO:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01005287#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00005288 case NTO2:
5289#endif
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005290 /* Take care of noclobber mode. */
5291 if (Cflag) {
Denys Vlasenkof1a5cb02017-07-25 17:47:48 +02005292 if (stat(fname, &sb) < 0) {
5293 f = open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
5294 if (f < 0)
5295 goto ecreate;
5296 } else if (!S_ISREG(sb.st_mode)) {
5297 f = open(fname, O_WRONLY, 0666);
5298 if (f < 0)
5299 goto ecreate;
5300 if (fstat(f, &sb) < 0 && S_ISREG(sb.st_mode)) {
5301 close(f);
5302 errno = EEXIST;
5303 goto ecreate;
5304 }
5305 } else {
5306 errno = EEXIST;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005307 goto ecreate;
Denys Vlasenkof1a5cb02017-07-25 17:47:48 +02005308 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005309 break;
5310 }
5311 /* FALLTHROUGH */
5312 case NCLOBBER:
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005313 f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666);
5314 if (f < 0)
5315 goto ecreate;
5316 break;
5317 case NAPPEND:
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005318 f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666);
5319 if (f < 0)
5320 goto ecreate;
5321 break;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005322 }
5323
5324 return f;
5325 ecreate:
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +00005326 ash_msg_and_raise_error("can't create %s: %s", fname, errmsg(errno, "nonexistent directory"));
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005327 eopen:
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +00005328 ash_msg_and_raise_error("can't open %s: %s", fname, errmsg(errno, "no such file"));
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005329}
5330
5331/*
Denys Vlasenko64774602016-10-26 15:24:30 +02005332 * Copy a file descriptor to be >= 10. Throws exception on error.
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005333 */
5334static int
Denys Vlasenko64774602016-10-26 15:24:30 +02005335savefd(int from)
5336{
5337 int newfd;
5338 int err;
5339
5340 newfd = fcntl(from, F_DUPFD, 10);
5341 err = newfd < 0 ? errno : 0;
5342 if (err != EBADF) {
5343 if (err)
Ron Yorstonbe366e52017-07-27 13:53:39 +01005344 ash_msg_and_raise_perror("%d", from);
Denys Vlasenko64774602016-10-26 15:24:30 +02005345 close(from);
5346 fcntl(newfd, F_SETFD, FD_CLOEXEC);
5347 }
5348
5349 return newfd;
5350}
5351static int
5352dup2_or_raise(int from, int to)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005353{
5354 int newfd;
5355
Denys Vlasenko64774602016-10-26 15:24:30 +02005356 newfd = (from != to) ? dup2(from, to) : to;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005357 if (newfd < 0) {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005358 /* Happens when source fd is not open: try "echo >&99" */
Ron Yorstonbe366e52017-07-27 13:53:39 +01005359 ash_msg_and_raise_perror("%d", from);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005360 }
5361 return newfd;
5362}
Denys Vlasenko035486c2017-07-31 04:09:19 +02005363static int
5364fcntl_F_DUPFD(int fd, int avoid_fd)
5365{
5366 int newfd;
5367 repeat:
5368 newfd = fcntl(fd, F_DUPFD, avoid_fd + 1);
5369 if (newfd < 0) {
5370 if (errno == EBUSY)
5371 goto repeat;
5372 if (errno == EINTR)
5373 goto repeat;
5374 }
5375 return newfd;
5376}
5377static int
5378xdup_CLOEXEC_and_close(int fd, int avoid_fd)
5379{
5380 int newfd;
5381 repeat:
5382 newfd = fcntl(fd, F_DUPFD, avoid_fd + 1);
5383 if (newfd < 0) {
5384 if (errno == EBUSY)
5385 goto repeat;
5386 if (errno == EINTR)
5387 goto repeat;
5388 /* fd was not open? */
5389 if (errno == EBADF)
5390 return fd;
5391 ash_msg_and_raise_perror("%d", newfd);
5392 }
5393 fcntl(newfd, F_SETFD, FD_CLOEXEC);
5394 close(fd);
5395 return newfd;
5396}
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005397
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005398/* Struct def and variable are moved down to the first usage site */
Denys Vlasenko035486c2017-07-31 04:09:19 +02005399struct squirrel {
5400 int orig_fd;
5401 int moved_to;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005402};
Denis Vlasenko0b769642008-07-24 07:54:57 +00005403struct redirtab {
5404 struct redirtab *next;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005405 int pair_count;
Denys Vlasenko035486c2017-07-31 04:09:19 +02005406 struct squirrel two_fd[];
Denis Vlasenko0b769642008-07-24 07:54:57 +00005407};
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005408#define redirlist (G_var.redirlist)
Denis Vlasenko0b769642008-07-24 07:54:57 +00005409
Denys Vlasenko035486c2017-07-31 04:09:19 +02005410static void
5411add_squirrel_closed(struct redirtab *sq, int fd)
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005412{
5413 int i;
5414
Denys Vlasenko035486c2017-07-31 04:09:19 +02005415 if (!sq)
5416 return;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005417
Denys Vlasenko035486c2017-07-31 04:09:19 +02005418 for (i = 0; sq->two_fd[i].orig_fd != EMPTY; i++) {
5419 /* If we collide with an already moved fd... */
5420 if (fd == sq->two_fd[i].orig_fd) {
5421 /* Examples:
5422 * "echo 3>FILE 3>&- 3>FILE"
5423 * "echo 3>&- 3>FILE"
5424 * No need for last redirect to insert
5425 * another "need to close 3" indicator.
5426 */
5427 TRACE(("redirect_fd %d: already moved or closed\n", fd));
5428 return;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005429 }
5430 }
Denys Vlasenko035486c2017-07-31 04:09:19 +02005431 TRACE(("redirect_fd %d: previous fd was closed\n", fd));
5432 sq->two_fd[i].orig_fd = fd;
5433 sq->two_fd[i].moved_to = CLOSED;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005434}
5435
Denys Vlasenko37dc08b2016-10-02 04:38:07 +02005436static int
Denys Vlasenko035486c2017-07-31 04:09:19 +02005437save_fd_on_redirect(int fd, int avoid_fd, struct redirtab *sq)
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005438{
Denys Vlasenko035486c2017-07-31 04:09:19 +02005439 int i, new_fd;
Denis Vlasenko34c73c42008-08-16 11:48:02 +00005440
Denys Vlasenko035486c2017-07-31 04:09:19 +02005441 if (avoid_fd < 9) /* the important case here is that it can be -1 */
5442 avoid_fd = 9;
5443
5444#if JOBS
5445 if (fd == ttyfd) {
5446 /* Testcase: "ls -l /proc/$$/fd 10>&-" should work */
5447 ttyfd = xdup_CLOEXEC_and_close(ttyfd, avoid_fd);
5448 TRACE(("redirect_fd %d: matches ttyfd, moving it to %d\n", fd, ttyfd));
5449 return 1; /* "we closed fd" */
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005450 }
Denys Vlasenko035486c2017-07-31 04:09:19 +02005451#endif
5452 /* Are we called from redirect(0)? E.g. redirect
5453 * in a forked child. No need to save fds,
5454 * we aren't going to use them anymore, ok to trash.
5455 */
5456 if (!sq)
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005457 return 0;
Denys Vlasenko035486c2017-07-31 04:09:19 +02005458
5459 /* If this one of script's fds? */
5460 if (fd != 0) {
5461 struct parsefile *pf = g_parsefile;
5462 while (pf) {
5463 /* We skip fd == 0 case because of the following:
5464 * $ ash # running ash interactively
5465 * $ . ./script.sh
5466 * and in script.sh: "exec 9>&0".
5467 * Even though top-level pf_fd _is_ 0,
5468 * it's still ok to use it: "read" builtin uses it,
5469 * why should we cripple "exec" builtin?
5470 */
5471 if (fd == pf->pf_fd) {
5472 pf->pf_fd = xdup_CLOEXEC_and_close(fd, avoid_fd);
5473 return 1; /* "we closed fd" */
5474 }
5475 pf = pf->prev;
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005476 }
5477 }
Denys Vlasenko035486c2017-07-31 04:09:19 +02005478
5479 /* Check whether it collides with any open fds (e.g. stdio), save fds as needed */
5480
5481 /* First: do we collide with some already moved fds? */
5482 for (i = 0; sq->two_fd[i].orig_fd != EMPTY; i++) {
5483 /* If we collide with an already moved fd... */
5484 if (fd == sq->two_fd[i].moved_to) {
5485 new_fd = fcntl_F_DUPFD(fd, avoid_fd);
5486 sq->two_fd[i].moved_to = new_fd;
5487 TRACE(("redirect_fd %d: already busy, moving to %d\n", fd, new_fd));
5488 if (new_fd < 0) /* what? */
5489 xfunc_die();
5490 return 0; /* "we did not close fd" */
5491 }
5492 if (fd == sq->two_fd[i].orig_fd) {
5493 /* Example: echo Hello >/dev/null 1>&2 */
5494 TRACE(("redirect_fd %d: already moved\n", fd));
5495 return 0; /* "we did not close fd" */
5496 }
5497 }
5498
5499 /* If this fd is open, we move and remember it; if it's closed, new_fd = CLOSED (-1) */
5500 new_fd = fcntl_F_DUPFD(fd, avoid_fd);
5501 TRACE(("redirect_fd %d: previous fd is moved to %d (-1 if it was closed)\n", fd, new_fd));
5502 if (new_fd < 0) {
5503 if (errno != EBADF)
5504 xfunc_die();
5505 /* new_fd = CLOSED; - already is -1 */
5506 }
5507 sq->two_fd[i].moved_to = new_fd;
5508 sq->two_fd[i].orig_fd = fd;
5509
5510 /* if we move stderr, let "set -x" code know */
5511 if (fd == preverrout_fd)
5512 preverrout_fd = new_fd;
5513
5514 return 0; /* "we did not close fd" */
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005515}
5516
Denys Vlasenko32fdf2f2017-07-31 04:32:06 +02005517static int
5518internally_opened_fd(int fd, struct redirtab *sq)
5519{
5520 int i;
5521#if JOBS
5522 if (fd == ttyfd)
5523 return 1;
5524#endif
5525 /* If this one of script's fds? */
5526 if (fd != 0) {
5527 struct parsefile *pf = g_parsefile;
5528 while (pf) {
5529 if (fd == pf->pf_fd)
5530 return 1;
5531 pf = pf->prev;
5532 }
5533 }
5534
5535 if (sq) for (i = 0; i < sq->pair_count && sq->two_fd[i].orig_fd != EMPTY; i++) {
5536 if (fd == sq->two_fd[i].moved_to)
5537 return 1;
5538 }
5539 return 0;
5540}
5541
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005542/*
5543 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
5544 * old file descriptors are stashed away so that the redirection can be
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005545 * undone by calling popredir.
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005546 */
5547/* flags passed to redirect */
5548#define REDIR_PUSH 01 /* save previous values of file descriptors */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005549static void
5550redirect(union node *redir, int flags)
5551{
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005552 struct redirtab *sv;
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005553
Denys Vlasenko1c79aeb2017-07-29 22:51:52 +02005554 if (!redir)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005555 return;
Denys Vlasenko035486c2017-07-31 04:09:19 +02005556
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005557 sv = NULL;
5558 INT_OFF;
Denys Vlasenko1c79aeb2017-07-29 22:51:52 +02005559 if (flags & REDIR_PUSH)
5560 sv = redirlist;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005561 do {
Denys Vlasenko035486c2017-07-31 04:09:19 +02005562 int fd;
5563 int newfd;
5564 int close_fd;
5565 int closed;
5566
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00005567 fd = redir->nfile.fd;
Denis Vlasenko0b769642008-07-24 07:54:57 +00005568 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
Denys Vlasenko035486c2017-07-31 04:09:19 +02005569 //bb_error_msg("doing %d > %d", fd, newfd);
5570 newfd = redir->ndup.dupfd;
5571 close_fd = -1;
Denis Vlasenko0b769642008-07-24 07:54:57 +00005572 } else {
5573 newfd = openredirect(redir); /* always >= 0 */
5574 if (fd == newfd) {
Denys Vlasenko035486c2017-07-31 04:09:19 +02005575 /* open() gave us precisely the fd we wanted.
5576 * This means that this fd was not busy
5577 * (not opened to anywhere).
5578 * Remember to close it on restore:
5579 */
5580 add_squirrel_closed(sv, fd);
Denis Vlasenko0b769642008-07-24 07:54:57 +00005581 continue;
5582 }
Denys Vlasenko035486c2017-07-31 04:09:19 +02005583 close_fd = newfd;
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005584 }
Denys Vlasenko035486c2017-07-31 04:09:19 +02005585
5586 if (fd == newfd)
5587 continue;
5588
5589 /* if "N>FILE": move newfd to fd */
5590 /* if "N>&M": dup newfd to fd */
5591 /* if "N>&-": close fd (newfd is -1) */
5592
5593 IF_BASH_REDIR_OUTPUT(redirect_more:)
5594
5595 closed = save_fd_on_redirect(fd, /*avoid:*/ newfd, sv);
5596 if (newfd == -1) {
5597 /* "N>&-" means "close me" */
5598 if (!closed) {
5599 /* ^^^ optimization: saving may already
5600 * have closed it. If not... */
5601 close(fd);
Denis Vlasenko22f74142008-07-24 22:34:43 +00005602 }
Denys Vlasenko035486c2017-07-31 04:09:19 +02005603 } else {
Denys Vlasenko32fdf2f2017-07-31 04:32:06 +02005604 /* if newfd is a script fd or saved fd, simulate EBADF */
5605 if (internally_opened_fd(newfd, sv)) {
5606 errno = EBADF;
5607 ash_msg_and_raise_perror("%d", newfd);
5608 }
Denys Vlasenko64774602016-10-26 15:24:30 +02005609 dup2_or_raise(newfd, fd);
Denys Vlasenko035486c2017-07-31 04:09:19 +02005610 if (close_fd >= 0) /* "N>FILE" or ">&FILE" or heredoc? */
5611 close(close_fd);
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01005612#if BASH_REDIR_OUTPUT
Denys Vlasenko035486c2017-07-31 04:09:19 +02005613 if (redir->nfile.type == NTO2 && fd == 1) {
5614 /* ">&FILE". we already redirected to 1, now copy 1 to 2 */
5615 fd = 2;
5616 newfd = 1;
5617 close_fd = -1;
5618 goto redirect_more;
5619 }
Denis Vlasenko559691a2008-10-05 18:39:31 +00005620#endif
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005621 }
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00005622 } while ((redir = redir->nfile.next) != NULL);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005623 INT_ON;
Denys Vlasenkod07a15b2017-07-30 16:51:05 +02005624
5625//dash:#define REDIR_SAVEFD2 03 /* set preverrout */
5626#define REDIR_SAVEFD2 0
5627 // dash has a bug: since REDIR_SAVEFD2=3 and REDIR_PUSH=1, this test
5628 // triggers for pure REDIR_PUSH too. Thus, this is done almost always,
5629 // not only for calls with flags containing REDIR_SAVEFD2.
Denys Vlasenko035486c2017-07-31 04:09:19 +02005630 // We do this unconditionally (see save_fd_on_redirect()).
Denys Vlasenkod07a15b2017-07-30 16:51:05 +02005631 //if ((flags & REDIR_SAVEFD2) && copied_fd2 >= 0)
5632 // preverrout_fd = copied_fd2;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005633}
5634
Denys Vlasenko170f93e2017-07-29 18:54:53 +02005635static int
5636redirectsafe(union node *redir, int flags)
5637{
5638 int err;
5639 volatile int saveint;
5640 struct jmploc *volatile savehandler = exception_handler;
5641 struct jmploc jmploc;
5642
5643 SAVE_INT(saveint);
5644 /* "echo 9>/dev/null; echo >&9; echo result: $?" - result should be 1, not 2! */
Denys Vlasenko035486c2017-07-31 04:09:19 +02005645 err = setjmp(jmploc.loc); /* was = setjmp(jmploc.loc) * 2; */
Denys Vlasenko170f93e2017-07-29 18:54:53 +02005646 if (!err) {
5647 exception_handler = &jmploc;
5648 redirect(redir, flags);
5649 }
5650 exception_handler = savehandler;
5651 if (err && exception_type != EXERROR)
5652 longjmp(exception_handler->loc, 1);
5653 RESTORE_INT(saveint);
5654 return err;
5655}
5656
Denys Vlasenko1c79aeb2017-07-29 22:51:52 +02005657static struct redirtab*
5658pushredir(union node *redir)
5659{
5660 struct redirtab *sv;
5661 int i;
5662
5663 if (!redir)
5664 return redirlist;
5665
5666 i = 0;
5667 do {
5668 i++;
5669#if BASH_REDIR_OUTPUT
5670 if (redir->nfile.type == NTO2)
5671 i++;
5672#endif
5673 redir = redir->nfile.next;
5674 } while (redir);
5675
5676 sv = ckzalloc(sizeof(*sv) + i * sizeof(sv->two_fd[0]));
5677 sv->pair_count = i;
5678 while (--i >= 0)
Denys Vlasenko035486c2017-07-31 04:09:19 +02005679 sv->two_fd[i].orig_fd = sv->two_fd[i].moved_to = EMPTY;
Denys Vlasenko1c79aeb2017-07-29 22:51:52 +02005680 sv->next = redirlist;
5681 redirlist = sv;
5682 return sv->next;
5683}
5684
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005685/*
5686 * Undo the effects of the last redirection.
5687 */
5688static void
Denys Vlasenko035486c2017-07-31 04:09:19 +02005689popredir(int drop)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005690{
5691 struct redirtab *rp;
5692 int i;
5693
Denys Vlasenkoeaf94362016-10-25 21:46:03 +02005694 if (redirlist == NULL)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005695 return;
5696 INT_OFF;
5697 rp = redirlist;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005698 for (i = 0; i < rp->pair_count; i++) {
Denys Vlasenko035486c2017-07-31 04:09:19 +02005699 int fd = rp->two_fd[i].orig_fd;
5700 int copy = rp->two_fd[i].moved_to;
Denis Vlasenko22f74142008-07-24 22:34:43 +00005701 if (copy == CLOSED) {
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005702 if (!drop)
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005703 close(fd);
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005704 continue;
5705 }
Denis Vlasenko22f74142008-07-24 22:34:43 +00005706 if (copy != EMPTY) {
Denys Vlasenko035486c2017-07-31 04:09:19 +02005707 if (!drop) {
Denis Vlasenko5a867312008-07-24 19:46:38 +00005708 /*close(fd);*/
Denys Vlasenko64774602016-10-26 15:24:30 +02005709 dup2_or_raise(copy, fd);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005710 }
Denys Vlasenko035486c2017-07-31 04:09:19 +02005711 close(copy);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005712 }
5713 }
5714 redirlist = rp->next;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005715 free(rp);
5716 INT_ON;
5717}
5718
Denys Vlasenko1c79aeb2017-07-29 22:51:52 +02005719static void
5720unwindredir(struct redirtab *stop)
5721{
5722 while (redirlist != stop)
Denys Vlasenko035486c2017-07-31 04:09:19 +02005723 popredir(/*drop:*/ 0);
Denys Vlasenko1c79aeb2017-07-29 22:51:52 +02005724}
5725
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005726
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005727/* ============ Routines to expand arguments to commands
5728 *
5729 * We have to deal with backquotes, shell variables, and file metacharacters.
5730 */
5731
Denys Vlasenko0b883582016-12-23 16:49:07 +01005732#if ENABLE_FEATURE_SH_MATH
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005733static arith_t
5734ash_arith(const char *s)
5735{
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005736 arith_state_t math_state;
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005737 arith_t result;
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005738
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005739 math_state.lookupvar = lookupvar;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02005740 math_state.setvar = setvar0;
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005741 //math_state.endofname = endofname;
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005742
5743 INT_OFF;
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005744 result = arith(&math_state, s);
Denys Vlasenko063847d2010-09-15 13:33:02 +02005745 if (math_state.errmsg)
5746 ash_msg_and_raise_error(math_state.errmsg);
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005747 INT_ON;
5748
5749 return result;
5750}
Denis Vlasenko448d30e2008-06-27 00:24:11 +00005751#endif
5752
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005753/*
5754 * expandarg flags
5755 */
5756#define EXP_FULL 0x1 /* perform word splitting & file globbing */
5757#define EXP_TILDE 0x2 /* do normal tilde expansion */
5758#define EXP_VARTILDE 0x4 /* expand tildes in an assignment */
5759#define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */
Denys Vlasenkodb74c6c2016-10-24 21:12:33 +02005760/* ^^^^^^^^^^^^^^ this is meant to support constructs such as "cmd >file*.txt"
5761 * POSIX says for this case:
5762 * Pathname expansion shall not be performed on the word by a
5763 * non-interactive shell; an interactive shell may perform it, but shall
5764 * do so only when the expansion would result in one word.
5765 * Currently, our code complies to the above rule by never globbing
5766 * redirection filenames.
5767 * Bash performs globbing, unless it is non-interactive and in POSIX mode.
5768 * (this means that on a typical Linux distro, bash almost always
5769 * performs globbing, and thus diverges from what we do).
5770 */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005771#define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */
Ron Yorston549deab2015-05-18 09:57:51 +02005772#define EXP_QPAT 0x20 /* pattern in quoted parameter expansion */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005773#define EXP_VARTILDE2 0x40 /* expand tildes after colons only */
5774#define EXP_WORD 0x80 /* expand word in parameter expansion */
Ron Yorston3df47f92015-05-18 09:53:26 +02005775#define EXP_QUOTED 0x100 /* expand word in double quotes */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005776/*
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005777 * rmescape() flags
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005778 */
5779#define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
5780#define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005781#define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */
5782#define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */
Ron Yorston417622c2015-05-18 09:59:14 +02005783#define RMESCAPE_SLASH 0x20 /* Stop globbing after slash */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005784
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005785/* Add CTLESC when necessary. */
Denys Vlasenko2990aa42017-07-25 17:37:57 +02005786#define QUOTES_ESC (EXP_FULL | EXP_CASE | EXP_QPAT)
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005787/* Do not skip NUL characters. */
5788#define QUOTES_KEEPNUL EXP_TILDE
5789
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005790/*
5791 * Structure specifying which parts of the string should be searched
5792 * for IFS characters.
5793 */
5794struct ifsregion {
5795 struct ifsregion *next; /* next region in list */
5796 int begoff; /* offset of start of region */
5797 int endoff; /* offset of end of region */
5798 int nulonly; /* search for nul bytes only */
5799};
5800
5801struct arglist {
5802 struct strlist *list;
5803 struct strlist **lastp;
5804};
5805
5806/* output of current string */
5807static char *expdest;
5808/* list of back quote expressions */
5809static struct nodelist *argbackq;
5810/* first struct in list of ifs regions */
5811static struct ifsregion ifsfirst;
5812/* last struct in list */
5813static struct ifsregion *ifslastp;
5814/* holds expanded arg list */
5815static struct arglist exparg;
5816
5817/*
5818 * Our own itoa().
Denys Vlasenkocf3a7962017-07-26 14:38:19 +02005819 * cvtnum() is used even if math support is off (to prepare $? values and such).
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005820 */
5821static int
5822cvtnum(arith_t num)
5823{
5824 int len;
5825
Denys Vlasenkocf3a7962017-07-26 14:38:19 +02005826 /* 32-bit and wider ints require buffer size of bytes*3 (or less) */
5827 len = sizeof(arith_t) * 3;
5828 /* If narrower: worst case, 1-byte ints: need 5 bytes: "-127<NUL>" */
5829 if (sizeof(arith_t) < 4) len += 2;
5830
5831 expdest = makestrspace(len, expdest);
5832 len = fmtstr(expdest, len, ARITH_FMT, num);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005833 STADJUST(len, expdest);
5834 return len;
5835}
5836
Denys Vlasenko455e4222016-10-27 14:45:13 +02005837/*
5838 * Break the argument string into pieces based upon IFS and add the
5839 * strings to the argument list. The regions of the string to be
5840 * searched for IFS characters have been stored by recordregion.
5841 */
5842static void
5843ifsbreakup(char *string, struct arglist *arglist)
5844{
5845 struct ifsregion *ifsp;
5846 struct strlist *sp;
5847 char *start;
5848 char *p;
5849 char *q;
5850 const char *ifs, *realifs;
5851 int ifsspc;
5852 int nulonly;
5853
5854 start = string;
5855 if (ifslastp != NULL) {
5856 ifsspc = 0;
5857 nulonly = 0;
5858 realifs = ifsset() ? ifsval() : defifs;
5859 ifsp = &ifsfirst;
5860 do {
5861 p = string + ifsp->begoff;
5862 nulonly = ifsp->nulonly;
5863 ifs = nulonly ? nullstr : realifs;
5864 ifsspc = 0;
5865 while (p < string + ifsp->endoff) {
5866 q = p;
5867 if ((unsigned char)*p == CTLESC)
5868 p++;
5869 if (!strchr(ifs, *p)) {
5870 p++;
5871 continue;
5872 }
5873 if (!nulonly)
5874 ifsspc = (strchr(defifs, *p) != NULL);
5875 /* Ignore IFS whitespace at start */
5876 if (q == start && ifsspc) {
5877 p++;
5878 start = p;
5879 continue;
5880 }
5881 *q = '\0';
5882 sp = stzalloc(sizeof(*sp));
5883 sp->text = start;
5884 *arglist->lastp = sp;
5885 arglist->lastp = &sp->next;
5886 p++;
5887 if (!nulonly) {
5888 for (;;) {
5889 if (p >= string + ifsp->endoff) {
5890 break;
5891 }
5892 q = p;
5893 if ((unsigned char)*p == CTLESC)
5894 p++;
5895 if (strchr(ifs, *p) == NULL) {
5896 p = q;
5897 break;
5898 }
5899 if (strchr(defifs, *p) == NULL) {
5900 if (ifsspc) {
5901 p++;
5902 ifsspc = 0;
5903 } else {
5904 p = q;
5905 break;
5906 }
5907 } else
5908 p++;
5909 }
5910 }
5911 start = p;
5912 } /* while */
5913 ifsp = ifsp->next;
5914 } while (ifsp != NULL);
5915 if (nulonly)
5916 goto add;
5917 }
5918
5919 if (!*start)
5920 return;
5921
5922 add:
5923 sp = stzalloc(sizeof(*sp));
5924 sp->text = start;
5925 *arglist->lastp = sp;
5926 arglist->lastp = &sp->next;
5927}
5928
5929static void
5930ifsfree(void)
5931{
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02005932 struct ifsregion *p = ifsfirst.next;
5933
5934 if (!p)
5935 goto out;
Denys Vlasenko455e4222016-10-27 14:45:13 +02005936
5937 INT_OFF;
Denys Vlasenko455e4222016-10-27 14:45:13 +02005938 do {
5939 struct ifsregion *ifsp;
5940 ifsp = p->next;
5941 free(p);
5942 p = ifsp;
5943 } while (p);
Denys Vlasenko455e4222016-10-27 14:45:13 +02005944 ifsfirst.next = NULL;
5945 INT_ON;
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02005946 out:
5947 ifslastp = NULL;
Denys Vlasenko455e4222016-10-27 14:45:13 +02005948}
5949
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005950static size_t
5951esclen(const char *start, const char *p)
5952{
5953 size_t esc = 0;
5954
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005955 while (p > start && (unsigned char)*--p == CTLESC) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005956 esc++;
5957 }
5958 return esc;
5959}
5960
5961/*
5962 * Remove any CTLESC characters from a string.
5963 */
5964static char *
Denys Vlasenkob6c84342009-08-29 20:23:20 +02005965rmescapes(char *str, int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005966{
Ron Yorston417622c2015-05-18 09:59:14 +02005967 static const char qchars[] ALIGN1 = {
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01005968 IF_BASH_PATTERN_SUBST('/',) CTLESC, CTLQUOTEMARK, '\0' };
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00005969
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005970 char *p, *q, *r;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005971 unsigned inquotes;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005972 unsigned protect_against_glob;
5973 unsigned globbing;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01005974 IF_BASH_PATTERN_SUBST(unsigned slash = flag & RMESCAPE_SLASH;)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005975
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01005976 p = strpbrk(str, qchars IF_BASH_PATTERN_SUBST(+ !slash));
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005977 if (!p)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005978 return str;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005979
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005980 q = p;
5981 r = str;
5982 if (flag & RMESCAPE_ALLOC) {
5983 size_t len = p - str;
5984 size_t fulllen = len + strlen(p) + 1;
5985
5986 if (flag & RMESCAPE_GROW) {
Colin Watson3963d942010-04-26 14:21:27 +02005987 int strloc = str - (char *)stackblock();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005988 r = makestrspace(fulllen, expdest);
Colin Watson3963d942010-04-26 14:21:27 +02005989 /* p and str may be invalidated by makestrspace */
5990 str = (char *)stackblock() + strloc;
5991 p = str + len;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005992 } else if (flag & RMESCAPE_HEAP) {
5993 r = ckmalloc(fulllen);
5994 } else {
5995 r = stalloc(fulllen);
5996 }
5997 q = r;
5998 if (len > 0) {
Denys Vlasenko5ace96a2017-07-23 21:46:02 +02005999 q = (char *)mempcpy(q, str, len);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006000 }
6001 }
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006002
Ron Yorston549deab2015-05-18 09:57:51 +02006003 inquotes = 0;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006004 globbing = flag & RMESCAPE_GLOB;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006005 protect_against_glob = globbing;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006006 while (*p) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006007 if ((unsigned char)*p == CTLQUOTEMARK) {
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006008// Note: both inquotes and protect_against_glob only affect whether
Denys Vlasenkofda9faf2017-07-05 19:10:21 +02006009// CTLESC,<ch> gets converted to <ch> or to \<ch>
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006010 inquotes = ~inquotes;
6011 p++;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006012 protect_against_glob = globbing;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006013 continue;
6014 }
Ron Yorston549deab2015-05-18 09:57:51 +02006015 if ((unsigned char)*p == CTLESC) {
6016 p++;
Denys Vlasenko13f20912016-09-25 20:54:25 +02006017#if DEBUG
6018 if (*p == '\0')
6019 ash_msg_and_raise_error("CTLESC at EOL (shouldn't happen)");
6020#endif
Ron Yorston549deab2015-05-18 09:57:51 +02006021 if (protect_against_glob) {
Denys Vlasenkofda9faf2017-07-05 19:10:21 +02006022 /*
6023 * We used to trust glob() and fnmatch() to eat
6024 * superfluous escapes (\z where z has no
6025 * special meaning anyway). But this causes
6026 * bugs such as string of one greek letter rho
Denys Vlasenkoed79a632017-07-05 19:20:43 +02006027 * (unicode-encoded as two bytes "cf,81")
Denys Vlasenkofda9faf2017-07-05 19:10:21 +02006028 * getting encoded as "cf,CTLESC,81"
6029 * and here, converted to "cf,\,81" -
6030 * which does not go well with some flavors
Denys Vlasenko92b8d9c2017-07-05 19:13:44 +02006031 * of fnmatch() in unicode locales
6032 * (for example, glibc <= 2.22).
Denys Vlasenkofda9faf2017-07-05 19:10:21 +02006033 *
6034 * Lets add "\" only on the chars which need it.
Denys Vlasenko4142f012017-07-05 22:19:28 +02006035 * Testcases for less obvious chars are shown.
Denys Vlasenkofda9faf2017-07-05 19:10:21 +02006036 */
6037 if (*p == '*'
6038 || *p == '?'
6039 || *p == '['
Denys Vlasenko4142f012017-07-05 22:19:28 +02006040 || *p == '\\' /* case '\' in \\ ) echo ok;; *) echo WRONG;; esac */
6041 || *p == ']' /* case ']' in [a\]] ) echo ok;; *) echo WRONG;; esac */
6042 || *p == '-' /* case '-' in [a\-c]) echo ok;; *) echo WRONG;; esac */
6043 || *p == '!' /* case '!' in [\!] ) echo ok;; *) echo WRONG;; esac */
6044 /* Some libc support [^negate], that's why "^" also needs love */
6045 || *p == '^' /* case '^' in [\^] ) echo ok;; *) echo WRONG;; esac */
Denys Vlasenkofda9faf2017-07-05 19:10:21 +02006046 ) {
6047 *q++ = '\\';
6048 }
Ron Yorston549deab2015-05-18 09:57:51 +02006049 }
6050 } else if (*p == '\\' && !inquotes) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006051 /* naked back slash */
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006052 protect_against_glob = 0;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006053 goto copy;
6054 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006055#if BASH_PATTERN_SUBST
Ron Yorston417622c2015-05-18 09:59:14 +02006056 else if (*p == '/' && slash) {
6057 /* stop handling globbing and mark location of slash */
6058 globbing = slash = 0;
6059 *p = CTLESC;
6060 }
6061#endif
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006062 protect_against_glob = globbing;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006063 copy:
6064 *q++ = *p++;
6065 }
6066 *q = '\0';
6067 if (flag & RMESCAPE_GROW) {
6068 expdest = r;
6069 STADJUST(q - r + 1, expdest);
6070 }
6071 return r;
6072}
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006073#define pmatch(a, b) !fnmatch((a), (b), 0)
6074
6075/*
6076 * Prepare a pattern for a expmeta (internal glob(3)) call.
6077 *
6078 * Returns an stalloced string.
6079 */
6080static char *
Ron Yorston549deab2015-05-18 09:57:51 +02006081preglob(const char *pattern, int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006082{
Ron Yorston549deab2015-05-18 09:57:51 +02006083 return rmescapes((char *)pattern, flag | RMESCAPE_GLOB);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006084}
6085
6086/*
6087 * Put a string on the stack.
6088 */
6089static void
6090memtodest(const char *p, size_t len, int syntax, int quotes)
6091{
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006092 char *q;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006093
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006094 if (!len)
6095 return;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006096
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006097 q = makestrspace((quotes & QUOTES_ESC) ? len * 2 : len, expdest);
6098
6099 do {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006100 unsigned char c = *p++;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006101 if (c) {
Denys Vlasenko2fe66b12016-12-12 17:39:12 +01006102 if (quotes & QUOTES_ESC) {
6103 int n = SIT(c, syntax);
6104 if (n == CCTL
6105 || (((quotes & EXP_FULL) || syntax != BASESYNTAX)
6106 && n == CBACK
6107 )
6108 ) {
6109 USTPUTC(CTLESC, q);
6110 }
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02006111 }
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006112 } else if (!(quotes & QUOTES_KEEPNUL))
6113 continue;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006114 USTPUTC(c, q);
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006115 } while (--len);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006116
6117 expdest = q;
6118}
6119
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006120static size_t
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006121strtodest(const char *p, int syntax, int quotes)
6122{
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006123 size_t len = strlen(p);
6124 memtodest(p, len, syntax, quotes);
6125 return len;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006126}
6127
6128/*
6129 * Record the fact that we have to scan this region of the
6130 * string for IFS characters.
6131 */
6132static void
6133recordregion(int start, int end, int nulonly)
6134{
6135 struct ifsregion *ifsp;
6136
6137 if (ifslastp == NULL) {
6138 ifsp = &ifsfirst;
6139 } else {
6140 INT_OFF;
Denis Vlasenko597906c2008-02-20 16:38:54 +00006141 ifsp = ckzalloc(sizeof(*ifsp));
6142 /*ifsp->next = NULL; - ckzalloc did it */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006143 ifslastp->next = ifsp;
6144 INT_ON;
6145 }
6146 ifslastp = ifsp;
6147 ifslastp->begoff = start;
6148 ifslastp->endoff = end;
6149 ifslastp->nulonly = nulonly;
6150}
6151
6152static void
6153removerecordregions(int endoff)
6154{
6155 if (ifslastp == NULL)
6156 return;
6157
6158 if (ifsfirst.endoff > endoff) {
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006159 while (ifsfirst.next) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006160 struct ifsregion *ifsp;
6161 INT_OFF;
6162 ifsp = ifsfirst.next->next;
6163 free(ifsfirst.next);
6164 ifsfirst.next = ifsp;
6165 INT_ON;
6166 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006167 if (ifsfirst.begoff > endoff) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006168 ifslastp = NULL;
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006169 } else {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006170 ifslastp = &ifsfirst;
6171 ifsfirst.endoff = endoff;
6172 }
6173 return;
6174 }
6175
6176 ifslastp = &ifsfirst;
6177 while (ifslastp->next && ifslastp->next->begoff < endoff)
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006178 ifslastp = ifslastp->next;
6179 while (ifslastp->next) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006180 struct ifsregion *ifsp;
6181 INT_OFF;
6182 ifsp = ifslastp->next->next;
6183 free(ifslastp->next);
6184 ifslastp->next = ifsp;
6185 INT_ON;
6186 }
6187 if (ifslastp->endoff > endoff)
6188 ifslastp->endoff = endoff;
6189}
6190
6191static char *
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006192exptilde(char *startp, char *p, int flags)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006193{
Denys Vlasenkocd716832009-11-28 22:14:02 +01006194 unsigned char c;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006195 char *name;
6196 struct passwd *pw;
6197 const char *home;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006198 int quotes = flags & QUOTES_ESC;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006199
6200 name = p + 1;
6201
6202 while ((c = *++p) != '\0') {
6203 switch (c) {
6204 case CTLESC:
6205 return startp;
6206 case CTLQUOTEMARK:
6207 return startp;
6208 case ':':
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006209 if (flags & EXP_VARTILDE)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006210 goto done;
6211 break;
6212 case '/':
6213 case CTLENDVAR:
6214 goto done;
6215 }
6216 }
6217 done:
6218 *p = '\0';
6219 if (*name == '\0') {
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02006220 home = lookupvar("HOME");
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006221 } else {
6222 pw = getpwnam(name);
6223 if (pw == NULL)
6224 goto lose;
6225 home = pw->pw_dir;
6226 }
6227 if (!home || !*home)
6228 goto lose;
6229 *p = c;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006230 strtodest(home, SQSYNTAX, quotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006231 return p;
6232 lose:
6233 *p = c;
6234 return startp;
6235}
6236
6237/*
6238 * Execute a command inside back quotes. If it's a builtin command, we
6239 * want to save its output in a block obtained from malloc. Otherwise
6240 * we fork off a subprocess and get the output of the command via a pipe.
6241 * Should be called with interrupts off.
6242 */
6243struct backcmd { /* result of evalbackcmd */
6244 int fd; /* file descriptor to read from */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006245 int nleft; /* number of chars in buffer */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00006246 char *buf; /* buffer */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006247 struct job *jp; /* job structure for command */
6248};
6249
6250/* These forward decls are needed to use "eval" code for backticks handling: */
Denys Vlasenko1e3e2cc2017-07-25 20:31:14 +02006251/* flags in argument to evaltree */
6252#define EV_EXIT 01 /* exit after evaluating tree */
6253#define EV_TESTED 02 /* exit status is checked; ignore -e flag */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02006254static int evaltree(union node *, int);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006255
Denys Vlasenko619d9b52017-07-28 15:28:33 +02006256/* An evaltree() which is known to never return.
6257 * Used to use an alias:
6258 * static int evaltreenr(union node *, int) __attribute__((alias("evaltree"),__noreturn__));
6259 * but clang was reported to "transfer" noreturn-ness to evaltree() as well.
6260 */
6261static ALWAYS_INLINE NORETURN void
6262evaltreenr(union node *n, int flags)
6263{
6264 evaltree(n, flags);
6265 bb_unreachable(abort());
6266 /* NOTREACHED */
6267}
6268
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02006269static void FAST_FUNC
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006270evalbackcmd(union node *n, struct backcmd *result)
6271{
Denys Vlasenko579ad102016-10-25 21:10:20 +02006272 int pip[2];
6273 struct job *jp;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006274
6275 result->fd = -1;
6276 result->buf = NULL;
6277 result->nleft = 0;
6278 result->jp = NULL;
Denys Vlasenko579ad102016-10-25 21:10:20 +02006279 if (n == NULL) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006280 goto out;
Denys Vlasenko579ad102016-10-25 21:10:20 +02006281 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006282
Denys Vlasenko579ad102016-10-25 21:10:20 +02006283 if (pipe(pip) < 0)
Denys Vlasenko12ffefb2017-08-23 14:52:56 +02006284 ash_msg_and_raise_perror("can't create pipe");
Denys Vlasenko579ad102016-10-25 21:10:20 +02006285 jp = makejob(/*n,*/ 1);
6286 if (forkshell(jp, n, FORK_NOJOB) == 0) {
Denys Vlasenko70392332016-10-27 02:31:55 +02006287 /* child */
Denys Vlasenko579ad102016-10-25 21:10:20 +02006288 FORCE_INT_ON;
6289 close(pip[0]);
6290 if (pip[1] != 1) {
6291 /*close(1);*/
Denys Vlasenko64774602016-10-26 15:24:30 +02006292 dup2_or_raise(pip[1], 1);
Denys Vlasenko579ad102016-10-25 21:10:20 +02006293 close(pip[1]);
6294 }
Denys Vlasenko960ca382016-10-25 18:12:15 +02006295/* TODO: eflag clearing makes the following not abort:
6296 * ash -c 'set -e; z=$(false;echo foo); echo $z'
6297 * which is what bash does (unless it is in POSIX mode).
6298 * dash deleted "eflag = 0" line in the commit
6299 * Date: Mon, 28 Jun 2010 17:11:58 +1000
6300 * [EVAL] Don't clear eflag in evalbackcmd
6301 * For now, preserve bash-like behavior, it seems to be somewhat more useful:
6302 */
Denys Vlasenko579ad102016-10-25 21:10:20 +02006303 eflag = 0;
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02006304 ifsfree();
Denys Vlasenko619d9b52017-07-28 15:28:33 +02006305 evaltreenr(n, EV_EXIT);
Denys Vlasenko579ad102016-10-25 21:10:20 +02006306 /* NOTREACHED */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006307 }
Denys Vlasenko70392332016-10-27 02:31:55 +02006308 /* parent */
Denys Vlasenko579ad102016-10-25 21:10:20 +02006309 close(pip[1]);
6310 result->fd = pip[0];
6311 result->jp = jp;
6312
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006313 out:
6314 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
6315 result->fd, result->buf, result->nleft, result->jp));
6316}
6317
6318/*
6319 * Expand stuff in backwards quotes.
6320 */
6321static void
Ron Yorston549deab2015-05-18 09:57:51 +02006322expbackq(union node *cmd, int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006323{
6324 struct backcmd in;
6325 int i;
6326 char buf[128];
6327 char *p;
6328 char *dest;
6329 int startloc;
Ron Yorston549deab2015-05-18 09:57:51 +02006330 int syntax = flag & EXP_QUOTED ? DQSYNTAX : BASESYNTAX;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006331 struct stackmark smark;
6332
6333 INT_OFF;
Denys Vlasenko60ca8342016-09-30 11:21:21 +02006334 startloc = expdest - (char *)stackblock();
6335 pushstackmark(&smark, startloc);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006336 evalbackcmd(cmd, &in);
6337 popstackmark(&smark);
6338
6339 p = in.buf;
6340 i = in.nleft;
6341 if (i == 0)
6342 goto read;
6343 for (;;) {
Ron Yorston549deab2015-05-18 09:57:51 +02006344 memtodest(p, i, syntax, flag & QUOTES_ESC);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006345 read:
6346 if (in.fd < 0)
6347 break;
Ron Yorston61d6ae22015-04-19 10:50:25 +01006348 i = nonblock_immune_read(in.fd, buf, sizeof(buf));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006349 TRACE(("expbackq: read returns %d\n", i));
6350 if (i <= 0)
6351 break;
6352 p = buf;
6353 }
6354
Denis Vlasenko60818682007-09-28 22:07:23 +00006355 free(in.buf);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006356 if (in.fd >= 0) {
6357 close(in.fd);
6358 back_exitstatus = waitforjob(in.jp);
6359 }
6360 INT_ON;
6361
6362 /* Eat all trailing newlines */
6363 dest = expdest;
6364 for (; dest > (char *)stackblock() && dest[-1] == '\n';)
6365 STUNPUTC(dest);
6366 expdest = dest;
6367
Ron Yorston549deab2015-05-18 09:57:51 +02006368 if (!(flag & EXP_QUOTED))
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006369 recordregion(startloc, dest - (char *)stackblock(), 0);
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006370 TRACE(("evalbackq: size:%d:'%.*s'\n",
6371 (int)((dest - (char *)stackblock()) - startloc),
6372 (int)((dest - (char *)stackblock()) - startloc),
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006373 stackblock() + startloc));
6374}
6375
Denys Vlasenko0b883582016-12-23 16:49:07 +01006376#if ENABLE_FEATURE_SH_MATH
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006377/*
6378 * Expand arithmetic expression. Backup to start of expression,
6379 * evaluate, place result in (backed up) result, adjust string position.
6380 */
6381static void
Ron Yorston549deab2015-05-18 09:57:51 +02006382expari(int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006383{
6384 char *p, *start;
6385 int begoff;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006386 int len;
6387
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006388 /* ifsfree(); */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006389
6390 /*
6391 * This routine is slightly over-complicated for
6392 * efficiency. Next we scan backwards looking for the
6393 * start of arithmetic.
6394 */
6395 start = stackblock();
6396 p = expdest - 1;
6397 *p = '\0';
6398 p--;
Denys Vlasenko940c7202011-03-02 04:07:14 +01006399 while (1) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006400 int esc;
6401
Denys Vlasenkocd716832009-11-28 22:14:02 +01006402 while ((unsigned char)*p != CTLARI) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006403 p--;
6404#if DEBUG
6405 if (p < start) {
6406 ash_msg_and_raise_error("missing CTLARI (shouldn't happen)");
6407 }
6408#endif
6409 }
6410
6411 esc = esclen(start, p);
6412 if (!(esc % 2)) {
6413 break;
6414 }
6415
6416 p -= esc + 1;
Denys Vlasenko940c7202011-03-02 04:07:14 +01006417 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006418
6419 begoff = p - start;
6420
6421 removerecordregions(begoff);
6422
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006423 expdest = p;
6424
Ron Yorston549deab2015-05-18 09:57:51 +02006425 if (flag & QUOTES_ESC)
6426 rmescapes(p + 1, 0);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006427
Ron Yorston549deab2015-05-18 09:57:51 +02006428 len = cvtnum(ash_arith(p + 1));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006429
Ron Yorston549deab2015-05-18 09:57:51 +02006430 if (!(flag & EXP_QUOTED))
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006431 recordregion(begoff, begoff + len, 0);
6432}
6433#endif
6434
6435/* argstr needs it */
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02006436static char *evalvar(char *p, int flags);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006437
6438/*
6439 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
6440 * characters to allow for further processing. Otherwise treat
6441 * $@ like $* since no splitting will be performed.
6442 */
6443static void
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02006444argstr(char *p, int flags)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006445{
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00006446 static const char spclchars[] ALIGN1 = {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006447 '=',
6448 ':',
6449 CTLQUOTEMARK,
6450 CTLENDVAR,
6451 CTLESC,
6452 CTLVAR,
6453 CTLBACKQ,
Denys Vlasenko0b883582016-12-23 16:49:07 +01006454#if ENABLE_FEATURE_SH_MATH
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006455 CTLENDARI,
6456#endif
Denys Vlasenkocd716832009-11-28 22:14:02 +01006457 '\0'
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006458 };
6459 const char *reject = spclchars;
Ron Yorston3df47f92015-05-18 09:53:26 +02006460 int breakall = (flags & (EXP_WORD | EXP_QUOTED)) == EXP_WORD;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006461 int inquotes;
6462 size_t length;
6463 int startloc;
6464
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006465 if (!(flags & EXP_VARTILDE)) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006466 reject += 2;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006467 } else if (flags & EXP_VARTILDE2) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006468 reject++;
6469 }
6470 inquotes = 0;
6471 length = 0;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006472 if (flags & EXP_TILDE) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006473 char *q;
6474
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006475 flags &= ~EXP_TILDE;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006476 tilde:
6477 q = p;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006478 if (*q == '~')
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006479 p = exptilde(p, q, flags);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006480 }
6481 start:
6482 startloc = expdest - (char *)stackblock();
6483 for (;;) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006484 unsigned char c;
6485
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006486 length += strcspn(p + length, reject);
Denys Vlasenkocd716832009-11-28 22:14:02 +01006487 c = p[length];
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006488 if (c) {
6489 if (!(c & 0x80)
Denys Vlasenko0b883582016-12-23 16:49:07 +01006490 IF_FEATURE_SH_MATH(|| c == CTLENDARI)
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006491 ) {
6492 /* c == '=' || c == ':' || c == CTLENDARI */
6493 length++;
6494 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006495 }
6496 if (length > 0) {
6497 int newloc;
6498 expdest = stack_nputstr(p, length, expdest);
6499 newloc = expdest - (char *)stackblock();
6500 if (breakall && !inquotes && newloc > startloc) {
6501 recordregion(startloc, newloc, 0);
6502 }
6503 startloc = newloc;
6504 }
6505 p += length + 1;
6506 length = 0;
6507
6508 switch (c) {
6509 case '\0':
6510 goto breakloop;
6511 case '=':
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006512 if (flags & EXP_VARTILDE2) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006513 p--;
6514 continue;
6515 }
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006516 flags |= EXP_VARTILDE2;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006517 reject++;
6518 /* fall through */
6519 case ':':
6520 /*
6521 * sort of a hack - expand tildes in variable
6522 * assignments (after the first '=' and after ':'s).
6523 */
6524 if (*--p == '~') {
6525 goto tilde;
6526 }
6527 continue;
6528 }
6529
6530 switch (c) {
6531 case CTLENDVAR: /* ??? */
6532 goto breakloop;
6533 case CTLQUOTEMARK:
Ron Yorston549deab2015-05-18 09:57:51 +02006534 inquotes ^= EXP_QUOTED;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006535 /* "$@" syntax adherence hack */
Ron Yorston549deab2015-05-18 09:57:51 +02006536 if (inquotes && !memcmp(p, dolatstr + 1, DOLATSTRLEN - 1)) {
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02006537 p = evalvar(p + 1, flags | inquotes) + 1;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006538 goto start;
6539 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006540 addquote:
Ron Yorston549deab2015-05-18 09:57:51 +02006541 if (flags & QUOTES_ESC) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006542 p--;
6543 length++;
6544 startloc++;
6545 }
6546 break;
6547 case CTLESC:
6548 startloc++;
6549 length++;
Ron Yorston549deab2015-05-18 09:57:51 +02006550
6551 /*
6552 * Quoted parameter expansion pattern: remove quote
6553 * unless inside inner quotes or we have a literal
6554 * backslash.
6555 */
6556 if (((flags | inquotes) & (EXP_QPAT | EXP_QUOTED)) ==
6557 EXP_QPAT && *p != '\\')
6558 break;
6559
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006560 goto addquote;
6561 case CTLVAR:
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02006562 TRACE(("argstr: evalvar('%s')\n", p));
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02006563 p = evalvar(p, flags | inquotes);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02006564 TRACE(("argstr: evalvar:'%s'\n", (char *)stackblock()));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006565 goto start;
6566 case CTLBACKQ:
Ron Yorston549deab2015-05-18 09:57:51 +02006567 expbackq(argbackq->n, flags | inquotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006568 argbackq = argbackq->next;
6569 goto start;
Denys Vlasenko0b883582016-12-23 16:49:07 +01006570#if ENABLE_FEATURE_SH_MATH
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006571 case CTLENDARI:
6572 p--;
Ron Yorston549deab2015-05-18 09:57:51 +02006573 expari(flags | inquotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006574 goto start;
6575#endif
6576 }
6577 }
Denys Vlasenko958581a2010-09-12 15:04:27 +02006578 breakloop: ;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006579}
6580
6581static char *
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006582scanleft(char *startp, char *rmesc, char *rmescend UNUSED_PARAM,
6583 char *pattern, int quotes, int zero)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006584{
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006585 char *loc, *loc2;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006586 char c;
6587
6588 loc = startp;
6589 loc2 = rmesc;
6590 do {
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006591 int match;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006592 const char *s = loc2;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006593
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006594 c = *loc2;
6595 if (zero) {
6596 *loc2 = '\0';
6597 s = rmesc;
6598 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006599 match = pmatch(pattern, s);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006600
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006601 *loc2 = c;
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006602 if (match)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006603 return loc;
Denys Vlasenkocd716832009-11-28 22:14:02 +01006604 if (quotes && (unsigned char)*loc == CTLESC)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006605 loc++;
6606 loc++;
6607 loc2++;
6608 } while (c);
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006609 return NULL;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006610}
6611
6612static char *
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006613scanright(char *startp, char *rmesc, char *rmescend,
6614 char *pattern, int quotes, int match_at_start)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006615{
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006616#if !ENABLE_ASH_OPTIMIZE_FOR_SIZE
6617 int try2optimize = match_at_start;
6618#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006619 int esc = 0;
6620 char *loc;
6621 char *loc2;
6622
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006623 /* If we called by "${v/pattern/repl}" or "${v//pattern/repl}":
6624 * startp="escaped_value_of_v" rmesc="raw_value_of_v"
6625 * rmescend=""(ptr to NUL in rmesc) pattern="pattern" quotes=match_at_start=1
6626 * Logic:
6627 * loc starts at NUL at the end of startp, loc2 starts at the end of rmesc,
6628 * and on each iteration they go back two/one char until they reach the beginning.
6629 * We try to find a match in "raw_value_of_v", "raw_value_of_", "raw_value_of" etc.
6630 */
6631 /* TODO: document in what other circumstances we are called. */
6632
6633 for (loc = pattern - 1, loc2 = rmescend; loc >= startp; loc2--) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006634 int match;
6635 char c = *loc2;
6636 const char *s = loc2;
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006637 if (match_at_start) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006638 *loc2 = '\0';
6639 s = rmesc;
6640 }
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006641 match = pmatch(pattern, s);
6642 //bb_error_msg("pmatch(pattern:'%s',s:'%s'):%d", pattern, s, match);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006643 *loc2 = c;
6644 if (match)
6645 return loc;
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006646#if !ENABLE_ASH_OPTIMIZE_FOR_SIZE
6647 if (try2optimize) {
6648 /* Maybe we can optimize this:
6649 * if pattern ends with unescaped *, we can avoid checking
Denys Vlasenko10ad6222017-04-17 16:13:32 +02006650 * shorter strings: if "foo*" doesn't match "raw_value_of_v",
6651 * it won't match truncated "raw_value_of_" strings too.
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006652 */
6653 unsigned plen = strlen(pattern);
6654 /* Does it end with "*"? */
6655 if (plen != 0 && pattern[--plen] == '*') {
6656 /* "xxxx*" is not escaped */
6657 /* "xxx\*" is escaped */
6658 /* "xx\\*" is not escaped */
6659 /* "x\\\*" is escaped */
6660 int slashes = 0;
6661 while (plen != 0 && pattern[--plen] == '\\')
6662 slashes++;
6663 if (!(slashes & 1))
6664 break; /* ends with unescaped "*" */
6665 }
6666 try2optimize = 0;
6667 }
6668#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006669 loc--;
6670 if (quotes) {
6671 if (--esc < 0) {
6672 esc = esclen(startp, loc);
6673 }
6674 if (esc % 2) {
6675 esc--;
6676 loc--;
6677 }
6678 }
6679 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006680 return NULL;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006681}
6682
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00006683static void varunset(const char *, const char *, const char *, int) NORETURN;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006684static void
6685varunset(const char *end, const char *var, const char *umsg, int varflags)
6686{
6687 const char *msg;
6688 const char *tail;
6689
6690 tail = nullstr;
6691 msg = "parameter not set";
6692 if (umsg) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006693 if ((unsigned char)*end == CTLENDVAR) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006694 if (varflags & VSNUL)
6695 tail = " or null";
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006696 } else {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006697 msg = umsg;
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006698 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006699 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006700 ash_msg_and_raise_error("%.*s: %s%s", (int)(end - var - 1), var, msg, tail);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006701}
6702
6703static const char *
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006704subevalvar(char *p, char *varname, int strloc, int subtype,
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02006705 int startloc, int varflags, int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006706{
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006707 struct nodelist *saveargbackq = argbackq;
Ron Yorston549deab2015-05-18 09:57:51 +02006708 int quotes = flag & QUOTES_ESC;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006709 char *startp;
6710 char *loc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006711 char *rmesc, *rmescend;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006712 char *str;
Denys Vlasenko0b4980c2012-09-25 12:49:29 +02006713 int amount, resetloc;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006714 IF_BASH_PATTERN_SUBST(int workloc;)
6715 IF_BASH_PATTERN_SUBST(char *repl = NULL;)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006716 int zero;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006717 char *(*scan)(char*, char*, char*, char*, int, int);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006718
Denys Vlasenko6040fe82010-09-12 15:03:16 +02006719 //bb_error_msg("subevalvar(p:'%s',varname:'%s',strloc:%d,subtype:%d,startloc:%d,varflags:%x,quotes:%d)",
6720 // p, varname, strloc, subtype, startloc, varflags, quotes);
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006721
Ron Yorstoneb6b48b2015-05-18 09:51:35 +02006722 argstr(p, EXP_TILDE | (subtype != VSASSIGN && subtype != VSQUESTION ?
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02006723 (flag & (EXP_QUOTED | EXP_QPAT) ? EXP_QPAT : EXP_CASE) : 0)
6724 );
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006725 STPUTC('\0', expdest);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006726 argbackq = saveargbackq;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006727 startp = (char *)stackblock() + startloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006728
6729 switch (subtype) {
6730 case VSASSIGN:
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02006731 setvar0(varname, startp);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006732 amount = startp - expdest;
6733 STADJUST(amount, expdest);
6734 return startp;
6735
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006736 case VSQUESTION:
6737 varunset(p, varname, startp, varflags);
6738 /* NOTREACHED */
6739
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006740#if BASH_SUBSTR
Denys Vlasenko826360f2017-07-17 17:49:11 +02006741 case VSSUBSTR: {
6742 int pos, len, orig_len;
6743 char *colon;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006744
Denys Vlasenko826360f2017-07-17 17:49:11 +02006745 loc = str = stackblock() + strloc;
6746
6747# if !ENABLE_FEATURE_SH_MATH
6748# define ash_arith number
6749# endif
6750 /* Read POS in ${var:POS:LEN} */
6751 colon = strchr(loc, ':');
6752 if (colon) *colon = '\0';
6753 pos = ash_arith(loc);
6754 if (colon) *colon = ':';
6755
6756 /* Read LEN in ${var:POS:LEN} */
6757 len = str - startp - 1;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006758 /* *loc != '\0', guaranteed by parser */
6759 if (quotes) {
6760 char *ptr;
6761
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006762 /* Adjust the length by the number of escapes */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006763 for (ptr = startp; ptr < (str - 1); ptr++) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006764 if ((unsigned char)*ptr == CTLESC) {
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006765 len--;
6766 ptr++;
6767 }
6768 }
6769 }
6770 orig_len = len;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006771 if (*loc++ == ':') {
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006772 /* ${var::LEN} */
Denys Vlasenko826360f2017-07-17 17:49:11 +02006773 len = ash_arith(loc);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006774 } else {
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006775 /* Skip POS in ${var:POS:LEN} */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006776 len = orig_len;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006777 while (*loc && *loc != ':') {
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006778 loc++;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006779 }
6780 if (*loc++ == ':') {
Denys Vlasenko826360f2017-07-17 17:49:11 +02006781 len = ash_arith(loc);
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006782 }
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006783 }
Denys Vlasenko826360f2017-07-17 17:49:11 +02006784# undef ash_arith
6785
Denys Vlasenko08a5dab2014-11-17 20:27:18 +01006786 if (pos < 0) {
6787 /* ${VAR:$((-n)):l} starts n chars from the end */
6788 pos = orig_len + pos;
6789 }
6790 if ((unsigned)pos >= orig_len) {
6791 /* apart from obvious ${VAR:999999:l},
6792 * covers ${VAR:$((-9999999)):l} - result is ""
Denys Vlasenko826360f2017-07-17 17:49:11 +02006793 * (bash compat)
Denys Vlasenko08a5dab2014-11-17 20:27:18 +01006794 */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006795 pos = 0;
6796 len = 0;
6797 }
Denys Vlasenko826360f2017-07-17 17:49:11 +02006798 if (len < 0) {
6799 /* ${VAR:N:-M} sets LEN to strlen()-M */
6800 len = (orig_len - pos) + len;
6801 }
6802 if ((unsigned)len > (orig_len - pos))
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006803 len = orig_len - pos;
6804
6805 for (str = startp; pos; str++, pos--) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006806 if (quotes && (unsigned char)*str == CTLESC)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006807 str++;
6808 }
6809 for (loc = startp; len; len--) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006810 if (quotes && (unsigned char)*str == CTLESC)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006811 *loc++ = *str++;
6812 *loc++ = *str++;
6813 }
6814 *loc = '\0';
6815 amount = loc - expdest;
6816 STADJUST(amount, expdest);
6817 return loc;
Denys Vlasenko826360f2017-07-17 17:49:11 +02006818 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006819#endif /* BASH_SUBSTR */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006820 }
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006821
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006822 resetloc = expdest - (char *)stackblock();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006823
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006824#if BASH_PATTERN_SUBST
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006825 /* We'll comeback here if we grow the stack while handling
6826 * a VSREPLACE or VSREPLACEALL, since our pointers into the
6827 * stack will need rebasing, and we'll need to remove our work
6828 * areas each time
6829 */
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006830 restart:
6831#endif
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006832
6833 amount = expdest - ((char *)stackblock() + resetloc);
6834 STADJUST(-amount, expdest);
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006835 startp = (char *)stackblock() + startloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006836
6837 rmesc = startp;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006838 rmescend = (char *)stackblock() + strloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006839 if (quotes) {
Denys Vlasenkob6c84342009-08-29 20:23:20 +02006840 rmesc = rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006841 if (rmesc != startp) {
6842 rmescend = expdest;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006843 startp = (char *)stackblock() + startloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006844 }
6845 }
6846 rmescend--;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006847 str = (char *)stackblock() + strloc;
Ron Yorston417622c2015-05-18 09:59:14 +02006848 /*
6849 * Example: v='a\bc'; echo ${v/\\b/_\\_\z_}
6850 * The result is a_\_z_c (not a\_\_z_c)!
6851 *
6852 * The search pattern and replace string treat backslashes differently!
6853 * RMESCAPE_SLASH causes preglob to work differently on the pattern
6854 * and string. It's only used on the first call.
6855 */
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006856 preglob(str, IF_BASH_PATTERN_SUBST(
Ron Yorston417622c2015-05-18 09:59:14 +02006857 (subtype == VSREPLACE || subtype == VSREPLACEALL) && !repl ?
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006858 RMESCAPE_SLASH : ) 0);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006859
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006860#if BASH_PATTERN_SUBST
Denys Vlasenko0b4980c2012-09-25 12:49:29 +02006861 workloc = expdest - (char *)stackblock();
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006862 if (subtype == VSREPLACE || subtype == VSREPLACEALL) {
Denys Vlasenko826360f2017-07-17 17:49:11 +02006863 int len;
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006864 char *idx, *end;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006865
Denis Vlasenkod6855d12008-09-27 14:03:25 +00006866 if (!repl) {
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02006867 repl = strchr(str, CTLESC);
6868 if (repl)
Ron Yorston417622c2015-05-18 09:59:14 +02006869 *repl++ = '\0';
6870 else
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006871 repl = nullstr;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006872 }
Ron Yorston417622c2015-05-18 09:59:14 +02006873 //bb_error_msg("str:'%s' repl:'%s'", str, repl);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006874
6875 /* If there's no pattern to match, return the expansion unmolested */
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006876 if (str[0] == '\0')
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006877 return NULL;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006878
6879 len = 0;
6880 idx = startp;
6881 end = str - 1;
6882 while (idx < end) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006883 try_to_match:
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006884 loc = scanright(idx, rmesc, rmescend, str, quotes, 1);
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006885 //bb_error_msg("scanright('%s'):'%s'", str, loc);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006886 if (!loc) {
6887 /* No match, advance */
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006888 char *restart_detect = stackblock();
6889 skip_matching:
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006890 STPUTC(*idx, expdest);
Denys Vlasenkocd716832009-11-28 22:14:02 +01006891 if (quotes && (unsigned char)*idx == CTLESC) {
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006892 idx++;
6893 len++;
6894 STPUTC(*idx, expdest);
6895 }
6896 if (stackblock() != restart_detect)
6897 goto restart;
6898 idx++;
6899 len++;
6900 rmesc++;
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006901 /* continue; - prone to quadratic behavior, smarter code: */
6902 if (idx >= end)
6903 break;
6904 if (str[0] == '*') {
6905 /* Pattern is "*foo". If "*foo" does not match "long_string",
6906 * it would never match "ong_string" etc, no point in trying.
6907 */
6908 goto skip_matching;
6909 }
6910 goto try_to_match;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006911 }
6912
6913 if (subtype == VSREPLACEALL) {
6914 while (idx < loc) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006915 if (quotes && (unsigned char)*idx == CTLESC)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006916 idx++;
6917 idx++;
6918 rmesc++;
6919 }
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006920 } else {
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006921 idx = loc;
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006922 }
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006923
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006924 //bb_error_msg("repl:'%s'", repl);
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006925 for (loc = (char*)repl; *loc; loc++) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006926 char *restart_detect = stackblock();
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006927 if (quotes && *loc == '\\') {
6928 STPUTC(CTLESC, expdest);
6929 len++;
6930 }
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006931 STPUTC(*loc, expdest);
6932 if (stackblock() != restart_detect)
6933 goto restart;
6934 len++;
6935 }
6936
6937 if (subtype == VSREPLACE) {
Denys Vlasenkof02c82f2010-08-06 19:14:47 +02006938 //bb_error_msg("tail:'%s', quotes:%x", idx, quotes);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006939 while (*idx) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006940 char *restart_detect = stackblock();
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006941 STPUTC(*idx, expdest);
6942 if (stackblock() != restart_detect)
6943 goto restart;
6944 len++;
6945 idx++;
6946 }
6947 break;
6948 }
6949 }
6950
6951 /* We've put the replaced text into a buffer at workloc, now
6952 * move it to the right place and adjust the stack.
6953 */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006954 STPUTC('\0', expdest);
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006955 startp = (char *)stackblock() + startloc;
6956 memmove(startp, (char *)stackblock() + workloc, len + 1);
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006957 //bb_error_msg("startp:'%s'", startp);
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006958 amount = expdest - (startp + len);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006959 STADJUST(-amount, expdest);
6960 return startp;
6961 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006962#endif /* BASH_PATTERN_SUBST */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006963
6964 subtype -= VSTRIMRIGHT;
6965#if DEBUG
6966 if (subtype < 0 || subtype > 7)
6967 abort();
6968#endif
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006969 /* zero = (subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX) */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006970 zero = subtype >> 1;
6971 /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */
6972 scan = (subtype & 1) ^ zero ? scanleft : scanright;
6973
6974 loc = scan(startp, rmesc, rmescend, str, quotes, zero);
6975 if (loc) {
6976 if (zero) {
6977 memmove(startp, loc, str - loc);
6978 loc = startp + (str - loc) - 1;
6979 }
6980 *loc = '\0';
6981 amount = loc - expdest;
6982 STADJUST(amount, expdest);
6983 }
6984 return loc;
6985}
6986
6987/*
6988 * Add the value of a specialized variable to the stack string.
Denys Vlasenko4d8873f2009-10-04 03:14:41 +02006989 * name parameter (examples):
6990 * ash -c 'echo $1' name:'1='
6991 * ash -c 'echo $qwe' name:'qwe='
6992 * ash -c 'echo $$' name:'$='
6993 * ash -c 'echo ${$}' name:'$='
6994 * ash -c 'echo ${$##q}' name:'$=q'
6995 * ash -c 'echo ${#$}' name:'$='
6996 * note: examples with bad shell syntax:
6997 * ash -c 'echo ${#$1}' name:'$=1'
6998 * ash -c 'echo ${#1#}' name:'1=#'
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006999 */
Denys Vlasenkoadf922e2009-10-08 14:35:37 +02007000static NOINLINE ssize_t
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02007001varvalue(char *name, int varflags, int flags, int *quotedp)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007002{
Mike Frysinger98c52642009-04-02 10:02:37 +00007003 const char *p;
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01007004 int num;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007005 int i;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007006 ssize_t len = 0;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007007 int sep;
Denys Vlasenko0dd8e452016-10-01 21:02:06 +02007008 int quoted = *quotedp;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007009 int subtype = varflags & VSTYPE;
7010 int discard = subtype == VSPLUS || subtype == VSLENGTH;
7011 int quotes = (discard ? 0 : (flags & QUOTES_ESC)) | QUOTES_KEEPNUL;
Denys Vlasenko0aaaa502016-10-02 02:46:56 +02007012 int syntax;
7013
7014 sep = (flags & EXP_FULL) << CHAR_BIT;
7015 syntax = quoted ? DQSYNTAX : BASESYNTAX;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007016
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007017 switch (*name) {
7018 case '$':
7019 num = rootpid;
7020 goto numvar;
7021 case '?':
7022 num = exitstatus;
7023 goto numvar;
7024 case '#':
7025 num = shellparam.nparam;
7026 goto numvar;
7027 case '!':
7028 num = backgndpid;
7029 if (num == 0)
7030 return -1;
7031 numvar:
7032 len = cvtnum(num);
Denys Vlasenko4d8873f2009-10-04 03:14:41 +02007033 goto check_1char_name;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007034 case '-':
Mike Frysinger98c52642009-04-02 10:02:37 +00007035 expdest = makestrspace(NOPTS, expdest);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007036 for (i = NOPTS - 1; i >= 0; i--) {
7037 if (optlist[i]) {
Mike Frysinger98c52642009-04-02 10:02:37 +00007038 USTPUTC(optletters(i), expdest);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007039 len++;
7040 }
7041 }
Denys Vlasenko4d8873f2009-10-04 03:14:41 +02007042 check_1char_name:
7043#if 0
7044 /* handles cases similar to ${#$1} */
7045 if (name[2] != '\0')
7046 raise_error_syntax("bad substitution");
7047#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007048 break;
Denys Vlasenko0aaaa502016-10-02 02:46:56 +02007049 case '@':
7050 if (quoted && sep)
7051 goto param;
7052 /* fall through */
7053 case '*': {
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01007054 char **ap;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007055 char sepc;
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01007056
Denys Vlasenko0aaaa502016-10-02 02:46:56 +02007057 if (quoted)
7058 sep = 0;
7059 sep |= ifsset() ? ifsval()[0] : ' ';
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007060 param:
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007061 sepc = sep;
Denys Vlasenko0dd8e452016-10-01 21:02:06 +02007062 *quotedp = !sepc;
7063 ap = shellparam.p;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007064 if (!ap)
7065 return -1;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02007066 while ((p = *ap++) != NULL) {
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007067 len += strtodest(p, syntax, quotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007068
7069 if (*ap && sep) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007070 len++;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007071 memtodest(&sepc, 1, syntax, quotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007072 }
7073 }
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007074 break;
Denys Vlasenko0aaaa502016-10-02 02:46:56 +02007075 } /* case '*' */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007076 case '0':
7077 case '1':
7078 case '2':
7079 case '3':
7080 case '4':
7081 case '5':
7082 case '6':
7083 case '7':
7084 case '8':
7085 case '9':
Denys Vlasenkoa00329c2009-08-30 20:05:10 +02007086 num = atoi(name); /* number(name) fails on ${N#str} etc */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007087 if (num < 0 || num > shellparam.nparam)
7088 return -1;
7089 p = num ? shellparam.p[num - 1] : arg0;
7090 goto value;
7091 default:
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00007092 /* NB: name has form "VAR=..." */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007093 p = lookupvar(name);
7094 value:
7095 if (!p)
7096 return -1;
7097
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007098 len = strtodest(p, syntax, quotes);
Denys Vlasenkoc76236f2014-12-29 00:04:18 +01007099#if ENABLE_UNICODE_SUPPORT
7100 if (subtype == VSLENGTH && len > 0) {
7101 reinit_unicode_for_ash();
7102 if (unicode_status == UNICODE_ON) {
Ron Yorston3e3bfb82016-03-18 11:29:19 +00007103 STADJUST(-len, expdest);
7104 discard = 0;
Denys Vlasenkoc76236f2014-12-29 00:04:18 +01007105 len = unicode_strlen(p);
7106 }
7107 }
7108#endif
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007109 break;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007110 }
7111
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007112 if (discard)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007113 STADJUST(-len, expdest);
7114 return len;
7115}
7116
7117/*
7118 * Expand a variable, and return a pointer to the next character in the
7119 * input string.
7120 */
7121static char *
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02007122evalvar(char *p, int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007123{
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00007124 char varflags;
7125 char subtype;
Ron Yorston549deab2015-05-18 09:57:51 +02007126 int quoted;
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00007127 char easy;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007128 char *var;
7129 int patloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007130 int startloc;
7131 ssize_t varlen;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007132
Denys Vlasenkob0d63382009-09-16 16:18:32 +02007133 varflags = (unsigned char) *p++;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007134 subtype = varflags & VSTYPE;
Denys Vlasenko88e15702016-10-26 01:55:56 +02007135
7136 if (!subtype)
7137 raise_error_syntax("bad substitution");
7138
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007139 quoted = flag & EXP_QUOTED;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007140 var = p;
7141 easy = (!quoted || (*var == '@' && shellparam.nparam));
7142 startloc = expdest - (char *)stackblock();
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02007143 p = strchr(p, '=') + 1; //TODO: use var_end(p)?
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007144
7145 again:
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02007146 varlen = varvalue(var, varflags, flag, &quoted);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007147 if (varflags & VSNUL)
7148 varlen--;
7149
7150 if (subtype == VSPLUS) {
7151 varlen = -1 - varlen;
7152 goto vsplus;
7153 }
7154
7155 if (subtype == VSMINUS) {
7156 vsplus:
7157 if (varlen < 0) {
7158 argstr(
Denys Vlasenko6040fe82010-09-12 15:03:16 +02007159 p,
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02007160 flag | EXP_TILDE | EXP_WORD
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007161 );
7162 goto end;
7163 }
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007164 goto record;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007165 }
7166
7167 if (subtype == VSASSIGN || subtype == VSQUESTION) {
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007168 if (varlen >= 0)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007169 goto record;
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007170
7171 subevalvar(p, var, 0, subtype, startloc, varflags,
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02007172 flag & ~QUOTES_ESC);
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007173 varflags &= ~VSNUL;
7174 /*
7175 * Remove any recorded regions beyond
7176 * start of variable
7177 */
7178 removerecordregions(startloc);
7179 goto again;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007180 }
7181
7182 if (varlen < 0 && uflag)
7183 varunset(p, var, 0, 0);
7184
7185 if (subtype == VSLENGTH) {
Denys Vlasenkoc76236f2014-12-29 00:04:18 +01007186 cvtnum(varlen > 0 ? varlen : 0);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007187 goto record;
7188 }
7189
7190 if (subtype == VSNORMAL) {
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007191 record:
7192 if (!easy)
7193 goto end;
Denys Vlasenko0dd8e452016-10-01 21:02:06 +02007194 recordregion(startloc, expdest - (char *)stackblock(), quoted);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007195 goto end;
7196 }
7197
7198#if DEBUG
7199 switch (subtype) {
7200 case VSTRIMLEFT:
7201 case VSTRIMLEFTMAX:
7202 case VSTRIMRIGHT:
7203 case VSTRIMRIGHTMAX:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01007204#if BASH_SUBSTR
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007205 case VSSUBSTR:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01007206#endif
7207#if BASH_PATTERN_SUBST
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007208 case VSREPLACE:
7209 case VSREPLACEALL:
7210#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007211 break;
7212 default:
7213 abort();
7214 }
7215#endif
7216
7217 if (varlen >= 0) {
7218 /*
7219 * Terminate the string and start recording the pattern
7220 * right after it
7221 */
7222 STPUTC('\0', expdest);
7223 patloc = expdest - (char *)stackblock();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02007224 if (NULL == subevalvar(p, /* varname: */ NULL, patloc, subtype,
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02007225 startloc, varflags, flag)) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007226 int amount = expdest - (
7227 (char *)stackblock() + patloc - 1
7228 );
7229 STADJUST(-amount, expdest);
7230 }
7231 /* Remove any recorded regions beyond start of variable */
7232 removerecordregions(startloc);
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007233 goto record;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007234 }
7235
7236 end:
7237 if (subtype != VSNORMAL) { /* skip to end of alternative */
7238 int nesting = 1;
7239 for (;;) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01007240 unsigned char c = *p++;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007241 if (c == CTLESC)
7242 p++;
Ron Yorston549deab2015-05-18 09:57:51 +02007243 else if (c == CTLBACKQ) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007244 if (varlen >= 0)
7245 argbackq = argbackq->next;
7246 } else if (c == CTLVAR) {
7247 if ((*p++ & VSTYPE) != VSNORMAL)
7248 nesting++;
7249 } else if (c == CTLENDVAR) {
7250 if (--nesting == 0)
7251 break;
7252 }
7253 }
7254 }
7255 return p;
7256}
7257
7258/*
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007259 * Add a file name to the list.
7260 */
7261static void
7262addfname(const char *name)
7263{
7264 struct strlist *sp;
7265
Denis Vlasenko597906c2008-02-20 16:38:54 +00007266 sp = stzalloc(sizeof(*sp));
Denys Vlasenko8e2bc472016-09-28 23:02:57 +02007267 sp->text = sstrdup(name);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007268 *exparg.lastp = sp;
7269 exparg.lastp = &sp->next;
7270}
7271
Felix Fietkaub5b21122017-01-31 21:58:55 +01007272/* Avoid glob() (and thus, stat() et al) for words like "echo" */
7273static int
7274hasmeta(const char *p)
7275{
7276 static const char chars[] ALIGN1 = {
7277 '*', '?', '[', '\\', CTLQUOTEMARK, CTLESC, 0
7278 };
7279
7280 for (;;) {
7281 p = strpbrk(p, chars);
7282 if (!p)
7283 break;
7284 switch ((unsigned char) *p) {
7285 case CTLQUOTEMARK:
7286 for (;;) {
7287 p++;
7288 if (*p == CTLQUOTEMARK)
7289 break;
7290 if (*p == CTLESC)
7291 p++;
7292 if (*p == '\0') /* huh? */
7293 return 0;
7294 }
7295 break;
7296 case '\\':
7297 case CTLESC:
7298 p++;
7299 if (*p == '\0')
7300 return 0;
7301 break;
7302 case '[':
7303 if (!strchr(p + 1, ']')) {
7304 /* It's not a properly closed [] pattern,
7305 * but other metas may follow. Continue checking.
7306 * my[file* _is_ globbed by bash
7307 * and matches filenames like "my[file1".
7308 */
7309 break;
7310 }
7311 /* fallthrough */
7312 default:
7313 /* case '*': */
7314 /* case '?': */
7315 return 1;
7316 }
7317 p++;
7318 }
7319
7320 return 0;
7321}
7322
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007323/* If we want to use glob() from libc... */
Denys Vlasenko514b51d2016-10-01 14:33:08 +02007324#if !ENABLE_ASH_INTERNAL_GLOB
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007325
7326/* Add the result of glob() to the list */
7327static void
7328addglob(const glob_t *pglob)
7329{
7330 char **p = pglob->gl_pathv;
7331
7332 do {
7333 addfname(*p);
7334 } while (*++p);
7335}
7336static void
7337expandmeta(struct strlist *str /*, int flag*/)
7338{
7339 /* TODO - EXP_REDIR */
7340
7341 while (str) {
7342 char *p;
7343 glob_t pglob;
7344 int i;
7345
7346 if (fflag)
7347 goto nometa;
Denys Vlasenkod4f3db92016-10-30 18:41:01 +01007348
Felix Fietkaub5b21122017-01-31 21:58:55 +01007349 if (!hasmeta(str->text))
7350 goto nometa;
Denys Vlasenkod4f3db92016-10-30 18:41:01 +01007351
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007352 INT_OFF;
7353 p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP);
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007354// GLOB_NOMAGIC (GNU): if no *?[ chars in pattern, return it even if no match
7355// GLOB_NOCHECK: if no match, return unchanged pattern (sans \* escapes?)
7356//
7357// glibc 2.24.90 glob(GLOB_NOMAGIC) does not remove backslashes used for escaping:
7358// if you pass it "file\?", it returns "file\?", not "file?", if no match.
7359// Which means you need to unescape the string, right? Not so fast:
7360// if there _is_ a file named "file\?" (with backslash), it is returned
7361// as "file\?" too (whichever pattern you used to find it, say, "file*").
Denys Vlasenko10ad6222017-04-17 16:13:32 +02007362// You DON'T KNOW by looking at the result whether you need to unescape it.
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007363//
7364// Worse, globbing of "file\?" in a directory with two files, "file?" and "file\?",
7365// returns "file\?" - which is WRONG: "file\?" pattern matches "file?" file.
7366// Without GLOB_NOMAGIC, this works correctly ("file?" is returned as a match).
7367// With GLOB_NOMAGIC | GLOB_NOCHECK, this also works correctly.
7368// i = glob(p, GLOB_NOMAGIC | GLOB_NOCHECK, NULL, &pglob);
7369// i = glob(p, GLOB_NOMAGIC, NULL, &pglob);
7370 i = glob(p, 0, NULL, &pglob);
7371 //bb_error_msg("glob('%s'):%d '%s'...", p, i, pglob.gl_pathv ? pglob.gl_pathv[0] : "-");
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007372 if (p != str->text)
7373 free(p);
7374 switch (i) {
7375 case 0:
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007376#if 0 // glibc 2.24.90 bug? Patterns like "*/file", when match, don't set GLOB_MAGCHAR
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007377 /* GLOB_MAGCHAR is set if *?[ chars were seen (GNU) */
7378 if (!(pglob.gl_flags & GLOB_MAGCHAR))
7379 goto nometa2;
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007380#endif
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007381 addglob(&pglob);
7382 globfree(&pglob);
7383 INT_ON;
7384 break;
7385 case GLOB_NOMATCH:
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007386 //nometa2:
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007387 globfree(&pglob);
7388 INT_ON;
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007389 nometa:
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007390 *exparg.lastp = str;
7391 rmescapes(str->text, 0);
7392 exparg.lastp = &str->next;
7393 break;
7394 default: /* GLOB_NOSPACE */
7395 globfree(&pglob);
7396 INT_ON;
7397 ash_msg_and_raise_error(bb_msg_memory_exhausted);
7398 }
7399 str = str->next;
7400 }
7401}
7402
7403#else
Denys Vlasenko514b51d2016-10-01 14:33:08 +02007404/* ENABLE_ASH_INTERNAL_GLOB: Homegrown globbing code. (dash also has both, uses homegrown one.) */
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007405
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007406/*
7407 * Do metacharacter (i.e. *, ?, [...]) expansion.
7408 */
7409static void
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007410expmeta(char *expdir, char *enddir, char *name)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007411{
7412 char *p;
7413 const char *cp;
7414 char *start;
7415 char *endname;
7416 int metaflag;
7417 struct stat statb;
7418 DIR *dirp;
7419 struct dirent *dp;
7420 int atend;
7421 int matchdot;
Ron Yorstonca25af92015-09-04 10:32:41 +01007422 int esc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007423
7424 metaflag = 0;
7425 start = name;
Ron Yorstonca25af92015-09-04 10:32:41 +01007426 for (p = name; esc = 0, *p; p += esc + 1) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007427 if (*p == '*' || *p == '?')
7428 metaflag = 1;
7429 else if (*p == '[') {
7430 char *q = p + 1;
7431 if (*q == '!')
7432 q++;
7433 for (;;) {
7434 if (*q == '\\')
7435 q++;
7436 if (*q == '/' || *q == '\0')
7437 break;
7438 if (*++q == ']') {
7439 metaflag = 1;
7440 break;
7441 }
7442 }
Ron Yorstonca25af92015-09-04 10:32:41 +01007443 } else {
7444 if (*p == '\\')
7445 esc++;
7446 if (p[esc] == '/') {
7447 if (metaflag)
7448 break;
7449 start = p + esc + 1;
7450 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007451 }
7452 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007453 if (metaflag == 0) { /* we've reached the end of the file name */
7454 if (enddir != expdir)
7455 metaflag++;
7456 p = name;
7457 do {
7458 if (*p == '\\')
7459 p++;
7460 *enddir++ = *p;
7461 } while (*p++);
7462 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
7463 addfname(expdir);
7464 return;
7465 }
7466 endname = p;
7467 if (name < start) {
7468 p = name;
7469 do {
7470 if (*p == '\\')
7471 p++;
7472 *enddir++ = *p++;
7473 } while (p < start);
7474 }
7475 if (enddir == expdir) {
7476 cp = ".";
7477 } else if (enddir == expdir + 1 && *expdir == '/') {
7478 cp = "/";
7479 } else {
7480 cp = expdir;
7481 enddir[-1] = '\0';
7482 }
7483 dirp = opendir(cp);
7484 if (dirp == NULL)
7485 return;
7486 if (enddir != expdir)
7487 enddir[-1] = '/';
7488 if (*endname == 0) {
7489 atend = 1;
7490 } else {
7491 atend = 0;
Ron Yorstonca25af92015-09-04 10:32:41 +01007492 *endname = '\0';
7493 endname += esc + 1;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007494 }
7495 matchdot = 0;
7496 p = start;
7497 if (*p == '\\')
7498 p++;
7499 if (*p == '.')
7500 matchdot++;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02007501 while (!pending_int && (dp = readdir(dirp)) != NULL) {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00007502 if (dp->d_name[0] == '.' && !matchdot)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007503 continue;
7504 if (pmatch(start, dp->d_name)) {
7505 if (atend) {
7506 strcpy(enddir, dp->d_name);
7507 addfname(expdir);
7508 } else {
7509 for (p = enddir, cp = dp->d_name; (*p++ = *cp++) != '\0';)
7510 continue;
7511 p[-1] = '/';
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007512 expmeta(expdir, p, endname);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007513 }
7514 }
7515 }
7516 closedir(dirp);
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00007517 if (!atend)
Ron Yorstonca25af92015-09-04 10:32:41 +01007518 endname[-esc - 1] = esc ? '\\' : '/';
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007519}
7520
7521static struct strlist *
7522msort(struct strlist *list, int len)
7523{
7524 struct strlist *p, *q = NULL;
7525 struct strlist **lpp;
7526 int half;
7527 int n;
7528
7529 if (len <= 1)
7530 return list;
7531 half = len >> 1;
7532 p = list;
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +00007533 for (n = half; --n >= 0;) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007534 q = p;
7535 p = p->next;
7536 }
7537 q->next = NULL; /* terminate first half of list */
7538 q = msort(list, half); /* sort first half of list */
7539 p = msort(p, len - half); /* sort second half */
7540 lpp = &list;
7541 for (;;) {
7542#if ENABLE_LOCALE_SUPPORT
7543 if (strcoll(p->text, q->text) < 0)
7544#else
7545 if (strcmp(p->text, q->text) < 0)
7546#endif
7547 {
7548 *lpp = p;
7549 lpp = &p->next;
7550 p = *lpp;
7551 if (p == NULL) {
7552 *lpp = q;
7553 break;
7554 }
7555 } else {
7556 *lpp = q;
7557 lpp = &q->next;
7558 q = *lpp;
7559 if (q == NULL) {
7560 *lpp = p;
7561 break;
7562 }
7563 }
7564 }
7565 return list;
7566}
7567
7568/*
7569 * Sort the results of file name expansion. It calculates the number of
7570 * strings to sort and then calls msort (short for merge sort) to do the
7571 * work.
7572 */
7573static struct strlist *
7574expsort(struct strlist *str)
7575{
7576 int len;
7577 struct strlist *sp;
7578
7579 len = 0;
7580 for (sp = str; sp; sp = sp->next)
7581 len++;
7582 return msort(str, len);
7583}
7584
7585static void
Denis Vlasenko68404f12008-03-17 09:00:54 +00007586expandmeta(struct strlist *str /*, int flag*/)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007587{
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007588 /* TODO - EXP_REDIR */
7589
7590 while (str) {
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007591 char *expdir;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007592 struct strlist **savelastp;
7593 struct strlist *sp;
7594 char *p;
7595
7596 if (fflag)
7597 goto nometa;
Felix Fietkaub5b21122017-01-31 21:58:55 +01007598 if (!hasmeta(str->text))
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007599 goto nometa;
7600 savelastp = exparg.lastp;
7601
7602 INT_OFF;
Ron Yorston549deab2015-05-18 09:57:51 +02007603 p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007604 {
7605 int i = strlen(str->text);
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007606//BUGGY estimation of how long expanded name can be
7607 expdir = ckmalloc(i < 2048 ? 2048 : i+1);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007608 }
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007609 expmeta(expdir, expdir, p);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007610 free(expdir);
7611 if (p != str->text)
7612 free(p);
7613 INT_ON;
7614 if (exparg.lastp == savelastp) {
7615 /*
7616 * no matches
7617 */
7618 nometa:
7619 *exparg.lastp = str;
Denys Vlasenkob6c84342009-08-29 20:23:20 +02007620 rmescapes(str->text, 0);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007621 exparg.lastp = &str->next;
7622 } else {
7623 *exparg.lastp = NULL;
7624 *savelastp = sp = expsort(*savelastp);
7625 while (sp->next != NULL)
7626 sp = sp->next;
7627 exparg.lastp = &sp->next;
7628 }
7629 str = str->next;
7630 }
7631}
Denys Vlasenko514b51d2016-10-01 14:33:08 +02007632#endif /* ENABLE_ASH_INTERNAL_GLOB */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007633
7634/*
7635 * Perform variable substitution and command substitution on an argument,
7636 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
7637 * perform splitting and file name expansion. When arglist is NULL, perform
7638 * here document expansion.
7639 */
7640static void
7641expandarg(union node *arg, struct arglist *arglist, int flag)
7642{
7643 struct strlist *sp;
7644 char *p;
7645
7646 argbackq = arg->narg.backquote;
7647 STARTSTACKSTR(expdest);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02007648 TRACE(("expandarg: argstr('%s',flags:%x)\n", arg->narg.text, flag));
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02007649 argstr(arg->narg.text, flag);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007650 p = _STPUTC('\0', expdest);
7651 expdest = p - 1;
7652 if (arglist == NULL) {
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02007653 /* here document expanded */
7654 goto out;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007655 }
7656 p = grabstackstr(p);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02007657 TRACE(("expandarg: p:'%s'\n", p));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007658 exparg.lastp = &exparg.list;
7659 /*
7660 * TODO - EXP_REDIR
7661 */
7662 if (flag & EXP_FULL) {
7663 ifsbreakup(p, &exparg);
7664 *exparg.lastp = NULL;
7665 exparg.lastp = &exparg.list;
Denis Vlasenko68404f12008-03-17 09:00:54 +00007666 expandmeta(exparg.list /*, flag*/);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007667 } else {
Denis Vlasenko597906c2008-02-20 16:38:54 +00007668 sp = stzalloc(sizeof(*sp));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007669 sp->text = p;
7670 *exparg.lastp = sp;
7671 exparg.lastp = &sp->next;
7672 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007673 *exparg.lastp = NULL;
7674 if (exparg.list) {
7675 *arglist->lastp = exparg.list;
7676 arglist->lastp = exparg.lastp;
7677 }
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02007678
7679 out:
7680 ifsfree();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007681}
7682
7683/*
7684 * Expand shell variables and backquotes inside a here document.
7685 */
7686static void
7687expandhere(union node *arg, int fd)
7688{
Ron Yorston549deab2015-05-18 09:57:51 +02007689 expandarg(arg, (struct arglist *)NULL, EXP_QUOTED);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007690 full_write(fd, stackblock(), expdest - (char *)stackblock());
7691}
7692
7693/*
7694 * Returns true if the pattern matches the string.
7695 */
7696static int
7697patmatch(char *pattern, const char *string)
7698{
Denys Vlasenkobd43c672017-07-05 23:12:15 +02007699 char *p = preglob(pattern, 0);
Denys Vlasenko4476c702017-08-15 15:27:41 +02007700 int r = pmatch(p, string);
7701 //bb_error_msg("!fnmatch(pattern:'%s',str:'%s',0):%d", p, string, r);
7702 return r;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007703}
7704
7705/*
7706 * See if a pattern matches in a case statement.
7707 */
7708static int
7709casematch(union node *pattern, char *val)
7710{
7711 struct stackmark smark;
7712 int result;
7713
7714 setstackmark(&smark);
7715 argbackq = pattern->narg.backquote;
7716 STARTSTACKSTR(expdest);
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02007717 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007718 STACKSTRNUL(expdest);
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02007719 ifsfree();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007720 result = patmatch(stackblock(), val);
7721 popstackmark(&smark);
7722 return result;
7723}
7724
7725
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007726/* ============ find_command */
7727
7728struct builtincmd {
7729 const char *name;
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02007730 int (*builtin)(int, char **) FAST_FUNC;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007731 /* unsigned flags; */
7732};
7733#define IS_BUILTIN_SPECIAL(b) ((b)->name[0] & 1)
Denis Vlasenkoe26b2782008-02-12 07:40:29 +00007734/* "regular" builtins always take precedence over commands,
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007735 * regardless of PATH=....%builtin... position */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007736#define IS_BUILTIN_REGULAR(b) ((b)->name[0] & 2)
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007737#define IS_BUILTIN_ASSIGN(b) ((b)->name[0] & 4)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007738
7739struct cmdentry {
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00007740 smallint cmdtype; /* CMDxxx */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007741 union param {
7742 int index;
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00007743 /* index >= 0 for commands without path (slashes) */
7744 /* (TODO: what exactly does the value mean? PATH position?) */
7745 /* index == -1 for commands with slashes */
7746 /* index == (-2 - applet_no) for NOFORK applets */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007747 const struct builtincmd *cmd;
7748 struct funcnode *func;
7749 } u;
7750};
7751/* values of cmdtype */
7752#define CMDUNKNOWN -1 /* no entry in table for command */
7753#define CMDNORMAL 0 /* command is an executable program */
7754#define CMDFUNCTION 1 /* command is a shell function */
7755#define CMDBUILTIN 2 /* command is a shell builtin */
7756
7757/* action to find_command() */
7758#define DO_ERR 0x01 /* prints errors */
7759#define DO_ABS 0x02 /* checks absolute paths */
7760#define DO_NOFUNC 0x04 /* don't return shell functions, for command */
7761#define DO_ALTPATH 0x08 /* using alternate path */
7762#define DO_ALTBLTIN 0x20 /* %builtin in alt. path */
7763
7764static void find_command(char *, struct cmdentry *, int, const char *);
7765
7766
7767/* ============ Hashing commands */
7768
7769/*
7770 * When commands are first encountered, they are entered in a hash table.
7771 * This ensures that a full path search will not have to be done for them
7772 * on each invocation.
7773 *
7774 * We should investigate converting to a linear search, even though that
7775 * would make the command name "hash" a misnomer.
7776 */
7777
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007778struct tblentry {
7779 struct tblentry *next; /* next entry in hash chain */
7780 union param param; /* definition of builtin function */
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00007781 smallint cmdtype; /* CMDxxx */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007782 char rehash; /* if set, cd done since entry created */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00007783 char cmdname[1]; /* name of command */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007784};
7785
Denis Vlasenko01631112007-12-16 17:20:38 +00007786static struct tblentry **cmdtable;
7787#define INIT_G_cmdtable() do { \
7788 cmdtable = xzalloc(CMDTABLESIZE * sizeof(cmdtable[0])); \
7789} while (0)
7790
7791static int builtinloc = -1; /* index in path of %builtin, or -1 */
7792
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007793
7794static void
Denys Vlasenko00a1dbd2017-07-29 01:20:53 +02007795tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) const char *cmd, char **argv, char **envp)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007796{
Denis Vlasenko80d14be2007-04-10 23:03:30 +00007797#if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007798 if (applet_no >= 0) {
Denis Vlasenkob7304742008-10-20 08:15:51 +00007799 if (APPLET_IS_NOEXEC(applet_no)) {
Denys Vlasenko7df28bb2010-06-18 14:23:47 +02007800 clearenv();
Denis Vlasenkob7304742008-10-20 08:15:51 +00007801 while (*envp)
7802 putenv(*envp++);
Denys Vlasenko035486c2017-07-31 04:09:19 +02007803 popredir(/*drop:*/ 1);
Denys Vlasenko80e8e3c2017-08-07 19:24:57 +02007804 run_noexec_applet_and_exit(applet_no, cmd, argv);
Denis Vlasenkob7304742008-10-20 08:15:51 +00007805 }
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007806 /* re-exec ourselves with the new arguments */
7807 execve(bb_busybox_exec_path, argv, envp);
7808 /* If they called chroot or otherwise made the binary no longer
7809 * executable, fall through */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007810 }
7811#endif
7812
7813 repeat:
7814#ifdef SYSV
7815 do {
7816 execve(cmd, argv, envp);
7817 } while (errno == EINTR);
7818#else
7819 execve(cmd, argv, envp);
7820#endif
Denys Vlasenko00a1dbd2017-07-29 01:20:53 +02007821 if (cmd != bb_busybox_exec_path && errno == ENOEXEC) {
Denys Vlasenkoaefe1c22011-03-07 12:02:40 +01007822 /* Run "cmd" as a shell script:
7823 * http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html
7824 * "If the execve() function fails with ENOEXEC, the shell
7825 * shall execute a command equivalent to having a shell invoked
7826 * with the command name as its first operand,
7827 * with any remaining arguments passed to the new shell"
7828 *
7829 * That is, do not use $SHELL, user's shell, or /bin/sh;
7830 * just call ourselves.
Denys Vlasenko2bef5262011-12-16 00:25:17 +01007831 *
7832 * Note that bash reads ~80 chars of the file, and if it sees
7833 * a zero byte before it sees newline, it doesn't try to
7834 * interpret it, but fails with "cannot execute binary file"
Denys Vlasenkocda6ea92011-12-16 00:44:36 +01007835 * message and exit code 126. For one, this prevents attempts
7836 * to interpret foreign ELF binaries as shell scripts.
Denys Vlasenkoaefe1c22011-03-07 12:02:40 +01007837 */
Denys Vlasenko00a1dbd2017-07-29 01:20:53 +02007838 argv[0] = (char*) cmd;
7839 cmd = bb_busybox_exec_path;
Denys Vlasenko65a8b852016-10-26 22:29:11 +02007840 /* NB: this is only possible because all callers of shellexec()
7841 * ensure that the argv[-1] slot exists!
7842 */
7843 argv--;
7844 argv[0] = (char*) "ash";
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007845 goto repeat;
7846 }
7847}
7848
7849/*
7850 * Exec a program. Never returns. If you change this routine, you may
7851 * have to change the find_command routine as well.
Denys Vlasenko65a8b852016-10-26 22:29:11 +02007852 * argv[-1] must exist and be writable! See tryexec() for why.
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007853 */
Denys Vlasenkoe139ae32017-04-12 21:02:33 +02007854static void shellexec(char *prog, char **argv, const char *path, int idx) NORETURN;
7855static void shellexec(char *prog, char **argv, const char *path, int idx)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007856{
7857 char *cmdname;
7858 int e;
7859 char **envp;
7860 int exerrno;
Denys Vlasenko83f103b2011-12-20 06:10:35 +01007861 int applet_no = -1; /* used only by FEATURE_SH_STANDALONE */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007862
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +02007863 envp = listvars(VEXPORT, VUNSET, /*end:*/ NULL);
Denys Vlasenkoe139ae32017-04-12 21:02:33 +02007864 if (strchr(prog, '/') != NULL
Denis Vlasenko80d14be2007-04-10 23:03:30 +00007865#if ENABLE_FEATURE_SH_STANDALONE
Denys Vlasenkoe139ae32017-04-12 21:02:33 +02007866 || (applet_no = find_applet_by_name(prog)) >= 0
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007867#endif
7868 ) {
Denys Vlasenkoe139ae32017-04-12 21:02:33 +02007869 tryexec(IF_FEATURE_SH_STANDALONE(applet_no,) prog, argv, envp);
Denys Vlasenko83f103b2011-12-20 06:10:35 +01007870 if (applet_no >= 0) {
7871 /* We tried execing ourself, but it didn't work.
7872 * Maybe /proc/self/exe doesn't exist?
7873 * Try $PATH search.
7874 */
7875 goto try_PATH;
7876 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007877 e = errno;
7878 } else {
Denys Vlasenko83f103b2011-12-20 06:10:35 +01007879 try_PATH:
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007880 e = ENOENT;
Denys Vlasenkoe139ae32017-04-12 21:02:33 +02007881 while ((cmdname = path_advance(&path, prog)) != NULL) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007882 if (--idx < 0 && pathopt == NULL) {
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00007883 tryexec(IF_FEATURE_SH_STANDALONE(-1,) cmdname, argv, envp);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007884 if (errno != ENOENT && errno != ENOTDIR)
7885 e = errno;
7886 }
7887 stunalloc(cmdname);
7888 }
7889 }
7890
7891 /* Map to POSIX errors */
7892 switch (e) {
7893 case EACCES:
7894 exerrno = 126;
7895 break;
7896 case ENOENT:
7897 exerrno = 127;
7898 break;
7899 default:
7900 exerrno = 2;
7901 break;
7902 }
7903 exitstatus = exerrno;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02007904 TRACE(("shellexec failed for %s, errno %d, suppress_int %d\n",
Denys Vlasenkoe139ae32017-04-12 21:02:33 +02007905 prog, e, suppress_int));
7906 ash_msg_and_raise(EXEXIT, "%s: %s", prog, errmsg(e, "not found"));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007907 /* NOTREACHED */
7908}
7909
7910static void
7911printentry(struct tblentry *cmdp)
7912{
7913 int idx;
7914 const char *path;
7915 char *name;
7916
7917 idx = cmdp->param.index;
7918 path = pathval();
7919 do {
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02007920 name = path_advance(&path, cmdp->cmdname);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007921 stunalloc(name);
7922 } while (--idx >= 0);
7923 out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr));
7924}
7925
7926/*
7927 * Clear out command entries. The argument specifies the first entry in
7928 * PATH which has changed.
7929 */
7930static void
7931clearcmdentry(int firstchange)
7932{
7933 struct tblentry **tblp;
7934 struct tblentry **pp;
7935 struct tblentry *cmdp;
7936
7937 INT_OFF;
7938 for (tblp = cmdtable; tblp < &cmdtable[CMDTABLESIZE]; tblp++) {
7939 pp = tblp;
7940 while ((cmdp = *pp) != NULL) {
7941 if ((cmdp->cmdtype == CMDNORMAL &&
7942 cmdp->param.index >= firstchange)
7943 || (cmdp->cmdtype == CMDBUILTIN &&
7944 builtinloc >= firstchange)
7945 ) {
7946 *pp = cmdp->next;
7947 free(cmdp);
7948 } else {
7949 pp = &cmdp->next;
7950 }
7951 }
7952 }
7953 INT_ON;
7954}
7955
7956/*
7957 * Locate a command in the command hash table. If "add" is nonzero,
7958 * add the command to the table if it is not already present. The
7959 * variable "lastcmdentry" is set to point to the address of the link
7960 * pointing to the entry, so that delete_cmd_entry can delete the
7961 * entry.
7962 *
7963 * Interrupts must be off if called with add != 0.
7964 */
7965static struct tblentry **lastcmdentry;
7966
7967static struct tblentry *
7968cmdlookup(const char *name, int add)
7969{
7970 unsigned int hashval;
7971 const char *p;
7972 struct tblentry *cmdp;
7973 struct tblentry **pp;
7974
7975 p = name;
7976 hashval = (unsigned char)*p << 4;
7977 while (*p)
7978 hashval += (unsigned char)*p++;
7979 hashval &= 0x7FFF;
7980 pp = &cmdtable[hashval % CMDTABLESIZE];
7981 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
7982 if (strcmp(cmdp->cmdname, name) == 0)
7983 break;
7984 pp = &cmdp->next;
7985 }
7986 if (add && cmdp == NULL) {
Denis Vlasenkob07a4962008-06-22 13:16:23 +00007987 cmdp = *pp = ckzalloc(sizeof(struct tblentry)
7988 + strlen(name)
7989 /* + 1 - already done because
7990 * tblentry::cmdname is char[1] */);
Denis Vlasenko597906c2008-02-20 16:38:54 +00007991 /*cmdp->next = NULL; - ckzalloc did it */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007992 cmdp->cmdtype = CMDUNKNOWN;
7993 strcpy(cmdp->cmdname, name);
7994 }
7995 lastcmdentry = pp;
7996 return cmdp;
7997}
7998
7999/*
8000 * Delete the command entry returned on the last lookup.
8001 */
8002static void
8003delete_cmd_entry(void)
8004{
8005 struct tblentry *cmdp;
8006
8007 INT_OFF;
8008 cmdp = *lastcmdentry;
8009 *lastcmdentry = cmdp->next;
8010 if (cmdp->cmdtype == CMDFUNCTION)
8011 freefunc(cmdp->param.func);
8012 free(cmdp);
8013 INT_ON;
8014}
8015
8016/*
8017 * Add a new command entry, replacing any existing command entry for
8018 * the same name - except special builtins.
8019 */
8020static void
8021addcmdentry(char *name, struct cmdentry *entry)
8022{
8023 struct tblentry *cmdp;
8024
8025 cmdp = cmdlookup(name, 1);
8026 if (cmdp->cmdtype == CMDFUNCTION) {
8027 freefunc(cmdp->param.func);
8028 }
8029 cmdp->cmdtype = entry->cmdtype;
8030 cmdp->param = entry->u;
8031 cmdp->rehash = 0;
8032}
8033
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02008034static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00008035hashcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008036{
8037 struct tblentry **pp;
8038 struct tblentry *cmdp;
8039 int c;
8040 struct cmdentry entry;
8041 char *name;
8042
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008043 if (nextopt("r") != '\0') {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008044 clearcmdentry(0);
8045 return 0;
8046 }
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008047
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008048 if (*argptr == NULL) {
8049 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
8050 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
8051 if (cmdp->cmdtype == CMDNORMAL)
8052 printentry(cmdp);
8053 }
8054 }
8055 return 0;
8056 }
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008057
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008058 c = 0;
8059 while ((name = *argptr) != NULL) {
8060 cmdp = cmdlookup(name, 0);
8061 if (cmdp != NULL
8062 && (cmdp->cmdtype == CMDNORMAL
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008063 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))
8064 ) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008065 delete_cmd_entry();
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008066 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008067 find_command(name, &entry, DO_ERR, pathval());
8068 if (entry.cmdtype == CMDUNKNOWN)
8069 c = 1;
8070 argptr++;
8071 }
8072 return c;
8073}
8074
8075/*
8076 * Called when a cd is done. Marks all commands so the next time they
8077 * are executed they will be rehashed.
8078 */
8079static void
8080hashcd(void)
8081{
8082 struct tblentry **pp;
8083 struct tblentry *cmdp;
8084
8085 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
8086 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008087 if (cmdp->cmdtype == CMDNORMAL
8088 || (cmdp->cmdtype == CMDBUILTIN
Denys Vlasenkoe4dcba12010-10-28 18:57:19 +02008089 && !IS_BUILTIN_REGULAR(cmdp->param.cmd)
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008090 && builtinloc > 0)
8091 ) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008092 cmdp->rehash = 1;
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008093 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008094 }
8095 }
8096}
8097
8098/*
8099 * Fix command hash table when PATH changed.
8100 * Called before PATH is changed. The argument is the new value of PATH;
8101 * pathval() still returns the old value at this point.
8102 * Called with interrupts off.
8103 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02008104static void FAST_FUNC
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008105changepath(const char *new)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008106{
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008107 const char *old;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008108 int firstchange;
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008109 int idx;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008110 int idx_bltin;
8111
8112 old = pathval();
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008113 firstchange = 9999; /* assume no change */
8114 idx = 0;
8115 idx_bltin = -1;
8116 for (;;) {
8117 if (*old != *new) {
8118 firstchange = idx;
8119 if ((*old == '\0' && *new == ':')
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +02008120 || (*old == ':' && *new == '\0')
8121 ) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008122 firstchange++;
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +02008123 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008124 old = new; /* ignore subsequent differences */
8125 }
8126 if (*new == '\0')
8127 break;
8128 if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin"))
8129 idx_bltin = idx;
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008130 if (*new == ':')
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008131 idx++;
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +02008132 new++;
8133 old++;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008134 }
8135 if (builtinloc < 0 && idx_bltin >= 0)
8136 builtinloc = idx_bltin; /* zap builtins */
8137 if (builtinloc >= 0 && idx_bltin < 0)
8138 firstchange = 0;
8139 clearcmdentry(firstchange);
8140 builtinloc = idx_bltin;
8141}
Ron Yorston95ebcf72015-11-03 09:42:23 +00008142enum {
8143 TEOF,
8144 TNL,
8145 TREDIR,
8146 TWORD,
8147 TSEMI,
8148 TBACKGND,
8149 TAND,
8150 TOR,
8151 TPIPE,
8152 TLP,
8153 TRP,
8154 TENDCASE,
8155 TENDBQUOTE,
8156 TNOT,
8157 TCASE,
8158 TDO,
8159 TDONE,
8160 TELIF,
8161 TELSE,
8162 TESAC,
8163 TFI,
8164 TFOR,
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01008165#if BASH_FUNCTION
Ron Yorston95ebcf72015-11-03 09:42:23 +00008166 TFUNCTION,
8167#endif
8168 TIF,
8169 TIN,
8170 TTHEN,
8171 TUNTIL,
8172 TWHILE,
8173 TBEGIN,
8174 TEND
8175};
Denis Vlasenkob07a4962008-06-22 13:16:23 +00008176typedef smallint token_id_t;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008177
Denys Vlasenko888527c2016-10-02 16:54:17 +02008178/* Nth bit indicates if token marks the end of a list */
8179enum {
8180 tokendlist = 0
8181 /* 0 */ | (1u << TEOF)
8182 /* 1 */ | (0u << TNL)
8183 /* 2 */ | (0u << TREDIR)
8184 /* 3 */ | (0u << TWORD)
8185 /* 4 */ | (0u << TSEMI)
8186 /* 5 */ | (0u << TBACKGND)
8187 /* 6 */ | (0u << TAND)
8188 /* 7 */ | (0u << TOR)
8189 /* 8 */ | (0u << TPIPE)
8190 /* 9 */ | (0u << TLP)
8191 /* 10 */ | (1u << TRP)
8192 /* 11 */ | (1u << TENDCASE)
8193 /* 12 */ | (1u << TENDBQUOTE)
8194 /* 13 */ | (0u << TNOT)
8195 /* 14 */ | (0u << TCASE)
8196 /* 15 */ | (1u << TDO)
8197 /* 16 */ | (1u << TDONE)
8198 /* 17 */ | (1u << TELIF)
8199 /* 18 */ | (1u << TELSE)
8200 /* 19 */ | (1u << TESAC)
8201 /* 20 */ | (1u << TFI)
8202 /* 21 */ | (0u << TFOR)
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01008203#if BASH_FUNCTION
Denys Vlasenko888527c2016-10-02 16:54:17 +02008204 /* 22 */ | (0u << TFUNCTION)
Denys Vlasenko80729a42016-10-02 22:33:15 +02008205#endif
Denys Vlasenko888527c2016-10-02 16:54:17 +02008206 /* 23 */ | (0u << TIF)
8207 /* 24 */ | (0u << TIN)
8208 /* 25 */ | (1u << TTHEN)
8209 /* 26 */ | (0u << TUNTIL)
8210 /* 27 */ | (0u << TWHILE)
8211 /* 28 */ | (0u << TBEGIN)
8212 /* 29 */ | (1u << TEND)
8213 , /* thus far 29 bits used */
8214};
8215
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008216static const char *const tokname_array[] = {
Denys Vlasenko888527c2016-10-02 16:54:17 +02008217 "end of file",
8218 "newline",
8219 "redirection",
8220 "word",
8221 ";",
8222 "&",
8223 "&&",
8224 "||",
8225 "|",
8226 "(",
8227 ")",
8228 ";;",
8229 "`",
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008230#define KWDOFFSET 13
8231 /* the following are keywords */
Denys Vlasenko888527c2016-10-02 16:54:17 +02008232 "!",
8233 "case",
8234 "do",
8235 "done",
8236 "elif",
8237 "else",
8238 "esac",
8239 "fi",
8240 "for",
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01008241#if BASH_FUNCTION
Denys Vlasenko888527c2016-10-02 16:54:17 +02008242 "function",
Ron Yorston95ebcf72015-11-03 09:42:23 +00008243#endif
Denys Vlasenko888527c2016-10-02 16:54:17 +02008244 "if",
8245 "in",
8246 "then",
8247 "until",
8248 "while",
8249 "{",
8250 "}",
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008251};
8252
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008253/* Wrapper around strcmp for qsort/bsearch/... */
8254static int
8255pstrcmp(const void *a, const void *b)
8256{
Denys Vlasenko888527c2016-10-02 16:54:17 +02008257 return strcmp((char*)a, *(char**)b);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008258}
8259
8260static const char *const *
8261findkwd(const char *s)
8262{
8263 return bsearch(s, tokname_array + KWDOFFSET,
Denis Vlasenko80b8b392007-06-25 10:55:35 +00008264 ARRAY_SIZE(tokname_array) - KWDOFFSET,
8265 sizeof(tokname_array[0]), pstrcmp);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008266}
8267
8268/*
8269 * Locate and print what a word is...
8270 */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008271static int
Ron Yorston3f221112015-08-03 13:47:33 +01008272describe_command(char *command, const char *path, int describe_command_verbose)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008273{
8274 struct cmdentry entry;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008275#if ENABLE_ASH_ALIAS
8276 const struct alias *ap;
8277#endif
Ron Yorston3f221112015-08-03 13:47:33 +01008278
8279 path = path ? path : pathval();
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008280
8281 if (describe_command_verbose) {
8282 out1str(command);
8283 }
8284
8285 /* First look at the keywords */
8286 if (findkwd(command)) {
8287 out1str(describe_command_verbose ? " is a shell keyword" : command);
8288 goto out;
8289 }
8290
8291#if ENABLE_ASH_ALIAS
8292 /* Then look at the aliases */
8293 ap = lookupalias(command, 0);
8294 if (ap != NULL) {
Denis Vlasenko46846e22007-05-20 13:08:31 +00008295 if (!describe_command_verbose) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008296 out1str("alias ");
8297 printalias(ap);
8298 return 0;
8299 }
Denis Vlasenko46846e22007-05-20 13:08:31 +00008300 out1fmt(" is an alias for %s", ap->val);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008301 goto out;
8302 }
8303#endif
Youfu Zhang6683d1c2017-05-26 15:31:29 +08008304 /* Brute force */
8305 find_command(command, &entry, DO_ABS, path);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008306
8307 switch (entry.cmdtype) {
8308 case CMDNORMAL: {
8309 int j = entry.u.index;
8310 char *p;
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00008311 if (j < 0) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008312 p = command;
8313 } else {
8314 do {
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02008315 p = path_advance(&path, command);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008316 stunalloc(p);
8317 } while (--j >= 0);
8318 }
8319 if (describe_command_verbose) {
Youfu Zhang6683d1c2017-05-26 15:31:29 +08008320 out1fmt(" is %s", p);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008321 } else {
8322 out1str(p);
8323 }
8324 break;
8325 }
8326
8327 case CMDFUNCTION:
8328 if (describe_command_verbose) {
8329 out1str(" is a shell function");
8330 } else {
8331 out1str(command);
8332 }
8333 break;
8334
8335 case CMDBUILTIN:
8336 if (describe_command_verbose) {
8337 out1fmt(" is a %sshell builtin",
8338 IS_BUILTIN_SPECIAL(entry.u.cmd) ?
8339 "special " : nullstr
8340 );
8341 } else {
8342 out1str(command);
8343 }
8344 break;
8345
8346 default:
8347 if (describe_command_verbose) {
8348 out1str(": not found\n");
8349 }
8350 return 127;
8351 }
8352 out:
Denys Vlasenko285ad152009-12-04 23:02:27 +01008353 out1str("\n");
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008354 return 0;
8355}
8356
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02008357static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00008358typecmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008359{
Denis Vlasenko46846e22007-05-20 13:08:31 +00008360 int i = 1;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008361 int err = 0;
Denis Vlasenko46846e22007-05-20 13:08:31 +00008362 int verbose = 1;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008363
Denis Vlasenko46846e22007-05-20 13:08:31 +00008364 /* type -p ... ? (we don't bother checking for 'p') */
Denis Vlasenko1fc62382007-06-25 22:55:34 +00008365 if (argv[1] && argv[1][0] == '-') {
Denis Vlasenko46846e22007-05-20 13:08:31 +00008366 i++;
8367 verbose = 0;
8368 }
Denis Vlasenko68404f12008-03-17 09:00:54 +00008369 while (argv[i]) {
Ron Yorston3f221112015-08-03 13:47:33 +01008370 err |= describe_command(argv[i++], NULL, verbose);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008371 }
8372 return err;
8373}
8374
8375#if ENABLE_ASH_CMDCMD
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008376/* Is it "command [-p] PROG ARGS" bltin, no other opts? Return ptr to "PROG" if yes */
8377static char **
8378parse_command_args(char **argv, const char **path)
8379{
8380 char *cp, c;
8381
8382 for (;;) {
8383 cp = *++argv;
8384 if (!cp)
8385 return NULL;
8386 if (*cp++ != '-')
8387 break;
8388 c = *cp++;
8389 if (!c)
8390 break;
8391 if (c == '-' && !*cp) {
8392 if (!*++argv)
8393 return NULL;
8394 break;
8395 }
8396 do {
8397 switch (c) {
8398 case 'p':
8399 *path = bb_default_path;
8400 break;
8401 default:
8402 /* run 'typecmd' for other options */
8403 return NULL;
8404 }
8405 c = *cp++;
8406 } while (c);
8407 }
8408 return argv;
8409}
8410
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02008411static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00008412commandcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008413{
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008414 char *cmd;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008415 int c;
8416 enum {
8417 VERIFY_BRIEF = 1,
8418 VERIFY_VERBOSE = 2,
8419 } verify = 0;
Ron Yorston3f221112015-08-03 13:47:33 +01008420 const char *path = NULL;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008421
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008422 /* "command [-p] PROG ARGS" (that is, without -V or -v)
8423 * never reaches this function.
8424 */
8425
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008426 while ((c = nextopt("pvV")) != '\0')
8427 if (c == 'V')
8428 verify |= VERIFY_VERBOSE;
8429 else if (c == 'v')
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008430 /*verify |= VERIFY_BRIEF*/;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008431#if DEBUG
8432 else if (c != 'p')
8433 abort();
8434#endif
Ron Yorston3f221112015-08-03 13:47:33 +01008435 else
8436 path = bb_default_path;
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008437
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00008438 /* Mimic bash: just "command -v" doesn't complain, it's a nop */
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008439 cmd = *argptr;
8440 if (/*verify && */ cmd)
8441 return describe_command(cmd, path, verify /* - VERIFY_BRIEF*/);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008442
8443 return 0;
8444}
8445#endif
8446
8447
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008448/*static int funcblocksize; // size of structures in function */
8449/*static int funcstringsize; // size of strings in node */
Denis Vlasenko340299a2008-11-21 10:36:36 +00008450static void *funcblock; /* block to allocate function from */
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008451static char *funcstring_end; /* end of block to allocate strings from */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008452
Denys Vlasenko3e134eb2016-04-22 18:09:21 +02008453static const uint8_t nodesize[N_NUMBER] ALIGN1 = {
Denis Vlasenko340299a2008-11-21 10:36:36 +00008454 [NCMD ] = SHELL_ALIGN(sizeof(struct ncmd)),
8455 [NPIPE ] = SHELL_ALIGN(sizeof(struct npipe)),
8456 [NREDIR ] = SHELL_ALIGN(sizeof(struct nredir)),
8457 [NBACKGND ] = SHELL_ALIGN(sizeof(struct nredir)),
8458 [NSUBSHELL] = SHELL_ALIGN(sizeof(struct nredir)),
8459 [NAND ] = SHELL_ALIGN(sizeof(struct nbinary)),
8460 [NOR ] = SHELL_ALIGN(sizeof(struct nbinary)),
8461 [NSEMI ] = SHELL_ALIGN(sizeof(struct nbinary)),
8462 [NIF ] = SHELL_ALIGN(sizeof(struct nif)),
8463 [NWHILE ] = SHELL_ALIGN(sizeof(struct nbinary)),
8464 [NUNTIL ] = SHELL_ALIGN(sizeof(struct nbinary)),
8465 [NFOR ] = SHELL_ALIGN(sizeof(struct nfor)),
8466 [NCASE ] = SHELL_ALIGN(sizeof(struct ncase)),
8467 [NCLIST ] = SHELL_ALIGN(sizeof(struct nclist)),
8468 [NDEFUN ] = SHELL_ALIGN(sizeof(struct narg)),
8469 [NARG ] = SHELL_ALIGN(sizeof(struct narg)),
8470 [NTO ] = SHELL_ALIGN(sizeof(struct nfile)),
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01008471#if BASH_REDIR_OUTPUT
Denis Vlasenko340299a2008-11-21 10:36:36 +00008472 [NTO2 ] = SHELL_ALIGN(sizeof(struct nfile)),
Denis Vlasenkocc5feab2008-11-22 01:32:40 +00008473#endif
Denis Vlasenko340299a2008-11-21 10:36:36 +00008474 [NCLOBBER ] = SHELL_ALIGN(sizeof(struct nfile)),
8475 [NFROM ] = SHELL_ALIGN(sizeof(struct nfile)),
8476 [NFROMTO ] = SHELL_ALIGN(sizeof(struct nfile)),
8477 [NAPPEND ] = SHELL_ALIGN(sizeof(struct nfile)),
8478 [NTOFD ] = SHELL_ALIGN(sizeof(struct ndup)),
8479 [NFROMFD ] = SHELL_ALIGN(sizeof(struct ndup)),
8480 [NHERE ] = SHELL_ALIGN(sizeof(struct nhere)),
8481 [NXHERE ] = SHELL_ALIGN(sizeof(struct nhere)),
8482 [NNOT ] = SHELL_ALIGN(sizeof(struct nnot)),
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008483};
8484
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008485static int calcsize(int funcblocksize, union node *n);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008486
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008487static int
8488sizenodelist(int funcblocksize, struct nodelist *lp)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008489{
8490 while (lp) {
8491 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008492 funcblocksize = calcsize(funcblocksize, lp->n);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008493 lp = lp->next;
8494 }
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008495 return funcblocksize;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008496}
8497
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008498static int
8499calcsize(int funcblocksize, union node *n)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008500{
8501 if (n == NULL)
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008502 return funcblocksize;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008503 funcblocksize += nodesize[n->type];
8504 switch (n->type) {
8505 case NCMD:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008506 funcblocksize = calcsize(funcblocksize, n->ncmd.redirect);
8507 funcblocksize = calcsize(funcblocksize, n->ncmd.args);
8508 funcblocksize = calcsize(funcblocksize, n->ncmd.assign);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008509 break;
8510 case NPIPE:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008511 funcblocksize = sizenodelist(funcblocksize, n->npipe.cmdlist);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008512 break;
8513 case NREDIR:
8514 case NBACKGND:
8515 case NSUBSHELL:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008516 funcblocksize = calcsize(funcblocksize, n->nredir.redirect);
8517 funcblocksize = calcsize(funcblocksize, n->nredir.n);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008518 break;
8519 case NAND:
8520 case NOR:
8521 case NSEMI:
8522 case NWHILE:
8523 case NUNTIL:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008524 funcblocksize = calcsize(funcblocksize, n->nbinary.ch2);
8525 funcblocksize = calcsize(funcblocksize, n->nbinary.ch1);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008526 break;
8527 case NIF:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008528 funcblocksize = calcsize(funcblocksize, n->nif.elsepart);
8529 funcblocksize = calcsize(funcblocksize, n->nif.ifpart);
8530 funcblocksize = calcsize(funcblocksize, n->nif.test);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008531 break;
8532 case NFOR:
Denys Vlasenko561639a2016-10-07 04:28:33 +02008533 funcblocksize += SHELL_ALIGN(strlen(n->nfor.var) + 1); /* was funcstringsize += ... */
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008534 funcblocksize = calcsize(funcblocksize, n->nfor.body);
8535 funcblocksize = calcsize(funcblocksize, n->nfor.args);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008536 break;
8537 case NCASE:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008538 funcblocksize = calcsize(funcblocksize, n->ncase.cases);
8539 funcblocksize = calcsize(funcblocksize, n->ncase.expr);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008540 break;
8541 case NCLIST:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008542 funcblocksize = calcsize(funcblocksize, n->nclist.body);
8543 funcblocksize = calcsize(funcblocksize, n->nclist.pattern);
8544 funcblocksize = calcsize(funcblocksize, n->nclist.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008545 break;
8546 case NDEFUN:
8547 case NARG:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008548 funcblocksize = sizenodelist(funcblocksize, n->narg.backquote);
Denys Vlasenko561639a2016-10-07 04:28:33 +02008549 funcblocksize += SHELL_ALIGN(strlen(n->narg.text) + 1); /* was funcstringsize += ... */
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008550 funcblocksize = calcsize(funcblocksize, n->narg.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008551 break;
8552 case NTO:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01008553#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00008554 case NTO2:
8555#endif
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008556 case NCLOBBER:
8557 case NFROM:
8558 case NFROMTO:
8559 case NAPPEND:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008560 funcblocksize = calcsize(funcblocksize, n->nfile.fname);
8561 funcblocksize = calcsize(funcblocksize, n->nfile.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008562 break;
8563 case NTOFD:
8564 case NFROMFD:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008565 funcblocksize = calcsize(funcblocksize, n->ndup.vname);
8566 funcblocksize = calcsize(funcblocksize, n->ndup.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008567 break;
8568 case NHERE:
8569 case NXHERE:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008570 funcblocksize = calcsize(funcblocksize, n->nhere.doc);
8571 funcblocksize = calcsize(funcblocksize, n->nhere.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008572 break;
8573 case NNOT:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008574 funcblocksize = calcsize(funcblocksize, n->nnot.com);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008575 break;
8576 };
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008577 return funcblocksize;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008578}
8579
8580static char *
8581nodeckstrdup(char *s)
8582{
Denys Vlasenko561639a2016-10-07 04:28:33 +02008583 funcstring_end -= SHELL_ALIGN(strlen(s) + 1);
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008584 return strcpy(funcstring_end, s);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008585}
8586
8587static union node *copynode(union node *);
8588
8589static struct nodelist *
8590copynodelist(struct nodelist *lp)
8591{
8592 struct nodelist *start;
8593 struct nodelist **lpp;
8594
8595 lpp = &start;
8596 while (lp) {
8597 *lpp = funcblock;
8598 funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist));
8599 (*lpp)->n = copynode(lp->n);
8600 lp = lp->next;
8601 lpp = &(*lpp)->next;
8602 }
8603 *lpp = NULL;
8604 return start;
8605}
8606
8607static union node *
8608copynode(union node *n)
8609{
8610 union node *new;
8611
8612 if (n == NULL)
8613 return NULL;
8614 new = funcblock;
8615 funcblock = (char *) funcblock + nodesize[n->type];
8616
8617 switch (n->type) {
8618 case NCMD:
8619 new->ncmd.redirect = copynode(n->ncmd.redirect);
8620 new->ncmd.args = copynode(n->ncmd.args);
8621 new->ncmd.assign = copynode(n->ncmd.assign);
8622 break;
8623 case NPIPE:
8624 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00008625 new->npipe.pipe_backgnd = n->npipe.pipe_backgnd;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008626 break;
8627 case NREDIR:
8628 case NBACKGND:
8629 case NSUBSHELL:
8630 new->nredir.redirect = copynode(n->nredir.redirect);
8631 new->nredir.n = copynode(n->nredir.n);
8632 break;
8633 case NAND:
8634 case NOR:
8635 case NSEMI:
8636 case NWHILE:
8637 case NUNTIL:
8638 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8639 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8640 break;
8641 case NIF:
8642 new->nif.elsepart = copynode(n->nif.elsepart);
8643 new->nif.ifpart = copynode(n->nif.ifpart);
8644 new->nif.test = copynode(n->nif.test);
8645 break;
8646 case NFOR:
8647 new->nfor.var = nodeckstrdup(n->nfor.var);
8648 new->nfor.body = copynode(n->nfor.body);
8649 new->nfor.args = copynode(n->nfor.args);
8650 break;
8651 case NCASE:
8652 new->ncase.cases = copynode(n->ncase.cases);
8653 new->ncase.expr = copynode(n->ncase.expr);
8654 break;
8655 case NCLIST:
8656 new->nclist.body = copynode(n->nclist.body);
8657 new->nclist.pattern = copynode(n->nclist.pattern);
8658 new->nclist.next = copynode(n->nclist.next);
8659 break;
8660 case NDEFUN:
8661 case NARG:
8662 new->narg.backquote = copynodelist(n->narg.backquote);
8663 new->narg.text = nodeckstrdup(n->narg.text);
8664 new->narg.next = copynode(n->narg.next);
8665 break;
8666 case NTO:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01008667#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00008668 case NTO2:
8669#endif
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008670 case NCLOBBER:
8671 case NFROM:
8672 case NFROMTO:
8673 case NAPPEND:
8674 new->nfile.fname = copynode(n->nfile.fname);
8675 new->nfile.fd = n->nfile.fd;
8676 new->nfile.next = copynode(n->nfile.next);
8677 break;
8678 case NTOFD:
8679 case NFROMFD:
8680 new->ndup.vname = copynode(n->ndup.vname);
8681 new->ndup.dupfd = n->ndup.dupfd;
8682 new->ndup.fd = n->ndup.fd;
8683 new->ndup.next = copynode(n->ndup.next);
8684 break;
8685 case NHERE:
8686 case NXHERE:
8687 new->nhere.doc = copynode(n->nhere.doc);
8688 new->nhere.fd = n->nhere.fd;
8689 new->nhere.next = copynode(n->nhere.next);
8690 break;
8691 case NNOT:
8692 new->nnot.com = copynode(n->nnot.com);
8693 break;
8694 };
8695 new->type = n->type;
8696 return new;
8697}
8698
8699/*
8700 * Make a copy of a parse tree.
8701 */
8702static struct funcnode *
8703copyfunc(union node *n)
8704{
8705 struct funcnode *f;
8706 size_t blocksize;
8707
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008708 /*funcstringsize = 0;*/
8709 blocksize = offsetof(struct funcnode, n) + calcsize(0, n);
8710 f = ckzalloc(blocksize /* + funcstringsize */);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008711 funcblock = (char *) f + offsetof(struct funcnode, n);
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008712 funcstring_end = (char *) f + blocksize;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008713 copynode(n);
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008714 /* f->count = 0; - ckzalloc did it */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008715 return f;
8716}
8717
8718/*
8719 * Define a shell function.
8720 */
8721static void
Denys Vlasenko7aec8682016-10-25 20:26:02 +02008722defun(union node *func)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008723{
8724 struct cmdentry entry;
8725
8726 INT_OFF;
8727 entry.cmdtype = CMDFUNCTION;
8728 entry.u.func = copyfunc(func);
Denys Vlasenko7aec8682016-10-25 20:26:02 +02008729 addcmdentry(func->narg.text, &entry);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008730 INT_ON;
8731}
8732
Denis Vlasenko4b875702009-03-19 13:30:04 +00008733/* Reasons for skipping commands (see comment on breakcmd routine) */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008734#define SKIPBREAK (1 << 0)
8735#define SKIPCONT (1 << 1)
8736#define SKIPFUNC (1 << 2)
Denis Vlasenko4b875702009-03-19 13:30:04 +00008737static smallint evalskip; /* set to SKIPxxx if we are skipping commands */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008738static int skipcount; /* number of levels to skip */
8739static int funcnest; /* depth of function calls */
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +00008740static int loopnest; /* current loop nesting level */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008741
Denis Vlasenko4b875702009-03-19 13:30:04 +00008742/* Forward decl way out to parsing code - dotrap needs it */
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02008743static int evalstring(char *s, int flags);
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008744
Denis Vlasenko4b875702009-03-19 13:30:04 +00008745/* Called to execute a trap.
8746 * Single callsite - at the end of evaltree().
Denys Vlasenkob563f622010-09-25 17:15:13 +02008747 * If we return non-zero, evaltree raises EXEXIT exception.
Denis Vlasenko4b875702009-03-19 13:30:04 +00008748 *
8749 * Perhaps we should avoid entering new trap handlers
8750 * while we are executing a trap handler. [is it a TODO?]
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008751 */
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008752static void
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008753dotrap(void)
8754{
Denis Vlasenko4b875702009-03-19 13:30:04 +00008755 uint8_t *g;
8756 int sig;
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008757 uint8_t last_status;
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008758
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008759 if (!pending_sig)
8760 return;
8761
8762 last_status = exitstatus;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02008763 pending_sig = 0;
Denys Vlasenkode892052016-10-02 01:49:13 +02008764 barrier();
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008765
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008766 TRACE(("dotrap entered\n"));
Denis Vlasenko4b875702009-03-19 13:30:04 +00008767 for (sig = 1, g = gotsig; sig < NSIG; sig++, g++) {
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008768 char *p;
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008769
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008770 if (!*g)
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008771 continue;
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008772
8773 if (evalskip) {
8774 pending_sig = sig;
8775 break;
8776 }
8777
8778 p = trap[sig];
Denis Vlasenko4b875702009-03-19 13:30:04 +00008779 /* non-trapped SIGINT is handled separately by raise_interrupt,
8780 * don't upset it by resetting gotsig[SIGINT-1] */
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008781 if (sig == SIGINT && !p)
Denis Vlasenko4b875702009-03-19 13:30:04 +00008782 continue;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008783
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008784 TRACE(("sig %d is active, will run handler '%s'\n", sig, p));
Denis Vlasenko4b875702009-03-19 13:30:04 +00008785 *g = 0;
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008786 if (!p)
Denis Vlasenko4b875702009-03-19 13:30:04 +00008787 continue;
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008788 evalstring(p, 0);
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008789 }
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008790 exitstatus = last_status;
8791 TRACE(("dotrap returns\n"));
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008792}
8793
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00008794/* forward declarations - evaluation is fairly recursive business... */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008795static int evalloop(union node *, int);
8796static int evalfor(union node *, int);
8797static int evalcase(union node *, int);
8798static int evalsubshell(union node *, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008799static void expredir(union node *);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008800static int evalpipe(union node *, int);
8801static int evalcommand(union node *, int);
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02008802static int evalbltin(const struct builtincmd *, int, char **, int);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008803static void prehash(union node *);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008804
Eric Andersen62483552001-07-10 06:09:16 +00008805/*
Eric Andersenc470f442003-07-28 09:56:35 +00008806 * Evaluate a parse tree. The value is left in the global variable
8807 * exitstatus.
Eric Andersen62483552001-07-10 06:09:16 +00008808 */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008809static int
Eric Andersenc470f442003-07-28 09:56:35 +00008810evaltree(union node *n, int flags)
Eric Andersen62483552001-07-10 06:09:16 +00008811{
Eric Andersenc470f442003-07-28 09:56:35 +00008812 int checkexit = 0;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008813 int (*evalfn)(union node *, int);
8814 int status = 0;
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008815
Eric Andersenc470f442003-07-28 09:56:35 +00008816 if (n == NULL) {
8817 TRACE(("evaltree(NULL) called\n"));
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02008818 goto out;
Eric Andersen62483552001-07-10 06:09:16 +00008819 }
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008820 TRACE(("evaltree(%p: %d, %d) called\n", n, n->type, flags));
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008821
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008822 dotrap();
8823
Eric Andersenc470f442003-07-28 09:56:35 +00008824 switch (n->type) {
8825 default:
Denis Vlasenkoa7189f02006-11-17 20:29:00 +00008826#if DEBUG
Eric Andersenc470f442003-07-28 09:56:35 +00008827 out1fmt("Node type = %d\n", n->type);
Denys Vlasenko8131eea2009-11-02 14:19:51 +01008828 fflush_all();
Eric Andersenc470f442003-07-28 09:56:35 +00008829 break;
8830#endif
8831 case NNOT:
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008832 status = !evaltree(n->nnot.com, EV_TESTED);
Eric Andersenc470f442003-07-28 09:56:35 +00008833 goto setstatus;
8834 case NREDIR:
8835 expredir(n->nredir.redirect);
Denys Vlasenko1c79aeb2017-07-29 22:51:52 +02008836 pushredir(n->nredir.redirect);
Eric Andersenc470f442003-07-28 09:56:35 +00008837 status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
8838 if (!status) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008839 status = evaltree(n->nredir.n, flags & EV_TESTED);
Eric Andersenc470f442003-07-28 09:56:35 +00008840 }
Denys Vlasenkoeaf94362016-10-25 21:46:03 +02008841 if (n->nredir.redirect)
Denys Vlasenko035486c2017-07-31 04:09:19 +02008842 popredir(/*drop:*/ 0);
Eric Andersenc470f442003-07-28 09:56:35 +00008843 goto setstatus;
8844 case NCMD:
8845 evalfn = evalcommand;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008846 checkexit:
Eric Andersenc470f442003-07-28 09:56:35 +00008847 if (eflag && !(flags & EV_TESTED))
8848 checkexit = ~0;
8849 goto calleval;
8850 case NFOR:
8851 evalfn = evalfor;
8852 goto calleval;
8853 case NWHILE:
8854 case NUNTIL:
8855 evalfn = evalloop;
8856 goto calleval;
8857 case NSUBSHELL:
8858 case NBACKGND:
8859 evalfn = evalsubshell;
Denys Vlasenkocf98b0c2016-10-25 18:19:39 +02008860 goto checkexit;
Eric Andersenc470f442003-07-28 09:56:35 +00008861 case NPIPE:
8862 evalfn = evalpipe;
8863 goto checkexit;
8864 case NCASE:
8865 evalfn = evalcase;
8866 goto calleval;
8867 case NAND:
8868 case NOR:
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008869 case NSEMI: {
8870
Eric Andersenc470f442003-07-28 09:56:35 +00008871#if NAND + 1 != NOR
8872#error NAND + 1 != NOR
8873#endif
8874#if NOR + 1 != NSEMI
8875#error NOR + 1 != NSEMI
8876#endif
Denis Vlasenko87d5fd92008-07-26 13:48:35 +00008877 unsigned is_or = n->type - NAND;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008878 status = evaltree(
Eric Andersenc470f442003-07-28 09:56:35 +00008879 n->nbinary.ch1,
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008880 (flags | ((is_or >> 1) - 1)) & EV_TESTED
Eric Andersenc470f442003-07-28 09:56:35 +00008881 );
Denys Vlasenkobc1a0082016-10-02 15:31:33 +02008882 if ((!status) == is_or || evalskip)
Eric Andersenc470f442003-07-28 09:56:35 +00008883 break;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008884 n = n->nbinary.ch2;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008885 evaln:
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008886 evalfn = evaltree;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008887 calleval:
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008888 status = evalfn(n, flags);
8889 goto setstatus;
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008890 }
Eric Andersenc470f442003-07-28 09:56:35 +00008891 case NIF:
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008892 status = evaltree(n->nif.test, EV_TESTED);
Eric Andersenc470f442003-07-28 09:56:35 +00008893 if (evalskip)
8894 break;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008895 if (!status) {
Eric Andersenc470f442003-07-28 09:56:35 +00008896 n = n->nif.ifpart;
8897 goto evaln;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008898 }
8899 if (n->nif.elsepart) {
Eric Andersenc470f442003-07-28 09:56:35 +00008900 n = n->nif.elsepart;
8901 goto evaln;
8902 }
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008903 status = 0;
8904 goto setstatus;
Eric Andersenc470f442003-07-28 09:56:35 +00008905 case NDEFUN:
Denys Vlasenko7aec8682016-10-25 20:26:02 +02008906 defun(n);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008907 /* Not necessary. To test it:
8908 * "false; f() { qwerty; }; echo $?" should print 0.
8909 */
8910 /* status = 0; */
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008911 setstatus:
Eric Andersenc470f442003-07-28 09:56:35 +00008912 exitstatus = status;
8913 break;
8914 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008915 out:
Denys Vlasenkob563f622010-09-25 17:15:13 +02008916 /* Order of checks below is important:
8917 * signal handlers trigger before exit caused by "set -e".
8918 */
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008919 dotrap();
8920
8921 if (checkexit & status)
Denis Vlasenkob012b102007-02-19 22:43:01 +00008922 raise_exception(EXEXIT);
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008923 if (flags & EV_EXIT)
8924 raise_exception(EXEXIT);
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008925
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008926 TRACE(("leaving evaltree (no interrupts)\n"));
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008927 return exitstatus;
Eric Andersen62483552001-07-10 06:09:16 +00008928}
8929
Denys Vlasenko37dc08b2016-10-02 04:38:07 +02008930static int
8931skiploop(void)
Denys Vlasenko35ec8182016-10-01 19:56:52 +02008932{
8933 int skip = evalskip;
8934
8935 switch (skip) {
8936 case 0:
8937 break;
8938 case SKIPBREAK:
8939 case SKIPCONT:
8940 if (--skipcount <= 0) {
8941 evalskip = 0;
8942 break;
8943 }
8944 skip = SKIPBREAK;
8945 break;
8946 }
8947 return skip;
8948}
8949
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008950static int
Eric Andersenc470f442003-07-28 09:56:35 +00008951evalloop(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00008952{
Denys Vlasenko35ec8182016-10-01 19:56:52 +02008953 int skip;
Eric Andersencb57d552001-06-28 07:25:16 +00008954 int status;
8955
8956 loopnest++;
8957 status = 0;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008958 flags &= EV_TESTED;
Denys Vlasenko35ec8182016-10-01 19:56:52 +02008959 do {
Eric Andersenc470f442003-07-28 09:56:35 +00008960 int i;
8961
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008962 i = evaltree(n->nbinary.ch1, EV_TESTED);
Denys Vlasenko35ec8182016-10-01 19:56:52 +02008963 skip = skiploop();
8964 if (skip == SKIPFUNC)
8965 status = i;
8966 if (skip)
8967 continue;
Eric Andersenc470f442003-07-28 09:56:35 +00008968 if (n->type != NWHILE)
8969 i = !i;
8970 if (i != 0)
8971 break;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008972 status = evaltree(n->nbinary.ch2, flags);
Denys Vlasenko35ec8182016-10-01 19:56:52 +02008973 skip = skiploop();
8974 } while (!(skip & ~SKIPCONT));
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008975 loopnest--;
8976
8977 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00008978}
8979
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008980static int
Eric Andersenc470f442003-07-28 09:56:35 +00008981evalfor(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00008982{
8983 struct arglist arglist;
8984 union node *argp;
8985 struct strlist *sp;
8986 struct stackmark smark;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008987 int status = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00008988
8989 setstackmark(&smark);
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00008990 arglist.list = NULL;
Eric Andersencb57d552001-06-28 07:25:16 +00008991 arglist.lastp = &arglist.list;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008992 for (argp = n->nfor.args; argp; argp = argp->narg.next) {
Ron Yorston549deab2015-05-18 09:57:51 +02008993 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
Eric Andersencb57d552001-06-28 07:25:16 +00008994 }
8995 *arglist.lastp = NULL;
8996
Eric Andersencb57d552001-06-28 07:25:16 +00008997 loopnest++;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008998 flags &= EV_TESTED;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008999 for (sp = arglist.list; sp; sp = sp->next) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009000 setvar0(n->nfor.var, sp->text);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009001 status = evaltree(n->nfor.body, flags);
Denys Vlasenko35ec8182016-10-01 19:56:52 +02009002 if (skiploop() & ~SKIPCONT)
Eric Andersencb57d552001-06-28 07:25:16 +00009003 break;
Eric Andersencb57d552001-06-28 07:25:16 +00009004 }
9005 loopnest--;
Eric Andersencb57d552001-06-28 07:25:16 +00009006 popstackmark(&smark);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009007
9008 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00009009}
9010
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009011static int
Eric Andersenc470f442003-07-28 09:56:35 +00009012evalcase(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00009013{
9014 union node *cp;
9015 union node *patp;
9016 struct arglist arglist;
9017 struct stackmark smark;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009018 int status = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00009019
9020 setstackmark(&smark);
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00009021 arglist.list = NULL;
Eric Andersencb57d552001-06-28 07:25:16 +00009022 arglist.lastp = &arglist.list;
Eric Andersencb57d552001-06-28 07:25:16 +00009023 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009024 for (cp = n->ncase.cases; cp && evalskip == 0; cp = cp->nclist.next) {
9025 for (patp = cp->nclist.pattern; patp; patp = patp->narg.next) {
Eric Andersencb57d552001-06-28 07:25:16 +00009026 if (casematch(patp, arglist.list->text)) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009027 /* Ensure body is non-empty as otherwise
9028 * EV_EXIT may prevent us from setting the
9029 * exit status.
9030 */
9031 if (evalskip == 0 && cp->nclist.body) {
9032 status = evaltree(cp->nclist.body, flags);
Eric Andersencb57d552001-06-28 07:25:16 +00009033 }
9034 goto out;
9035 }
9036 }
9037 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009038 out:
Eric Andersencb57d552001-06-28 07:25:16 +00009039 popstackmark(&smark);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009040
9041 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00009042}
9043
Eric Andersenc470f442003-07-28 09:56:35 +00009044/*
9045 * Kick off a subshell to evaluate a tree.
9046 */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009047static int
Eric Andersenc470f442003-07-28 09:56:35 +00009048evalsubshell(union node *n, int flags)
9049{
9050 struct job *jp;
Denys Vlasenko098b7132017-01-11 19:59:03 +01009051 int backgnd = (n->type == NBACKGND); /* FORK_BG(1) if yes, else FORK_FG(0) */
Eric Andersenc470f442003-07-28 09:56:35 +00009052 int status;
9053
9054 expredir(n->nredir.redirect);
Denys Vlasenko238bf182010-05-18 15:49:07 +02009055 if (!backgnd && (flags & EV_EXIT) && !may_have_traps)
Eric Andersenc470f442003-07-28 09:56:35 +00009056 goto nofork;
Denis Vlasenkob012b102007-02-19 22:43:01 +00009057 INT_OFF;
Denys Vlasenko098b7132017-01-11 19:59:03 +01009058 if (backgnd == FORK_FG)
9059 get_tty_state();
Denis Vlasenko68404f12008-03-17 09:00:54 +00009060 jp = makejob(/*n,*/ 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009061 if (forkshell(jp, n, backgnd) == 0) {
Denys Vlasenko238bf182010-05-18 15:49:07 +02009062 /* child */
Denis Vlasenkob012b102007-02-19 22:43:01 +00009063 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +00009064 flags |= EV_EXIT;
9065 if (backgnd)
Denys Vlasenko238bf182010-05-18 15:49:07 +02009066 flags &= ~EV_TESTED;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00009067 nofork:
Eric Andersenc470f442003-07-28 09:56:35 +00009068 redirect(n->nredir.redirect, 0);
9069 evaltreenr(n->nredir.n, flags);
9070 /* never returns */
9071 }
Denys Vlasenko70392332016-10-27 02:31:55 +02009072 /* parent */
Eric Andersenc470f442003-07-28 09:56:35 +00009073 status = 0;
Denys Vlasenko098b7132017-01-11 19:59:03 +01009074 if (backgnd == FORK_FG)
Eric Andersenc470f442003-07-28 09:56:35 +00009075 status = waitforjob(jp);
Denis Vlasenkob012b102007-02-19 22:43:01 +00009076 INT_ON;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009077 return status;
Eric Andersenc470f442003-07-28 09:56:35 +00009078}
9079
Eric Andersenc470f442003-07-28 09:56:35 +00009080/*
9081 * Compute the names of the files in a redirection list.
9082 */
Denis Vlasenko99eb8502007-02-23 21:09:49 +00009083static void fixredir(union node *, const char *, int);
Eric Andersenc470f442003-07-28 09:56:35 +00009084static void
9085expredir(union node *n)
9086{
9087 union node *redir;
9088
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009089 for (redir = n; redir; redir = redir->nfile.next) {
Eric Andersenc470f442003-07-28 09:56:35 +00009090 struct arglist fn;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009091
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00009092 fn.list = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00009093 fn.lastp = &fn.list;
9094 switch (redir->type) {
9095 case NFROMTO:
9096 case NFROM:
9097 case NTO:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01009098#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00009099 case NTO2:
9100#endif
Eric Andersenc470f442003-07-28 09:56:35 +00009101 case NCLOBBER:
9102 case NAPPEND:
9103 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02009104 TRACE(("expredir expanded to '%s'\n", fn.list->text));
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01009105#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00009106 store_expfname:
9107#endif
Denys Vlasenko7c4b13e2013-01-17 13:02:27 +01009108#if 0
9109// By the design of stack allocator, the loop of this kind:
9110// while true; do while true; do break; done </dev/null; done
9111// will look like a memory leak: ash plans to free expfname's
9112// of "/dev/null" as soon as it finishes running the loop
9113// (in this case, never).
9114// This "fix" is wrong:
Jon Tollefson4ba6c5d2012-11-13 19:26:53 +01009115 if (redir->nfile.expfname)
9116 stunalloc(redir->nfile.expfname);
Denys Vlasenko7c4b13e2013-01-17 13:02:27 +01009117// It results in corrupted state of stacked allocations.
9118#endif
Eric Andersenc470f442003-07-28 09:56:35 +00009119 redir->nfile.expfname = fn.list->text;
9120 break;
9121 case NFROMFD:
Denis Vlasenko559691a2008-10-05 18:39:31 +00009122 case NTOFD: /* >& */
Eric Andersenc470f442003-07-28 09:56:35 +00009123 if (redir->ndup.vname) {
9124 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009125 if (fn.list == NULL)
Denis Vlasenkob012b102007-02-19 22:43:01 +00009126 ash_msg_and_raise_error("redir error");
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01009127#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00009128//FIXME: we used expandarg with different args!
9129 if (!isdigit_str9(fn.list->text)) {
9130 /* >&file, not >&fd */
9131 if (redir->nfile.fd != 1) /* 123>&file - BAD */
9132 ash_msg_and_raise_error("redir error");
9133 redir->type = NTO2;
9134 goto store_expfname;
9135 }
9136#endif
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009137 fixredir(redir, fn.list->text, 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009138 }
9139 break;
9140 }
9141 }
9142}
9143
Eric Andersencb57d552001-06-28 07:25:16 +00009144/*
Eric Andersencb57d552001-06-28 07:25:16 +00009145 * Evaluate a pipeline. All the processes in the pipeline are children
9146 * of the process creating the pipeline. (This differs from some versions
9147 * of the shell, which make the last process in a pipeline the parent
9148 * of all the rest.)
9149 */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009150static int
Eric Andersenc470f442003-07-28 09:56:35 +00009151evalpipe(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00009152{
9153 struct job *jp;
9154 struct nodelist *lp;
9155 int pipelen;
9156 int prevfd;
9157 int pip[2];
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009158 int status = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00009159
Eric Andersenc470f442003-07-28 09:56:35 +00009160 TRACE(("evalpipe(0x%lx) called\n", (long)n));
Eric Andersencb57d552001-06-28 07:25:16 +00009161 pipelen = 0;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009162 for (lp = n->npipe.cmdlist; lp; lp = lp->next)
Eric Andersencb57d552001-06-28 07:25:16 +00009163 pipelen++;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009164 flags |= EV_EXIT;
Denis Vlasenkob012b102007-02-19 22:43:01 +00009165 INT_OFF;
Denys Vlasenko098b7132017-01-11 19:59:03 +01009166 if (n->npipe.pipe_backgnd == 0)
9167 get_tty_state();
Denis Vlasenko68404f12008-03-17 09:00:54 +00009168 jp = makejob(/*n,*/ pipelen);
Eric Andersencb57d552001-06-28 07:25:16 +00009169 prevfd = -1;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009170 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009171 prehash(lp->n);
Eric Andersencb57d552001-06-28 07:25:16 +00009172 pip[1] = -1;
9173 if (lp->next) {
9174 if (pipe(pip) < 0) {
9175 close(prevfd);
Denys Vlasenko12ffefb2017-08-23 14:52:56 +02009176 ash_msg_and_raise_perror("can't create pipe");
Eric Andersencb57d552001-06-28 07:25:16 +00009177 }
9178 }
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00009179 if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) {
Denys Vlasenko70392332016-10-27 02:31:55 +02009180 /* child */
Denis Vlasenkob012b102007-02-19 22:43:01 +00009181 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +00009182 if (pip[1] >= 0) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009183 close(pip[0]);
Eric Andersencb57d552001-06-28 07:25:16 +00009184 }
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009185 if (prevfd > 0) {
9186 dup2(prevfd, 0);
9187 close(prevfd);
9188 }
9189 if (pip[1] > 1) {
9190 dup2(pip[1], 1);
9191 close(pip[1]);
9192 }
Eric Andersenc470f442003-07-28 09:56:35 +00009193 evaltreenr(lp->n, flags);
9194 /* never returns */
Eric Andersencb57d552001-06-28 07:25:16 +00009195 }
Denys Vlasenko70392332016-10-27 02:31:55 +02009196 /* parent */
Eric Andersencb57d552001-06-28 07:25:16 +00009197 if (prevfd >= 0)
9198 close(prevfd);
9199 prevfd = pip[0];
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +00009200 /* Don't want to trigger debugging */
9201 if (pip[1] != -1)
9202 close(pip[1]);
Eric Andersencb57d552001-06-28 07:25:16 +00009203 }
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00009204 if (n->npipe.pipe_backgnd == 0) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009205 status = waitforjob(jp);
9206 TRACE(("evalpipe: job done exit status %d\n", status));
Eric Andersencb57d552001-06-28 07:25:16 +00009207 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00009208 INT_ON;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009209
9210 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00009211}
9212
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009213/*
9214 * Controls whether the shell is interactive or not.
9215 */
9216static void
9217setinteractive(int on)
9218{
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009219 static smallint is_interactive;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009220
9221 if (++on == is_interactive)
9222 return;
9223 is_interactive = on;
9224 setsignal(SIGINT);
9225 setsignal(SIGQUIT);
9226 setsignal(SIGTERM);
9227#if !ENABLE_FEATURE_SH_EXTRA_QUIET
9228 if (is_interactive > 1) {
9229 /* Looks like they want an interactive shell */
Denis Vlasenkoca525b42007-06-13 12:27:17 +00009230 static smallint did_banner;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009231
Denis Vlasenkoca525b42007-06-13 12:27:17 +00009232 if (!did_banner) {
Denys Vlasenkoc34c0332009-09-29 12:25:30 +02009233 /* note: ash and hush share this string */
9234 out1fmt("\n\n%s %s\n"
Denys Vlasenko2ec34962014-09-08 16:52:39 +02009235 IF_ASH_HELP("Enter 'help' for a list of built-in commands.\n")
9236 "\n",
Denys Vlasenkoc34c0332009-09-29 12:25:30 +02009237 bb_banner,
9238 "built-in shell (ash)"
9239 );
Denis Vlasenkoca525b42007-06-13 12:27:17 +00009240 did_banner = 1;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009241 }
9242 }
9243#endif
9244}
9245
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009246static void
9247optschanged(void)
9248{
9249#if DEBUG
9250 opentrace();
9251#endif
9252 setinteractive(iflag);
9253 setjobctl(mflag);
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009254#if ENABLE_FEATURE_EDITING_VI
9255 if (viflag)
9256 line_input_state->flags |= VI_MODE;
9257 else
9258 line_input_state->flags &= ~VI_MODE;
9259#else
9260 viflag = 0; /* forcibly keep the option off */
9261#endif
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009262}
9263
Denys Vlasenkob8ab27b2017-07-26 19:22:34 +02009264struct localvar_list {
9265 struct localvar_list *next;
9266 struct localvar *lv;
9267};
9268
9269static struct localvar_list *localvar_stack;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009270
9271/*
9272 * Called after a function returns.
9273 * Interrupts must be off.
9274 */
9275static void
Denys Vlasenko981a0562017-07-26 19:53:11 +02009276poplocalvars(int keep)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009277{
Denys Vlasenkob8ab27b2017-07-26 19:22:34 +02009278 struct localvar_list *ll;
9279 struct localvar *lvp, *next;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009280 struct var *vp;
9281
Denys Vlasenkob8ab27b2017-07-26 19:22:34 +02009282 INT_OFF;
9283 ll = localvar_stack;
9284 localvar_stack = ll->next;
9285
9286 next = ll->lv;
9287 free(ll);
9288
9289 while ((lvp = next) != NULL) {
9290 next = lvp->next;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009291 vp = lvp->vp;
Denys Vlasenkob563f622010-09-25 17:15:13 +02009292 TRACE(("poplocalvar %s\n", vp ? vp->var_text : "-"));
Denys Vlasenko981a0562017-07-26 19:53:11 +02009293 if (keep) {
9294 int bits = VSTRFIXED;
9295
9296 if (lvp->flags != VUNSET) {
9297 if (vp->var_text == lvp->text)
9298 bits |= VTEXTFIXED;
9299 else if (!(lvp->flags & (VTEXTFIXED|VSTACK)))
9300 free((char*)lvp->text);
9301 }
9302
9303 vp->flags &= ~bits;
9304 vp->flags |= (lvp->flags & bits);
9305
9306 if ((vp->flags &
9307 (VEXPORT|VREADONLY|VSTRFIXED|VUNSET)) == VUNSET)
9308 unsetvar(vp->var_text);
9309 } else if (vp == NULL) { /* $- saved */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009310 memcpy(optlist, lvp->text, sizeof(optlist));
9311 free((char*)lvp->text);
9312 optschanged();
Denys Vlasenkod5b500c2017-07-26 19:25:40 +02009313 } else if (lvp->flags == VUNSET) {
9314 vp->flags &= ~(VSTRFIXED|VREADONLY);
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009315 unsetvar(vp->var_text);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009316 } else {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009317 if (vp->var_func)
9318 vp->var_func(var_end(lvp->text));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009319 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009320 free((char*)vp->var_text);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009321 vp->flags = lvp->flags;
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009322 vp->var_text = lvp->text;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009323 }
9324 free(lvp);
9325 }
Denys Vlasenkob8ab27b2017-07-26 19:22:34 +02009326 INT_ON;
9327}
9328
9329/*
9330 * Create a new localvar environment.
9331 */
Denys Vlasenko484fc202017-07-26 19:55:31 +02009332static struct localvar_list *
Denys Vlasenkob8ab27b2017-07-26 19:22:34 +02009333pushlocalvars(void)
9334{
9335 struct localvar_list *ll;
9336
9337 INT_OFF;
9338 ll = ckzalloc(sizeof(*ll));
9339 /*ll->lv = NULL; - zalloc did it */
9340 ll->next = localvar_stack;
9341 localvar_stack = ll;
9342 INT_ON;
Denys Vlasenko484fc202017-07-26 19:55:31 +02009343
9344 return ll->next;
9345}
9346
9347static void
9348unwindlocalvars(struct localvar_list *stop)
9349{
9350 while (localvar_stack != stop)
9351 poplocalvars(0);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009352}
9353
9354static int
9355evalfun(struct funcnode *func, int argc, char **argv, int flags)
9356{
9357 volatile struct shparam saveparam;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009358 struct jmploc *volatile savehandler;
9359 struct jmploc jmploc;
9360 int e;
9361
9362 saveparam = shellparam;
Denys Vlasenkoa2d121c2016-09-30 11:30:11 +02009363 savehandler = exception_handler;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009364 e = setjmp(jmploc.loc);
9365 if (e) {
9366 goto funcdone;
9367 }
9368 INT_OFF;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009369 exception_handler = &jmploc;
Denis Vlasenko01631112007-12-16 17:20:38 +00009370 shellparam.malloced = 0;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009371 func->count++;
9372 funcnest++;
9373 INT_ON;
9374 shellparam.nparam = argc - 1;
9375 shellparam.p = argv + 1;
9376#if ENABLE_ASH_GETOPTS
9377 shellparam.optind = 1;
9378 shellparam.optoff = -1;
9379#endif
Denys Vlasenkob8ab27b2017-07-26 19:22:34 +02009380 pushlocalvars();
Denys Vlasenko7aec8682016-10-25 20:26:02 +02009381 evaltree(func->n.narg.next, flags & EV_TESTED);
Denys Vlasenko981a0562017-07-26 19:53:11 +02009382 poplocalvars(0);
Denis Vlasenko01631112007-12-16 17:20:38 +00009383 funcdone:
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009384 INT_OFF;
9385 funcnest--;
9386 freefunc(func);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009387 freeparam(&shellparam);
9388 shellparam = saveparam;
9389 exception_handler = savehandler;
9390 INT_ON;
9391 evalskip &= ~SKIPFUNC;
9392 return e;
9393}
9394
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009395/*
9396 * Make a variable a local variable. When a variable is made local, it's
9397 * value and flags are saved in a localvar structure. The saved values
9398 * will be restored when the shell function returns. We handle the name
Denys Vlasenkoe0a4e102015-05-13 02:20:14 +02009399 * "-" as a special case: it makes changes to "set +-options" local
9400 * (options will be restored on return from the function).
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009401 */
9402static void
9403mklocal(char *name)
9404{
9405 struct localvar *lvp;
9406 struct var **vpp;
9407 struct var *vp;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009408 char *eq = strchr(name, '=');
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009409
9410 INT_OFF;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009411 /* Cater for duplicate "local". Examples:
9412 * x=0; f() { local x=1; echo $x; local x; echo $x; }; f; echo $x
9413 * x=0; f() { local x=1; echo $x; local x=2; echo $x; }; f; echo $x
9414 */
Denys Vlasenkob8ab27b2017-07-26 19:22:34 +02009415 lvp = localvar_stack->lv;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009416 while (lvp) {
Eugene Rudoy1285aa62015-04-26 23:32:00 +02009417 if (lvp->vp && varcmp(lvp->vp->var_text, name) == 0) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009418 if (eq)
9419 setvareq(name, 0);
9420 /* else:
9421 * it's a duplicate "local VAR" declaration, do nothing
9422 */
Denys Vlasenko06b11492016-11-04 16:43:18 +01009423 goto ret;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009424 }
9425 lvp = lvp->next;
9426 }
9427
9428 lvp = ckzalloc(sizeof(*lvp));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009429 if (LONE_DASH(name)) {
9430 char *p;
9431 p = ckmalloc(sizeof(optlist));
9432 lvp->text = memcpy(p, optlist, sizeof(optlist));
9433 vp = NULL;
9434 } else {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009435 vpp = hashvar(name);
9436 vp = *findvar(vpp, name);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009437 if (vp == NULL) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009438 /* variable did not exist yet */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009439 if (eq)
Denys Vlasenkod04fc712017-07-26 20:06:48 +02009440 vp = setvareq(name, VSTRFIXED);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009441 else
Denys Vlasenkod04fc712017-07-26 20:06:48 +02009442 vp = setvar(name, NULL, VSTRFIXED);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009443 lvp->flags = VUNSET;
9444 } else {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009445 lvp->text = vp->var_text;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009446 lvp->flags = vp->flags;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009447 /* make sure neither "struct var" nor string gets freed
9448 * during (un)setting:
9449 */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009450 vp->flags |= VSTRFIXED|VTEXTFIXED;
9451 if (eq)
9452 setvareq(name, 0);
Denys Vlasenko109ee5d2014-03-16 18:41:11 +01009453 else
9454 /* "local VAR" unsets VAR: */
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009455 setvar0(name, NULL);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009456 }
9457 }
9458 lvp->vp = vp;
Denys Vlasenkob8ab27b2017-07-26 19:22:34 +02009459 lvp->next = localvar_stack->lv;
9460 localvar_stack->lv = lvp;
Denys Vlasenko06b11492016-11-04 16:43:18 +01009461 ret:
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009462 INT_ON;
9463}
9464
9465/*
9466 * The "local" command.
9467 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009468static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009469localcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009470{
9471 char *name;
9472
Denys Vlasenkob8ab27b2017-07-26 19:22:34 +02009473 if (!localvar_stack)
Ron Yorstonef2386b2015-10-29 16:19:14 +00009474 ash_msg_and_raise_error("not in a function");
9475
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009476 argv = argptr;
9477 while ((name = *argv++) != NULL) {
9478 mklocal(name);
9479 }
9480 return 0;
9481}
9482
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009483static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009484falsecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009485{
9486 return 1;
9487}
9488
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009489static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009490truecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009491{
9492 return 0;
9493}
9494
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009495static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009496execcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009497{
Denys Vlasenko6c149f42017-04-12 21:31:32 +02009498 optionarg = NULL;
9499 while (nextopt("a:") != '\0')
9500 /* nextopt() sets optionarg to "-a ARGV0" */;
9501
9502 argv = argptr;
9503 if (argv[0]) {
9504 char *prog;
9505
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009506 iflag = 0; /* exit on error */
9507 mflag = 0;
9508 optschanged();
Denys Vlasenkoe5814a52016-07-16 18:33:55 +02009509 /* We should set up signals for "exec CMD"
9510 * the same way as for "CMD" without "exec".
9511 * But optschanged->setinteractive->setsignal
9512 * still thought we are a root shell. Therefore, for example,
9513 * SIGQUIT is still set to IGN. Fix it:
9514 */
9515 shlvl++;
9516 setsignal(SIGQUIT);
9517 /*setsignal(SIGTERM); - unnecessary because of iflag=0 */
9518 /*setsignal(SIGTSTP); - unnecessary because of mflag=0 */
9519 /*setsignal(SIGTTOU); - unnecessary because of mflag=0 */
9520
Denys Vlasenko6c149f42017-04-12 21:31:32 +02009521 prog = argv[0];
9522 if (optionarg)
9523 argv[0] = optionarg;
9524 shellexec(prog, argv, pathval(), 0);
Denys Vlasenkoe5814a52016-07-16 18:33:55 +02009525 /* NOTREACHED */
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009526 }
9527 return 0;
9528}
9529
9530/*
9531 * The return command.
9532 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009533static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009534returncmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009535{
9536 /*
9537 * If called outside a function, do what ksh does;
9538 * skip the rest of the file.
9539 */
Denys Vlasenko6a0710e2016-09-30 14:18:34 +02009540 evalskip = SKIPFUNC;
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009541 return argv[1] ? number(argv[1]) : exitstatus;
9542}
9543
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009544/* Forward declarations for builtintab[] */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009545static int breakcmd(int, char **) FAST_FUNC;
9546static int dotcmd(int, char **) FAST_FUNC;
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009547static int evalcmd(int, char **, int) FAST_FUNC;
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009548static int exitcmd(int, char **) FAST_FUNC;
9549static int exportcmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009550#if ENABLE_ASH_GETOPTS
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009551static int getoptscmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009552#endif
Denys Vlasenko2ec34962014-09-08 16:52:39 +02009553#if ENABLE_ASH_HELP
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009554static int helpcmd(int, char **) FAST_FUNC;
Denis Vlasenko52764022007-02-24 13:42:56 +00009555#endif
Flemming Madsend96ffda2013-04-07 18:47:24 +02009556#if MAX_HISTORY
9557static int historycmd(int, char **) FAST_FUNC;
9558#endif
Denys Vlasenko0b883582016-12-23 16:49:07 +01009559#if ENABLE_FEATURE_SH_MATH
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009560static int letcmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009561#endif
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009562static int readcmd(int, char **) FAST_FUNC;
9563static int setcmd(int, char **) FAST_FUNC;
9564static int shiftcmd(int, char **) FAST_FUNC;
9565static int timescmd(int, char **) FAST_FUNC;
9566static int trapcmd(int, char **) FAST_FUNC;
9567static int umaskcmd(int, char **) FAST_FUNC;
9568static int unsetcmd(int, char **) FAST_FUNC;
9569static int ulimitcmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009570
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009571#define BUILTIN_NOSPEC "0"
9572#define BUILTIN_SPECIAL "1"
9573#define BUILTIN_REGULAR "2"
9574#define BUILTIN_SPEC_REG "3"
9575#define BUILTIN_ASSIGN "4"
9576#define BUILTIN_SPEC_ASSG "5"
9577#define BUILTIN_REG_ASSG "6"
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009578#define BUILTIN_SPEC_REG_ASSG "7"
9579
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009580/* Stubs for calling non-FAST_FUNC's */
Denys Vlasenko265062d2017-01-10 15:13:30 +01009581#if ENABLE_ASH_ECHO
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009582static int FAST_FUNC echocmd(int argc, char **argv) { return echo_main(argc, argv); }
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009583#endif
Denys Vlasenko265062d2017-01-10 15:13:30 +01009584#if ENABLE_ASH_PRINTF
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009585static int FAST_FUNC printfcmd(int argc, char **argv) { return printf_main(argc, argv); }
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009586#endif
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01009587#if ENABLE_ASH_TEST || BASH_TEST2
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009588static int FAST_FUNC testcmd(int argc, char **argv) { return test_main(argc, argv); }
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009589#endif
Denis Vlasenko468aea22008-04-01 14:47:57 +00009590
Denis Vlasenkof7d56652008-03-25 05:51:41 +00009591/* Keep these in proper order since it is searched via bsearch() */
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009592static const struct builtincmd builtintab[] = {
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009593 { BUILTIN_SPEC_REG "." , dotcmd },
9594 { BUILTIN_SPEC_REG ":" , truecmd },
Denys Vlasenko265062d2017-01-10 15:13:30 +01009595#if ENABLE_ASH_TEST
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009596 { BUILTIN_REGULAR "[" , testcmd },
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01009597#endif
9598#if BASH_TEST2
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009599 { BUILTIN_REGULAR "[[" , testcmd },
Denis Vlasenko80591b02008-03-25 07:49:43 +00009600#endif
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009601#if ENABLE_ASH_ALIAS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009602 { BUILTIN_REG_ASSG "alias" , aliascmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009603#endif
9604#if JOBS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009605 { BUILTIN_REGULAR "bg" , fg_bgcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009606#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009607 { BUILTIN_SPEC_REG "break" , breakcmd },
9608 { BUILTIN_REGULAR "cd" , cdcmd },
9609 { BUILTIN_NOSPEC "chdir" , cdcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009610#if ENABLE_ASH_CMDCMD
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009611 { BUILTIN_REGULAR "command" , commandcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009612#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009613 { BUILTIN_SPEC_REG "continue", breakcmd },
Denys Vlasenko265062d2017-01-10 15:13:30 +01009614#if ENABLE_ASH_ECHO
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009615 { BUILTIN_REGULAR "echo" , echocmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009616#endif
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009617 { BUILTIN_SPEC_REG "eval" , NULL }, /*evalcmd() has a differing prototype*/
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009618 { BUILTIN_SPEC_REG "exec" , execcmd },
9619 { BUILTIN_SPEC_REG "exit" , exitcmd },
9620 { BUILTIN_SPEC_REG_ASSG "export" , exportcmd },
9621 { BUILTIN_REGULAR "false" , falsecmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009622#if JOBS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009623 { BUILTIN_REGULAR "fg" , fg_bgcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009624#endif
9625#if ENABLE_ASH_GETOPTS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009626 { BUILTIN_REGULAR "getopts" , getoptscmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009627#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009628 { BUILTIN_NOSPEC "hash" , hashcmd },
Denys Vlasenko2ec34962014-09-08 16:52:39 +02009629#if ENABLE_ASH_HELP
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009630 { BUILTIN_NOSPEC "help" , helpcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009631#endif
Flemming Madsend96ffda2013-04-07 18:47:24 +02009632#if MAX_HISTORY
9633 { BUILTIN_NOSPEC "history" , historycmd },
9634#endif
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009635#if JOBS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009636 { BUILTIN_REGULAR "jobs" , jobscmd },
9637 { BUILTIN_REGULAR "kill" , killcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009638#endif
Denys Vlasenko0b883582016-12-23 16:49:07 +01009639#if ENABLE_FEATURE_SH_MATH
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009640 { BUILTIN_NOSPEC "let" , letcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009641#endif
Denys Vlasenko85241c72017-07-26 20:00:08 +02009642 { BUILTIN_SPEC_REG_ASSG "local" , localcmd },
Denys Vlasenko265062d2017-01-10 15:13:30 +01009643#if ENABLE_ASH_PRINTF
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009644 { BUILTIN_REGULAR "printf" , printfcmd },
Denis Vlasenkocd2663f2008-06-01 22:36:39 +00009645#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009646 { BUILTIN_NOSPEC "pwd" , pwdcmd },
9647 { BUILTIN_REGULAR "read" , readcmd },
9648 { BUILTIN_SPEC_REG_ASSG "readonly", exportcmd },
9649 { BUILTIN_SPEC_REG "return" , returncmd },
9650 { BUILTIN_SPEC_REG "set" , setcmd },
9651 { BUILTIN_SPEC_REG "shift" , shiftcmd },
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01009652#if BASH_SOURCE
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009653 { BUILTIN_SPEC_REG "source" , dotcmd },
Denys Vlasenko82731b42010-05-17 17:49:52 +02009654#endif
Denys Vlasenko265062d2017-01-10 15:13:30 +01009655#if ENABLE_ASH_TEST
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009656 { BUILTIN_REGULAR "test" , testcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009657#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009658 { BUILTIN_SPEC_REG "times" , timescmd },
9659 { BUILTIN_SPEC_REG "trap" , trapcmd },
9660 { BUILTIN_REGULAR "true" , truecmd },
9661 { BUILTIN_NOSPEC "type" , typecmd },
9662 { BUILTIN_NOSPEC "ulimit" , ulimitcmd },
9663 { BUILTIN_REGULAR "umask" , umaskcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009664#if ENABLE_ASH_ALIAS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009665 { BUILTIN_REGULAR "unalias" , unaliascmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009666#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009667 { BUILTIN_SPEC_REG "unset" , unsetcmd },
9668 { BUILTIN_REGULAR "wait" , waitcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009669};
9670
Denis Vlasenko80591b02008-03-25 07:49:43 +00009671/* Should match the above table! */
9672#define COMMANDCMD (builtintab + \
Denys Vlasenko928e2a72016-09-29 00:30:31 +02009673 /* . : */ 2 + \
Denys Vlasenko265062d2017-01-10 15:13:30 +01009674 /* [ */ 1 * ENABLE_ASH_TEST + \
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01009675 /* [[ */ 1 * BASH_TEST2 + \
Denys Vlasenko928e2a72016-09-29 00:30:31 +02009676 /* alias */ 1 * ENABLE_ASH_ALIAS + \
9677 /* bg */ 1 * ENABLE_ASH_JOB_CONTROL + \
9678 /* break cd cddir */ 3)
9679#define EVALCMD (COMMANDCMD + \
9680 /* command */ 1 * ENABLE_ASH_CMDCMD + \
9681 /* continue */ 1 + \
Denys Vlasenko265062d2017-01-10 15:13:30 +01009682 /* echo */ 1 * ENABLE_ASH_ECHO + \
Denys Vlasenko928e2a72016-09-29 00:30:31 +02009683 0)
9684#define EXECCMD (EVALCMD + \
9685 /* eval */ 1)
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009686
9687/*
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009688 * Search the table of builtin commands.
9689 */
Denys Vlasenko888527c2016-10-02 16:54:17 +02009690static int
9691pstrcmp1(const void *a, const void *b)
9692{
9693 return strcmp((char*)a, *(char**)b + 1);
9694}
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009695static struct builtincmd *
9696find_builtin(const char *name)
9697{
9698 struct builtincmd *bp;
9699
9700 bp = bsearch(
Denis Vlasenko80b8b392007-06-25 10:55:35 +00009701 name, builtintab, ARRAY_SIZE(builtintab), sizeof(builtintab[0]),
Denys Vlasenko888527c2016-10-02 16:54:17 +02009702 pstrcmp1
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009703 );
9704 return bp;
9705}
9706
9707/*
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009708 * Execute a simple command.
9709 */
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009710static int
9711isassignment(const char *p)
Paul Foxc3850c82005-07-20 18:23:39 +00009712{
9713 const char *q = endofname(p);
9714 if (p == q)
9715 return 0;
9716 return *q == '=';
9717}
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009718static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009719bltincmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009720{
9721 /* Preserve exitstatus of a previous possible redirection
9722 * as POSIX mandates */
9723 return back_exitstatus;
9724}
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009725static int
Eric Andersenc470f442003-07-28 09:56:35 +00009726evalcommand(union node *cmd, int flags)
9727{
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00009728 static const struct builtincmd null_bltin = {
9729 "\0\0", bltincmd /* why three NULs? */
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009730 };
Denys Vlasenko484fc202017-07-26 19:55:31 +02009731 struct localvar_list *localvar_stop;
Denys Vlasenko1c79aeb2017-07-29 22:51:52 +02009732 struct redirtab *redir_stop;
Eric Andersenc470f442003-07-28 09:56:35 +00009733 struct stackmark smark;
9734 union node *argp;
9735 struct arglist arglist;
9736 struct arglist varlist;
9737 char **argv;
9738 int argc;
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009739 const struct strlist *sp;
Eric Andersenc470f442003-07-28 09:56:35 +00009740 struct cmdentry cmdentry;
9741 struct job *jp;
9742 char *lastarg;
9743 const char *path;
9744 int spclbltin;
Eric Andersenc470f442003-07-28 09:56:35 +00009745 int status;
9746 char **nargv;
Denis Vlasenko34c73c42008-08-16 11:48:02 +00009747 smallint cmd_is_exec;
Eric Andersenc470f442003-07-28 09:56:35 +00009748
9749 /* First expand the arguments. */
9750 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
9751 setstackmark(&smark);
Denys Vlasenko484fc202017-07-26 19:55:31 +02009752 localvar_stop = pushlocalvars();
Eric Andersenc470f442003-07-28 09:56:35 +00009753 back_exitstatus = 0;
9754
9755 cmdentry.cmdtype = CMDBUILTIN;
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00009756 cmdentry.u.cmd = &null_bltin;
Eric Andersenc470f442003-07-28 09:56:35 +00009757 varlist.lastp = &varlist.list;
9758 *varlist.lastp = NULL;
9759 arglist.lastp = &arglist.list;
9760 *arglist.lastp = NULL;
9761
9762 argc = 0;
Denis Vlasenkob012b102007-02-19 22:43:01 +00009763 if (cmd->ncmd.args) {
Denys Vlasenkod07a15b2017-07-30 16:51:05 +02009764 struct builtincmd *bcmd;
9765 smallint pseudovarflag;
9766
Paul Foxc3850c82005-07-20 18:23:39 +00009767 bcmd = find_builtin(cmd->ncmd.args->narg.text);
9768 pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd);
Paul Foxc3850c82005-07-20 18:23:39 +00009769
Denys Vlasenkod07a15b2017-07-30 16:51:05 +02009770 for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) {
9771 struct strlist **spp;
Eric Andersenc470f442003-07-28 09:56:35 +00009772
Denys Vlasenkod07a15b2017-07-30 16:51:05 +02009773 spp = arglist.lastp;
9774 if (pseudovarflag && isassignment(argp->narg.text))
9775 expandarg(argp, &arglist, EXP_VARTILDE);
9776 else
9777 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
Paul Foxc3850c82005-07-20 18:23:39 +00009778
Denys Vlasenkod07a15b2017-07-30 16:51:05 +02009779 for (sp = *spp; sp; sp = sp->next)
9780 argc++;
9781 }
Eric Andersenc470f442003-07-28 09:56:35 +00009782 }
9783
Denys Vlasenko65a8b852016-10-26 22:29:11 +02009784 /* Reserve one extra spot at the front for shellexec. */
9785 nargv = stalloc(sizeof(char *) * (argc + 2));
9786 argv = ++nargv;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009787 for (sp = arglist.list; sp; sp = sp->next) {
Eric Andersenc470f442003-07-28 09:56:35 +00009788 TRACE(("evalcommand arg: %s\n", sp->text));
9789 *nargv++ = sp->text;
9790 }
9791 *nargv = NULL;
9792
9793 lastarg = NULL;
9794 if (iflag && funcnest == 0 && argc > 0)
9795 lastarg = nargv[-1];
9796
9797 expredir(cmd->ncmd.redirect);
Denys Vlasenko1c79aeb2017-07-29 22:51:52 +02009798 redir_stop = pushredir(cmd->ncmd.redirect);
Denys Vlasenkod07a15b2017-07-30 16:51:05 +02009799 preverrout_fd = 2;
Denys Vlasenkof8cdc7a2017-08-04 15:24:49 +02009800 if (BASH_XTRACEFD && xflag) {
9801 /* NB: bash closes fd == $BASH_XTRACEFD when it is changed.
9802 * we do not emulate this. We only use its value.
9803 */
9804 const char *xtracefd = lookupvar("BASH_XTRACEFD");
9805 if (xtracefd && is_number(xtracefd))
9806 preverrout_fd = atoi(xtracefd);
9807
9808 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009809 status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH | REDIR_SAVEFD2);
Eric Andersenc470f442003-07-28 09:56:35 +00009810
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009811 path = vpath.var_text;
Eric Andersenc470f442003-07-28 09:56:35 +00009812 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
9813 struct strlist **spp;
9814 char *p;
9815
9816 spp = varlist.lastp;
9817 expandarg(argp, &varlist, EXP_VARTILDE);
9818
Denys Vlasenko981a0562017-07-26 19:53:11 +02009819 mklocal((*spp)->text);
9820
Eric Andersenc470f442003-07-28 09:56:35 +00009821 /*
9822 * Modify the command lookup path, if a PATH= assignment
9823 * is present
9824 */
9825 p = (*spp)->text;
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009826 if (varcmp(p, path) == 0)
Eric Andersenc470f442003-07-28 09:56:35 +00009827 path = p;
9828 }
9829
9830 /* Print the command if xflag is set. */
9831 if (xflag) {
Denys Vlasenko42ba7572017-07-21 13:20:14 +02009832 const char *pfx = "";
Eric Andersenc470f442003-07-28 09:56:35 +00009833
Denys Vlasenko46999802017-07-29 21:12:29 +02009834 fdprintf(preverrout_fd, "%s", expandstr(ps4val(), DQSYNTAX));
Denys Vlasenko42ba7572017-07-21 13:20:14 +02009835
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009836 sp = varlist.list;
Denys Vlasenko42ba7572017-07-21 13:20:14 +02009837 while (sp) {
9838 char *varval = sp->text;
9839 char *eq = strchrnul(varval, '=');
9840 if (*eq)
9841 eq++;
9842 fdprintf(preverrout_fd, "%s%.*s%s",
9843 pfx,
9844 (int)(eq - varval), varval,
9845 maybe_single_quote(eq)
9846 );
9847 sp = sp->next;
9848 pfx = " ";
9849 }
9850
9851 sp = arglist.list;
9852 while (sp) {
9853 fdprintf(preverrout_fd, "%s%s",
9854 pfx,
9855 /* always quote if matches reserved word: */
9856 findkwd(sp->text)
9857 ? single_quote(sp->text)
9858 : maybe_single_quote(sp->text)
9859 );
9860 sp = sp->next;
9861 pfx = " ";
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009862 }
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00009863 safe_write(preverrout_fd, "\n", 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009864 }
9865
9866 cmd_is_exec = 0;
9867 spclbltin = -1;
9868
9869 /* Now locate the command. */
9870 if (argc) {
Eric Andersenc470f442003-07-28 09:56:35 +00009871 int cmd_flag = DO_ERR;
Denys Vlasenko0b4980c2012-09-25 12:49:29 +02009872#if ENABLE_ASH_CMDCMD
9873 const char *oldpath = path + 5;
9874#endif
Eric Andersenc470f442003-07-28 09:56:35 +00009875 path += 5;
Eric Andersenc470f442003-07-28 09:56:35 +00009876 for (;;) {
9877 find_command(argv[0], &cmdentry, cmd_flag, path);
9878 if (cmdentry.cmdtype == CMDUNKNOWN) {
Denys Vlasenko8131eea2009-11-02 14:19:51 +01009879 flush_stdout_stderr();
Denis Vlasenko6514c5e2008-07-24 13:41:37 +00009880 status = 127;
Eric Andersenc470f442003-07-28 09:56:35 +00009881 goto bail;
9882 }
9883
9884 /* implement bltin and command here */
9885 if (cmdentry.cmdtype != CMDBUILTIN)
9886 break;
9887 if (spclbltin < 0)
9888 spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd);
9889 if (cmdentry.u.cmd == EXECCMD)
Denis Vlasenko34c73c42008-08-16 11:48:02 +00009890 cmd_is_exec = 1;
Denis Vlasenko131ae172007-02-18 13:00:19 +00009891#if ENABLE_ASH_CMDCMD
Eric Andersenc470f442003-07-28 09:56:35 +00009892 if (cmdentry.u.cmd == COMMANDCMD) {
Eric Andersenc470f442003-07-28 09:56:35 +00009893 path = oldpath;
9894 nargv = parse_command_args(argv, &path);
9895 if (!nargv)
9896 break;
Denys Vlasenkocac4d002016-10-01 03:02:25 +02009897 /* It's "command [-p] PROG ARGS" (that is, no -Vv).
9898 * nargv => "PROG". path is updated if -p.
9899 */
Eric Andersenc470f442003-07-28 09:56:35 +00009900 argc -= nargv - argv;
9901 argv = nargv;
9902 cmd_flag |= DO_NOFUNC;
9903 } else
9904#endif
9905 break;
9906 }
9907 }
9908
9909 if (status) {
Ron Yorstonea7d2f62017-01-03 11:18:23 +01009910 bail:
9911 exitstatus = status;
9912
Eric Andersenc470f442003-07-28 09:56:35 +00009913 /* We have a redirection error. */
9914 if (spclbltin > 0)
Denis Vlasenkob012b102007-02-19 22:43:01 +00009915 raise_exception(EXERROR);
Ron Yorstonea7d2f62017-01-03 11:18:23 +01009916
Eric Andersenc470f442003-07-28 09:56:35 +00009917 goto out;
9918 }
9919
9920 /* Execute the command. */
9921 switch (cmdentry.cmdtype) {
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009922 default: {
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +00009923
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009924#if ENABLE_FEATURE_SH_NOFORK
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009925/* (1) BUG: if variables are set, we need to fork, or save/restore them
9926 * around run_nofork_applet() call.
9927 * (2) Should this check also be done in forkshell()?
9928 * (perhaps it should, so that "VAR=VAL nofork" at least avoids exec...)
9929 */
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00009930 /* find_command() encodes applet_no as (-2 - applet_no) */
9931 int applet_no = (- cmdentry.u.index - 2);
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009932 if (applet_no >= 0 && APPLET_IS_NOFORK(applet_no)) {
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009933 listsetvar(varlist.list, VEXPORT|VSTACK);
Denys Vlasenkod329e342017-08-04 14:50:03 +02009934 /*
9935 * Run <applet>_main().
9936 * Signals (^C) can't interrupt here.
9937 * Otherwise we can mangle stdio or malloc internal state.
9938 * This makes applets which can run for a long time
9939 * and/or wait for user input ineligible for NOFORK:
9940 * for example, "yes" or "rm" (rm -i waits for input).
9941 */
9942 INT_OFF;
Ron Yorston5ccb0e92016-10-20 12:24:02 +01009943 status = run_nofork_applet(applet_no, argv);
Denys Vlasenkod329e342017-08-04 14:50:03 +02009944 /*
9945 * Try enabling NOFORK for "yes" applet.
9946 * ^C _will_ stop it (write returns EINTR),
9947 * but this causes stdout FILE to be stuck
9948 * and needing clearerr(). What if other applets
9949 * also can get EINTRs? Do we need to switch
9950 * our signals to SA_RESTART?
9951 */
9952 /*clearerr(stdout);*/
9953 INT_ON;
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009954 break;
9955 }
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009956#endif
Denys Vlasenkocfd392b2017-08-03 19:56:29 +02009957 /* Can we avoid forking? For example, very last command
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009958 * in a script or a subshell does not need forking,
9959 * we can just exec it.
9960 */
Denys Vlasenko238bf182010-05-18 15:49:07 +02009961 if (!(flags & EV_EXIT) || may_have_traps) {
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009962 /* No, forking off a child is necessary */
Denis Vlasenkob012b102007-02-19 22:43:01 +00009963 INT_OFF;
Denys Vlasenko098b7132017-01-11 19:59:03 +01009964 get_tty_state();
Denis Vlasenko68404f12008-03-17 09:00:54 +00009965 jp = makejob(/*cmd,*/ 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009966 if (forkshell(jp, cmd, FORK_FG) != 0) {
Denys Vlasenko238bf182010-05-18 15:49:07 +02009967 /* parent */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009968 status = waitforjob(jp);
Denis Vlasenkob012b102007-02-19 22:43:01 +00009969 INT_ON;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009970 TRACE(("forked child exited with %d\n", status));
Eric Andersenc470f442003-07-28 09:56:35 +00009971 break;
9972 }
Denys Vlasenko238bf182010-05-18 15:49:07 +02009973 /* child */
Denis Vlasenkob012b102007-02-19 22:43:01 +00009974 FORCE_INT_ON;
Denys Vlasenkoc7f95d22010-05-18 15:52:23 +02009975 /* fall through to exec'ing external program */
Eric Andersenc470f442003-07-28 09:56:35 +00009976 }
9977 listsetvar(varlist.list, VEXPORT|VSTACK);
Denys Vlasenkoe139ae32017-04-12 21:02:33 +02009978 shellexec(argv[0], argv, path, cmdentry.u.index);
Eric Andersenc470f442003-07-28 09:56:35 +00009979 /* NOTREACHED */
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009980 } /* default */
Eric Andersenc470f442003-07-28 09:56:35 +00009981 case CMDBUILTIN:
Denys Vlasenko85241c72017-07-26 20:00:08 +02009982 if (spclbltin > 0 || argc == 0) {
9983 poplocalvars(1);
9984 if (cmd_is_exec && argc > 1)
9985 listsetvar(varlist.list, VEXPORT);
9986 }
Denys Vlasenko981a0562017-07-26 19:53:11 +02009987
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +00009988 /* Tight loop with builtins only:
9989 * "while kill -0 $child; do true; done"
9990 * will never exit even if $child died, unless we do this
9991 * to reap the zombie and make kill detect that it's gone: */
9992 dowait(DOWAIT_NONBLOCK, NULL);
9993
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009994 if (evalbltin(cmdentry.u.cmd, argc, argv, flags)) {
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02009995 if (exception_type == EXERROR && spclbltin <= 0) {
9996 FORCE_INT_ON;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +02009997 goto readstatus;
Eric Andersenc470f442003-07-28 09:56:35 +00009998 }
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02009999 raise:
10000 longjmp(exception_handler->loc, 1);
Eric Andersenc470f442003-07-28 09:56:35 +000010001 }
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020010002 goto readstatus;
Eric Andersenc470f442003-07-28 09:56:35 +000010003
10004 case CMDFUNCTION:
Denys Vlasenko981a0562017-07-26 19:53:11 +020010005 poplocalvars(1);
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +000010006 /* See above for the rationale */
10007 dowait(DOWAIT_NONBLOCK, NULL);
Eric Andersenc470f442003-07-28 09:56:35 +000010008 if (evalfun(cmdentry.u.func, argc, argv, flags))
10009 goto raise;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020010010 readstatus:
10011 status = exitstatus;
Eric Andersenc470f442003-07-28 09:56:35 +000010012 break;
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +020010013 } /* switch */
Eric Andersenc470f442003-07-28 09:56:35 +000010014
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010015 out:
Denys Vlasenkoeaf94362016-10-25 21:46:03 +020010016 if (cmd->ncmd.redirect)
Denys Vlasenko035486c2017-07-31 04:09:19 +020010017 popredir(/*drop:*/ cmd_is_exec);
Denys Vlasenko1c79aeb2017-07-29 22:51:52 +020010018 unwindredir(redir_stop);
Denys Vlasenko484fc202017-07-26 19:55:31 +020010019 unwindlocalvars(localvar_stop);
Denis Vlasenko6514c5e2008-07-24 13:41:37 +000010020 if (lastarg) {
Eric Andersenc470f442003-07-28 09:56:35 +000010021 /* dsl: I think this is intended to be used to support
10022 * '_' in 'vi' command mode during line editing...
10023 * However I implemented that within libedit itself.
10024 */
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020010025 setvar0("_", lastarg);
Denis Vlasenko6514c5e2008-07-24 13:41:37 +000010026 }
Eric Andersenc470f442003-07-28 09:56:35 +000010027 popstackmark(&smark);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020010028
10029 return status;
Eric Andersenc470f442003-07-28 09:56:35 +000010030}
10031
10032static int
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020010033evalbltin(const struct builtincmd *cmd, int argc, char **argv, int flags)
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010034{
Eric Andersenc470f442003-07-28 09:56:35 +000010035 char *volatile savecmdname;
10036 struct jmploc *volatile savehandler;
10037 struct jmploc jmploc;
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020010038 int status;
Eric Andersenc470f442003-07-28 09:56:35 +000010039 int i;
10040
10041 savecmdname = commandname;
Denys Vlasenkoa2d121c2016-09-30 11:30:11 +020010042 savehandler = exception_handler;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010043 i = setjmp(jmploc.loc);
10044 if (i)
Eric Andersenc470f442003-07-28 09:56:35 +000010045 goto cmddone;
Denis Vlasenko2da584f2007-02-19 22:44:05 +000010046 exception_handler = &jmploc;
Eric Andersenc470f442003-07-28 09:56:35 +000010047 commandname = argv[0];
10048 argptr = argv + 1;
10049 optptr = NULL; /* initialize nextopt */
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020010050 if (cmd == EVALCMD)
10051 status = evalcmd(argc, argv, flags);
10052 else
10053 status = (*cmd->builtin)(argc, argv);
Denis Vlasenkob012b102007-02-19 22:43:01 +000010054 flush_stdout_stderr();
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020010055 status |= ferror(stdout);
10056 exitstatus = status;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010057 cmddone:
Rob Landleyf296f0b2006-07-06 01:09:21 +000010058 clearerr(stdout);
Eric Andersenc470f442003-07-28 09:56:35 +000010059 commandname = savecmdname;
Denis Vlasenko2da584f2007-02-19 22:44:05 +000010060 exception_handler = savehandler;
Eric Andersenc470f442003-07-28 09:56:35 +000010061
10062 return i;
10063}
10064
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010065static int
10066goodname(const char *p)
Glenn L McGrath16e45d72004-02-04 08:24:39 +000010067{
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +020010068 return endofname(p)[0] == '\0';
Glenn L McGrath16e45d72004-02-04 08:24:39 +000010069}
10070
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010071
Glenn L McGrath50812ff2002-08-23 13:14:48 +000010072/*
10073 * Search for a command. This is called before we fork so that the
10074 * location of the command will be available in the parent as well as
Glenn L McGrath16e45d72004-02-04 08:24:39 +000010075 * the child. The check for "goodname" is an overly conservative
10076 * check that the name will not be subject to expansion.
Glenn L McGrath50812ff2002-08-23 13:14:48 +000010077 */
Eric Andersenc470f442003-07-28 09:56:35 +000010078static void
10079prehash(union node *n)
Glenn L McGrath50812ff2002-08-23 13:14:48 +000010080{
10081 struct cmdentry entry;
10082
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000010083 if (n->type == NCMD && n->ncmd.args && goodname(n->ncmd.args->narg.text))
10084 find_command(n->ncmd.args->narg.text, &entry, 0, pathval());
Glenn L McGrath50812ff2002-08-23 13:14:48 +000010085}
10086
Eric Andersencb57d552001-06-28 07:25:16 +000010087
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000010088/* ============ Builtin commands
10089 *
10090 * Builtin commands whose functions are closely tied to evaluation
10091 * are implemented here.
Eric Andersencb57d552001-06-28 07:25:16 +000010092 */
10093
10094/*
Eric Andersencb57d552001-06-28 07:25:16 +000010095 * Handle break and continue commands. Break, continue, and return are
10096 * all handled by setting the evalskip flag. The evaluation routines
10097 * above all check this flag, and if it is set they start skipping
10098 * commands rather than executing them. The variable skipcount is
10099 * the number of loops to break/continue, or the number of function
10100 * levels to return. (The latter is always 1.) It should probably
10101 * be an error to break out of more loops than exist, but it isn't
10102 * in the standard shell so we don't make it one here.
10103 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010104static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010105breakcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000010106{
Denis Vlasenko68404f12008-03-17 09:00:54 +000010107 int n = argv[1] ? number(argv[1]) : 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010108
Aaron Lehmann2aef3a62001-12-31 06:03:12 +000010109 if (n <= 0)
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +020010110 ash_msg_and_raise_error(msg_illnum, argv[1]);
Eric Andersencb57d552001-06-28 07:25:16 +000010111 if (n > loopnest)
10112 n = loopnest;
10113 if (n > 0) {
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000010114 evalskip = (**argv == 'c') ? SKIPCONT : SKIPBREAK;
Eric Andersencb57d552001-06-28 07:25:16 +000010115 skipcount = n;
10116 }
10117 return 0;
10118}
10119
Eric Andersenc470f442003-07-28 09:56:35 +000010120
Denys Vlasenko70392332016-10-27 02:31:55 +020010121/*
Eric Andersen90898442003-08-06 11:20:52 +000010122 * This implements the input routines used by the parser.
Eric Andersencb57d552001-06-28 07:25:16 +000010123 */
Denis Vlasenko99eb8502007-02-23 21:09:49 +000010124
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010125enum {
10126 INPUT_PUSH_FILE = 1,
10127 INPUT_NOFILE_OK = 2,
10128};
Eric Andersencb57d552001-06-28 07:25:16 +000010129
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010130static smallint checkkwd;
Denis Vlasenko99eb8502007-02-23 21:09:49 +000010131/* values of checkkwd variable */
10132#define CHKALIAS 0x1
10133#define CHKKWD 0x2
10134#define CHKNL 0x4
Denys Vlasenkoa7328982017-07-29 19:57:28 +020010135#define CHKEOFMARK 0x8
Denis Vlasenko99eb8502007-02-23 21:09:49 +000010136
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010137/*
10138 * Push a string back onto the input at this current parsefile level.
10139 * We handle aliases this way.
10140 */
10141#if !ENABLE_ASH_ALIAS
10142#define pushstring(s, ap) pushstring(s)
10143#endif
10144static void
10145pushstring(char *s, struct alias *ap)
10146{
10147 struct strpush *sp;
10148 int len;
10149
10150 len = strlen(s);
10151 INT_OFF;
10152 if (g_parsefile->strpush) {
10153 sp = ckzalloc(sizeof(*sp));
10154 sp->prev = g_parsefile->strpush;
10155 } else {
10156 sp = &(g_parsefile->basestrpush);
10157 }
10158 g_parsefile->strpush = sp;
10159 sp->prev_string = g_parsefile->next_to_pgetc;
10160 sp->prev_left_in_line = g_parsefile->left_in_line;
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010161 sp->unget = g_parsefile->unget;
10162 memcpy(sp->lastc, g_parsefile->lastc, sizeof(sp->lastc));
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010163#if ENABLE_ASH_ALIAS
10164 sp->ap = ap;
10165 if (ap) {
10166 ap->flag |= ALIASINUSE;
10167 sp->string = s;
10168 }
10169#endif
10170 g_parsefile->next_to_pgetc = s;
10171 g_parsefile->left_in_line = len;
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010172 g_parsefile->unget = 0;
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010173 INT_ON;
10174}
10175
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010176static void
10177popstring(void)
Eric Andersenc470f442003-07-28 09:56:35 +000010178{
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010179 struct strpush *sp = g_parsefile->strpush;
Eric Andersenc470f442003-07-28 09:56:35 +000010180
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010181 INT_OFF;
Denis Vlasenko131ae172007-02-18 13:00:19 +000010182#if ENABLE_ASH_ALIAS
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010183 if (sp->ap) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010184 if (g_parsefile->next_to_pgetc[-1] == ' '
10185 || g_parsefile->next_to_pgetc[-1] == '\t'
10186 ) {
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010187 checkkwd |= CHKALIAS;
Glenn L McGrath28939ad2004-07-21 10:20:19 +000010188 }
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010189 if (sp->string != sp->ap->val) {
10190 free(sp->string);
10191 }
10192 sp->ap->flag &= ~ALIASINUSE;
10193 if (sp->ap->flag & ALIASDEAD) {
10194 unalias(sp->ap->name);
10195 }
Glenn L McGrath28939ad2004-07-21 10:20:19 +000010196 }
Denis Vlasenko8e1c7152007-01-22 07:21:38 +000010197#endif
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010198 g_parsefile->next_to_pgetc = sp->prev_string;
10199 g_parsefile->left_in_line = sp->prev_left_in_line;
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010200 g_parsefile->unget = sp->unget;
10201 memcpy(g_parsefile->lastc, sp->lastc, sizeof(sp->lastc));
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010202 g_parsefile->strpush = sp->prev;
10203 if (sp != &(g_parsefile->basestrpush))
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010204 free(sp);
10205 INT_ON;
10206}
Denis Vlasenko8e1c7152007-01-22 07:21:38 +000010207
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010208static int
10209preadfd(void)
Eric Andersencb57d552001-06-28 07:25:16 +000010210{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010211 int nr;
Denis Vlasenko6a0ad252008-07-25 13:34:05 +000010212 char *buf = g_parsefile->buf;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010213
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010214 g_parsefile->next_to_pgetc = buf;
Denis Vlasenko38f63192007-01-22 09:03:07 +000010215#if ENABLE_FEATURE_EDITING
Denis Vlasenko85c24712008-03-17 09:04:04 +000010216 retry:
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010217 if (!iflag || g_parsefile->pf_fd != STDIN_FILENO)
Ron Yorston61d6ae22015-04-19 10:50:25 +010010218 nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1);
Eric Andersenc470f442003-07-28 09:56:35 +000010219 else {
Denys Vlasenko66c5b122011-02-08 05:07:02 +010010220# if ENABLE_ASH_IDLE_TIMEOUT
Denys Vlasenko84ea60e2017-08-02 17:27:28 +020010221 int timeout = -1;
Denys Vlasenko66c5b122011-02-08 05:07:02 +010010222 if (iflag) {
10223 const char *tmout_var = lookupvar("TMOUT");
10224 if (tmout_var) {
10225 timeout = atoi(tmout_var) * 1000;
10226 if (timeout <= 0)
10227 timeout = -1;
10228 }
10229 }
Denys Vlasenko84ea60e2017-08-02 17:27:28 +020010230 line_input_state->timeout = timeout;
Denys Vlasenko66c5b122011-02-08 05:07:02 +010010231# endif
Denys Vlasenko8c52f802011-02-04 17:36:21 +010010232# if ENABLE_FEATURE_TAB_COMPLETION
Denis Vlasenko8e1c7152007-01-22 07:21:38 +000010233 line_input_state->path_lookup = pathval();
Denys Vlasenko8c52f802011-02-04 17:36:21 +010010234# endif
Denys Vlasenkoe9ab07c2014-08-13 18:00:08 +020010235 reinit_unicode_for_ash();
Denys Vlasenko84ea60e2017-08-02 17:27:28 +020010236 nr = read_line_input(line_input_state, cmdedit_prompt, buf, IBUFSIZ);
Denis Vlasenko8e1c7152007-01-22 07:21:38 +000010237 if (nr == 0) {
Denys Vlasenko4b89d512016-11-25 03:41:03 +010010238 /* ^C pressed, "convert" to SIGINT */
10239 write(STDOUT_FILENO, "^C", 2);
Denis Vlasenko8e1c7152007-01-22 07:21:38 +000010240 if (trap[SIGINT]) {
Glenn L McGrath16e45d72004-02-04 08:24:39 +000010241 buf[0] = '\n';
Denis Vlasenko8e1c7152007-01-22 07:21:38 +000010242 buf[1] = '\0';
Glenn L McGrath16e45d72004-02-04 08:24:39 +000010243 raise(SIGINT);
10244 return 1;
10245 }
Denys Vlasenko8660aeb2016-11-24 17:44:02 +010010246 exitstatus = 128 + SIGINT;
Denys Vlasenko4b89d512016-11-25 03:41:03 +010010247 bb_putchar('\n');
Eric Andersenc470f442003-07-28 09:56:35 +000010248 goto retry;
10249 }
Denys Vlasenko66c5b122011-02-08 05:07:02 +010010250 if (nr < 0) {
10251 if (errno == 0) {
10252 /* Ctrl+D pressed */
10253 nr = 0;
10254 }
10255# if ENABLE_ASH_IDLE_TIMEOUT
10256 else if (errno == EAGAIN && timeout > 0) {
Denys Vlasenkod60752f2015-10-07 22:42:45 +020010257 puts("\007timed out waiting for input: auto-logout");
Denys Vlasenko66c5b122011-02-08 05:07:02 +010010258 exitshell();
10259 }
10260# endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010261 }
Eric Andersencb57d552001-06-28 07:25:16 +000010262 }
10263#else
Ron Yorston61d6ae22015-04-19 10:50:25 +010010264 nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1);
Eric Andersencb57d552001-06-28 07:25:16 +000010265#endif
10266
Denys Vlasenko80c5b682011-05-08 21:21:10 +020010267#if 0 /* disabled: nonblock_immune_read() handles this problem */
Eric Andersencb57d552001-06-28 07:25:16 +000010268 if (nr < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +000010269 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
Denis Vlasenkod37f2222007-08-19 13:42:08 +000010270 int flags = fcntl(0, F_GETFL);
Denis Vlasenko9cb220b2007-12-09 10:03:28 +000010271 if (flags >= 0 && (flags & O_NONBLOCK)) {
10272 flags &= ~O_NONBLOCK;
Eric Andersencb57d552001-06-28 07:25:16 +000010273 if (fcntl(0, F_SETFL, flags) >= 0) {
10274 out2str("sh: turning off NDELAY mode\n");
10275 goto retry;
10276 }
10277 }
10278 }
10279 }
Denis Vlasenkoe376d452008-02-20 22:23:24 +000010280#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010281 return nr;
10282}
10283
10284/*
10285 * Refill the input buffer and return the next input character:
10286 *
10287 * 1) If a string was pushed back on the input, pop it;
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010288 * 2) If an EOF was pushed back (g_parsefile->left_in_line < -BIGNUM)
10289 * or we are reading from a string so we can't refill the buffer,
10290 * return EOF.
Denys Vlasenko883cea42009-07-11 15:31:59 +020010291 * 3) If there is more stuff in this buffer, use it else call read to fill it.
Eric Andersencb57d552001-06-28 07:25:16 +000010292 * 4) Process input up to the next newline, deleting nul characters.
10293 */
Denis Vlasenko727752d2008-11-28 03:41:47 +000010294//#define pgetc_debug(...) bb_error_msg(__VA_ARGS__)
10295#define pgetc_debug(...) ((void)0)
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010296static int pgetc(void);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010297static int
Eric Andersenc470f442003-07-28 09:56:35 +000010298preadbuffer(void)
Eric Andersencb57d552001-06-28 07:25:16 +000010299{
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010300 char *q;
Eric Andersencb57d552001-06-28 07:25:16 +000010301 int more;
Eric Andersencb57d552001-06-28 07:25:16 +000010302
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010303 if (g_parsefile->strpush) {
Denis Vlasenko131ae172007-02-18 13:00:19 +000010304#if ENABLE_ASH_ALIAS
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010305 if (g_parsefile->left_in_line == -1
10306 && g_parsefile->strpush->ap
10307 && g_parsefile->next_to_pgetc[-1] != ' '
10308 && g_parsefile->next_to_pgetc[-1] != '\t'
Denis Vlasenko16898402008-11-25 01:34:52 +000010309 ) {
Denis Vlasenko727752d2008-11-28 03:41:47 +000010310 pgetc_debug("preadbuffer PEOA");
Eric Andersencb57d552001-06-28 07:25:16 +000010311 return PEOA;
10312 }
Eric Andersen2870d962001-07-02 17:27:21 +000010313#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010314 popstring();
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010315 return pgetc();
Eric Andersencb57d552001-06-28 07:25:16 +000010316 }
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010317 /* on both branches above g_parsefile->left_in_line < 0.
Denis Vlasenko727752d2008-11-28 03:41:47 +000010318 * "pgetc" needs refilling.
10319 */
10320
Denis Vlasenkoe27dafd2008-11-28 04:01:03 +000010321 /* -90 is our -BIGNUM. Below we use -99 to mark "EOF on read",
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010322 * pungetc() may increment it a few times.
Denis Vlasenkoe27dafd2008-11-28 04:01:03 +000010323 * Assuming it won't increment it to less than -90.
Denis Vlasenko727752d2008-11-28 03:41:47 +000010324 */
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010325 if (g_parsefile->left_in_line < -90 || g_parsefile->buf == NULL) {
Denis Vlasenko727752d2008-11-28 03:41:47 +000010326 pgetc_debug("preadbuffer PEOF1");
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010327 /* even in failure keep left_in_line and next_to_pgetc
10328 * in lock step, for correct multi-layer pungetc.
10329 * left_in_line was decremented before preadbuffer(),
10330 * must inc next_to_pgetc: */
10331 g_parsefile->next_to_pgetc++;
Eric Andersencb57d552001-06-28 07:25:16 +000010332 return PEOF;
Denis Vlasenko727752d2008-11-28 03:41:47 +000010333 }
Eric Andersencb57d552001-06-28 07:25:16 +000010334
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010335 more = g_parsefile->left_in_buffer;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010336 if (more <= 0) {
Denis Vlasenko727752d2008-11-28 03:41:47 +000010337 flush_stdout_stderr();
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010338 again:
10339 more = preadfd();
10340 if (more <= 0) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010341 /* don't try reading again */
10342 g_parsefile->left_in_line = -99;
Denis Vlasenko727752d2008-11-28 03:41:47 +000010343 pgetc_debug("preadbuffer PEOF2");
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010344 g_parsefile->next_to_pgetc++;
Eric Andersencb57d552001-06-28 07:25:16 +000010345 return PEOF;
10346 }
10347 }
10348
Denis Vlasenko727752d2008-11-28 03:41:47 +000010349 /* Find out where's the end of line.
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010350 * Set g_parsefile->left_in_line
10351 * and g_parsefile->left_in_buffer acordingly.
Denis Vlasenko727752d2008-11-28 03:41:47 +000010352 * NUL chars are deleted.
10353 */
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010354 q = g_parsefile->next_to_pgetc;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010355 for (;;) {
Denis Vlasenko727752d2008-11-28 03:41:47 +000010356 char c;
Eric Andersencb57d552001-06-28 07:25:16 +000010357
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010358 more--;
Eric Andersenc470f442003-07-28 09:56:35 +000010359
Denis Vlasenko727752d2008-11-28 03:41:47 +000010360 c = *q;
10361 if (c == '\0') {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010362 memmove(q, q + 1, more);
Denis Vlasenko727752d2008-11-28 03:41:47 +000010363 } else {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010364 q++;
10365 if (c == '\n') {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010366 g_parsefile->left_in_line = q - g_parsefile->next_to_pgetc - 1;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010367 break;
10368 }
Eric Andersencb57d552001-06-28 07:25:16 +000010369 }
10370
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010371 if (more <= 0) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010372 g_parsefile->left_in_line = q - g_parsefile->next_to_pgetc - 1;
10373 if (g_parsefile->left_in_line < 0)
Eric Andersencb57d552001-06-28 07:25:16 +000010374 goto again;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010375 break;
Eric Andersencb57d552001-06-28 07:25:16 +000010376 }
10377 }
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010378 g_parsefile->left_in_buffer = more;
Eric Andersencb57d552001-06-28 07:25:16 +000010379
Eric Andersencb57d552001-06-28 07:25:16 +000010380 if (vflag) {
Denis Vlasenko727752d2008-11-28 03:41:47 +000010381 char save = *q;
10382 *q = '\0';
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010383 out2str(g_parsefile->next_to_pgetc);
Denis Vlasenko727752d2008-11-28 03:41:47 +000010384 *q = save;
Eric Andersencb57d552001-06-28 07:25:16 +000010385 }
10386
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010387 pgetc_debug("preadbuffer at %d:%p'%s'",
10388 g_parsefile->left_in_line,
10389 g_parsefile->next_to_pgetc,
10390 g_parsefile->next_to_pgetc);
Denys Vlasenkocd716832009-11-28 22:14:02 +010010391 return (unsigned char)*g_parsefile->next_to_pgetc++;
Eric Andersencb57d552001-06-28 07:25:16 +000010392}
10393
Denys Vlasenkoce332a22016-10-02 23:47:34 +020010394static void
10395nlprompt(void)
10396{
10397 g_parsefile->linno++;
10398 setprompt_if(doprompt, 2);
10399}
10400static void
10401nlnoprompt(void)
10402{
10403 g_parsefile->linno++;
10404 needprompt = doprompt;
10405}
10406
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010407static int
10408pgetc(void)
10409{
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010410 int c;
10411
10412 pgetc_debug("pgetc at %d:%p'%s'",
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010413 g_parsefile->left_in_line,
10414 g_parsefile->next_to_pgetc,
10415 g_parsefile->next_to_pgetc);
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010416 if (g_parsefile->unget)
10417 return g_parsefile->lastc[--g_parsefile->unget];
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010418
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010419 if (--g_parsefile->left_in_line >= 0)
Denys Vlasenko2fe66b12016-12-12 17:39:12 +010010420 c = (unsigned char)*g_parsefile->next_to_pgetc++;
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010421 else
10422 c = preadbuffer();
10423
10424 g_parsefile->lastc[1] = g_parsefile->lastc[0];
10425 g_parsefile->lastc[0] = c;
10426
10427 return c;
10428}
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010429
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010430#if ENABLE_ASH_ALIAS
10431static int
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010010432pgetc_without_PEOA(void)
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010433{
10434 int c;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010435 do {
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010436 pgetc_debug("pgetc at %d:%p'%s'",
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010437 g_parsefile->left_in_line,
10438 g_parsefile->next_to_pgetc,
10439 g_parsefile->next_to_pgetc);
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010440 c = pgetc();
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010441 } while (c == PEOA);
10442 return c;
10443}
10444#else
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010010445# define pgetc_without_PEOA() pgetc()
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010446#endif
10447
10448/*
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010449 * Undo a call to pgetc. Only two characters may be pushed back.
Eric Andersenc470f442003-07-28 09:56:35 +000010450 * PEOF may be pushed back.
10451 */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010452static void
Eric Andersenc470f442003-07-28 09:56:35 +000010453pungetc(void)
10454{
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010455 g_parsefile->unget++;
Eric Andersencb57d552001-06-28 07:25:16 +000010456}
10457
Denys Vlasenko73c3e072016-09-29 17:17:04 +020010458/* This one eats backslash+newline */
10459static int
10460pgetc_eatbnl(void)
10461{
10462 int c;
10463
10464 while ((c = pgetc()) == '\\') {
10465 if (pgetc() != '\n') {
10466 pungetc();
10467 break;
10468 }
10469
Denys Vlasenkoce332a22016-10-02 23:47:34 +020010470 nlprompt();
Denys Vlasenko73c3e072016-09-29 17:17:04 +020010471 }
10472
10473 return c;
10474}
10475
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010476/*
10477 * To handle the "." command, a stack of input files is used. Pushfile
10478 * adds a new entry to the stack and popfile restores the previous level.
10479 */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010480static void
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010481pushfile(void)
Eric Andersenc470f442003-07-28 09:56:35 +000010482{
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010483 struct parsefile *pf;
10484
Denis Vlasenko597906c2008-02-20 16:38:54 +000010485 pf = ckzalloc(sizeof(*pf));
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010486 pf->prev = g_parsefile;
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010487 pf->pf_fd = -1;
Denis Vlasenko597906c2008-02-20 16:38:54 +000010488 /*pf->strpush = NULL; - ckzalloc did it */
10489 /*pf->basestrpush.prev = NULL;*/
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010490 /*pf->unget = 0;*/
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010491 g_parsefile = pf;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010492}
10493
10494static void
10495popfile(void)
10496{
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010497 struct parsefile *pf = g_parsefile;
Eric Andersenc470f442003-07-28 09:56:35 +000010498
Denys Vlasenko493b9ca2016-10-30 18:27:14 +010010499 if (pf == &basepf)
10500 return;
10501
Denis Vlasenkob012b102007-02-19 22:43:01 +000010502 INT_OFF;
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010503 if (pf->pf_fd >= 0)
10504 close(pf->pf_fd);
Denis Vlasenko60818682007-09-28 22:07:23 +000010505 free(pf->buf);
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010506 while (pf->strpush)
10507 popstring();
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010508 g_parsefile = pf->prev;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010509 free(pf);
Denis Vlasenkob012b102007-02-19 22:43:01 +000010510 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +000010511}
10512
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010513/*
10514 * Return to top level.
10515 */
10516static void
10517popallfiles(void)
10518{
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010519 while (g_parsefile != &basepf)
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010520 popfile();
10521}
10522
10523/*
10524 * Close the file(s) that the shell is reading commands from. Called
10525 * after a fork is done.
10526 */
10527static void
10528closescript(void)
10529{
10530 popallfiles();
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010531 if (g_parsefile->pf_fd > 0) {
10532 close(g_parsefile->pf_fd);
10533 g_parsefile->pf_fd = 0;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010534 }
10535}
10536
10537/*
10538 * Like setinputfile, but takes an open file descriptor. Call this with
10539 * interrupts off.
10540 */
10541static void
10542setinputfd(int fd, int push)
10543{
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010544 if (push) {
10545 pushfile();
Denis Vlasenko727752d2008-11-28 03:41:47 +000010546 g_parsefile->buf = NULL;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010547 }
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010548 g_parsefile->pf_fd = fd;
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010549 if (g_parsefile->buf == NULL)
10550 g_parsefile->buf = ckmalloc(IBUFSIZ);
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010551 g_parsefile->left_in_buffer = 0;
10552 g_parsefile->left_in_line = 0;
10553 g_parsefile->linno = 1;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010554}
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010555
Eric Andersenc470f442003-07-28 09:56:35 +000010556/*
10557 * Set the input to take input from a file. If push is set, push the
10558 * old input onto the stack first.
10559 */
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010560static int
10561setinputfile(const char *fname, int flags)
Eric Andersenc470f442003-07-28 09:56:35 +000010562{
10563 int fd;
Eric Andersenc470f442003-07-28 09:56:35 +000010564
Denis Vlasenkob012b102007-02-19 22:43:01 +000010565 INT_OFF;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010566 fd = open(fname, O_RDONLY);
10567 if (fd < 0) {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010568 if (flags & INPUT_NOFILE_OK)
10569 goto out;
Denys Vlasenkob7adf7a2016-10-25 17:00:13 +020010570 exitstatus = 127;
Johannes Schindelin20a63b22017-08-22 22:03:17 +020010571 ash_msg_and_raise_perror("can't open '%s'", fname);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010572 }
Denys Vlasenko64774602016-10-26 15:24:30 +020010573 if (fd < 10)
10574 fd = savefd(fd);
Denys Vlasenkoe19923f2016-10-26 15:38:44 +020010575 else
10576 close_on_exec_on(fd);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010577 setinputfd(fd, flags & INPUT_PUSH_FILE);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010578 out:
Denis Vlasenkob012b102007-02-19 22:43:01 +000010579 INT_ON;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010580 return fd;
Eric Andersenc470f442003-07-28 09:56:35 +000010581}
10582
Eric Andersencb57d552001-06-28 07:25:16 +000010583/*
10584 * Like setinputfile, but takes input from a string.
10585 */
Eric Andersenc470f442003-07-28 09:56:35 +000010586static void
10587setinputstring(char *string)
Eric Andersen62483552001-07-10 06:09:16 +000010588{
Denis Vlasenkob012b102007-02-19 22:43:01 +000010589 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +000010590 pushfile();
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010591 g_parsefile->next_to_pgetc = string;
10592 g_parsefile->left_in_line = strlen(string);
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010593 g_parsefile->buf = NULL;
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010594 g_parsefile->linno = 1;
Denis Vlasenkob012b102007-02-19 22:43:01 +000010595 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +000010596}
10597
10598
Denys Vlasenko70392332016-10-27 02:31:55 +020010599/*
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010600 * Routines to check for mail.
Eric Andersencb57d552001-06-28 07:25:16 +000010601 */
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010602
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010603#if ENABLE_ASH_MAIL
Eric Andersencb57d552001-06-28 07:25:16 +000010604
Denys Vlasenko23841622015-10-09 15:52:03 +020010605/* Hash of mtimes of mailboxes */
10606static unsigned mailtime_hash;
Eric Andersenc470f442003-07-28 09:56:35 +000010607/* Set if MAIL or MAILPATH is changed. */
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010608static smallint mail_var_path_changed;
Eric Andersencb57d552001-06-28 07:25:16 +000010609
Eric Andersencb57d552001-06-28 07:25:16 +000010610/*
Eric Andersenc470f442003-07-28 09:56:35 +000010611 * Print appropriate message(s) if mail has arrived.
10612 * If mail_var_path_changed is set,
10613 * then the value of MAIL has mail_var_path_changed,
10614 * so we just update the values.
Eric Andersencb57d552001-06-28 07:25:16 +000010615 */
Eric Andersenc470f442003-07-28 09:56:35 +000010616static void
10617chkmail(void)
Eric Andersencb57d552001-06-28 07:25:16 +000010618{
Eric Andersencb57d552001-06-28 07:25:16 +000010619 const char *mpath;
10620 char *p;
10621 char *q;
Denys Vlasenko23841622015-10-09 15:52:03 +020010622 unsigned new_hash;
Eric Andersencb57d552001-06-28 07:25:16 +000010623 struct stackmark smark;
10624 struct stat statb;
10625
Eric Andersencb57d552001-06-28 07:25:16 +000010626 setstackmark(&smark);
Eric Andersenc470f442003-07-28 09:56:35 +000010627 mpath = mpathset() ? mpathval() : mailval();
Denys Vlasenko23841622015-10-09 15:52:03 +020010628 new_hash = 0;
10629 for (;;) {
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020010630 p = path_advance(&mpath, nullstr);
Eric Andersencb57d552001-06-28 07:25:16 +000010631 if (p == NULL)
10632 break;
10633 if (*p == '\0')
10634 continue;
Denis Vlasenkof7d56652008-03-25 05:51:41 +000010635 for (q = p; *q; q++)
10636 continue;
Denis Vlasenkoa7189f02006-11-17 20:29:00 +000010637#if DEBUG
Eric Andersencb57d552001-06-28 07:25:16 +000010638 if (q[-1] != '/')
10639 abort();
10640#endif
Eric Andersenc470f442003-07-28 09:56:35 +000010641 q[-1] = '\0'; /* delete trailing '/' */
10642 if (stat(p, &statb) < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +000010643 continue;
Eric Andersencb57d552001-06-28 07:25:16 +000010644 }
Denys Vlasenko23841622015-10-09 15:52:03 +020010645 /* Very simplistic "hash": just a sum of all mtimes */
10646 new_hash += (unsigned)statb.st_mtime;
10647 }
10648 if (!mail_var_path_changed && mailtime_hash != new_hash) {
Denys Vlasenko4cd99e72015-10-09 16:02:53 +020010649 if (mailtime_hash != 0)
10650 out2str("you have mail\n");
Denys Vlasenko23841622015-10-09 15:52:03 +020010651 mailtime_hash = new_hash;
Eric Andersencb57d552001-06-28 07:25:16 +000010652 }
Eric Andersenc470f442003-07-28 09:56:35 +000010653 mail_var_path_changed = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010654 popstackmark(&smark);
10655}
Eric Andersencb57d552001-06-28 07:25:16 +000010656
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010657static void FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010658changemail(const char *val UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000010659{
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010660 mail_var_path_changed = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000010661}
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010662
Denis Vlasenko131ae172007-02-18 13:00:19 +000010663#endif /* ASH_MAIL */
Eric Andersenc470f442003-07-28 09:56:35 +000010664
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010665
10666/* ============ ??? */
10667
Eric Andersencb57d552001-06-28 07:25:16 +000010668/*
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010669 * Set the shell parameters.
Eric Andersencb57d552001-06-28 07:25:16 +000010670 */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010671static void
10672setparam(char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000010673{
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010674 char **newparam;
10675 char **ap;
10676 int nparam;
Eric Andersencb57d552001-06-28 07:25:16 +000010677
Denis Vlasenkof7d56652008-03-25 05:51:41 +000010678 for (nparam = 0; argv[nparam]; nparam++)
10679 continue;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010680 ap = newparam = ckmalloc((nparam + 1) * sizeof(*ap));
10681 while (*argv) {
10682 *ap++ = ckstrdup(*argv++);
Eric Andersencb57d552001-06-28 07:25:16 +000010683 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010684 *ap = NULL;
10685 freeparam(&shellparam);
Denis Vlasenko01631112007-12-16 17:20:38 +000010686 shellparam.malloced = 1;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010687 shellparam.nparam = nparam;
10688 shellparam.p = newparam;
10689#if ENABLE_ASH_GETOPTS
10690 shellparam.optind = 1;
10691 shellparam.optoff = -1;
10692#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010693}
10694
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010695/*
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010696 * Process shell options. The global variable argptr contains a pointer
10697 * to the argument list; we advance it past the options.
Denis Vlasenko94e87bc2008-02-14 16:51:58 +000010698 *
10699 * SUSv3 section 2.8.1 "Consequences of Shell Errors" says:
10700 * For a non-interactive shell, an error condition encountered
10701 * by a special built-in ... shall cause the shell to write a diagnostic message
10702 * to standard error and exit as shown in the following table:
Denis Vlasenko56244732008-02-17 15:14:04 +000010703 * Error Special Built-In
Denis Vlasenko94e87bc2008-02-14 16:51:58 +000010704 * ...
10705 * Utility syntax error (option or operand error) Shall exit
10706 * ...
10707 * However, in bug 1142 (http://busybox.net/bugs/view.php?id=1142)
10708 * we see that bash does not do that (set "finishes" with error code 1 instead,
10709 * and shell continues), and people rely on this behavior!
10710 * Testcase:
10711 * set -o barfoo 2>/dev/null
10712 * echo $?
10713 *
10714 * Oh well. Let's mimic that.
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010715 */
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010716static int
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010717plus_minus_o(char *name, int val)
Eric Andersen62483552001-07-10 06:09:16 +000010718{
10719 int i;
10720
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010721 if (name) {
10722 for (i = 0; i < NOPTS; i++) {
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000010723 if (strcmp(name, optnames(i)) == 0) {
Eric Andersenc470f442003-07-28 09:56:35 +000010724 optlist[i] = val;
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010725 return 0;
Eric Andersen62483552001-07-10 06:09:16 +000010726 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010727 }
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010728 ash_msg("illegal option %co %s", val ? '-' : '+', name);
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010729 return 1;
Eric Andersen62483552001-07-10 06:09:16 +000010730 }
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000010731 for (i = 0; i < NOPTS; i++) {
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010732 if (val) {
10733 out1fmt("%-16s%s\n", optnames(i), optlist[i] ? "on" : "off");
10734 } else {
10735 out1fmt("set %co %s\n", optlist[i] ? '-' : '+', optnames(i));
10736 }
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000010737 }
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010738 return 0;
Eric Andersen62483552001-07-10 06:09:16 +000010739}
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010740static void
10741setoption(int flag, int val)
10742{
10743 int i;
10744
10745 for (i = 0; i < NOPTS; i++) {
10746 if (optletters(i) == flag) {
10747 optlist[i] = val;
10748 return;
10749 }
10750 }
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010751 ash_msg_and_raise_error("illegal option %c%c", val ? '-' : '+', flag);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010752 /* NOTREACHED */
10753}
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010754static int
Denys Vlasenkoec05df12017-07-31 19:43:47 +020010755options(int cmdline, int *login_sh)
Eric Andersencb57d552001-06-28 07:25:16 +000010756{
10757 char *p;
10758 int val;
10759 int c;
10760
10761 if (cmdline)
10762 minusc = NULL;
10763 while ((p = *argptr) != NULL) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010764 c = *p++;
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010765 if (c != '-' && c != '+')
10766 break;
10767 argptr++;
10768 val = 0; /* val = 0 if c == '+' */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010769 if (c == '-') {
Eric Andersencb57d552001-06-28 07:25:16 +000010770 val = 1;
Denis Vlasenko9f739442006-12-16 23:49:13 +000010771 if (p[0] == '\0' || LONE_DASH(p)) {
Eric Andersen2870d962001-07-02 17:27:21 +000010772 if (!cmdline) {
10773 /* "-" means turn off -x and -v */
10774 if (p[0] == '\0')
10775 xflag = vflag = 0;
10776 /* "--" means reset params */
10777 else if (*argptr == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +000010778 setparam(argptr);
Eric Andersen2870d962001-07-02 17:27:21 +000010779 }
Denys Vlasenkob0b83432011-03-07 12:34:59 +010010780 break; /* "-" or "--" terminates options */
Eric Andersencb57d552001-06-28 07:25:16 +000010781 }
Eric Andersencb57d552001-06-28 07:25:16 +000010782 }
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010783 /* first char was + or - */
Eric Andersencb57d552001-06-28 07:25:16 +000010784 while ((c = *p++) != '\0') {
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010785 /* bash 3.2 indeed handles -c CMD and +c CMD the same */
Eric Andersencb57d552001-06-28 07:25:16 +000010786 if (c == 'c' && cmdline) {
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010787 minusc = p; /* command is after shell args */
Eric Andersencb57d552001-06-28 07:25:16 +000010788 } else if (c == 'o') {
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010789 if (plus_minus_o(*argptr, val)) {
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010790 /* it already printed err message */
10791 return 1; /* error */
10792 }
Eric Andersencb57d552001-06-28 07:25:16 +000010793 if (*argptr)
10794 argptr++;
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010795 } else if (cmdline && (c == 'l')) { /* -l or +l == --login */
Denys Vlasenkoec05df12017-07-31 19:43:47 +020010796 if (login_sh)
10797 *login_sh = 1;
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010798 /* bash does not accept +-login, we also won't */
10799 } else if (cmdline && val && (c == '-')) { /* long options */
Denys Vlasenkoec05df12017-07-31 19:43:47 +020010800 if (strcmp(p, "login") == 0) {
10801 if (login_sh)
10802 *login_sh = 1;
10803 }
Robert Griebl64f70cc2002-05-14 23:22:06 +000010804 break;
Eric Andersencb57d552001-06-28 07:25:16 +000010805 } else {
10806 setoption(c, val);
10807 }
10808 }
10809 }
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010810 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010811}
10812
Eric Andersencb57d552001-06-28 07:25:16 +000010813/*
Eric Andersencb57d552001-06-28 07:25:16 +000010814 * The shift builtin command.
10815 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010816static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010817shiftcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000010818{
10819 int n;
10820 char **ap1, **ap2;
10821
10822 n = 1;
Denis Vlasenko68404f12008-03-17 09:00:54 +000010823 if (argv[1])
Eric Andersencb57d552001-06-28 07:25:16 +000010824 n = number(argv[1]);
10825 if (n > shellparam.nparam)
Denis Vlasenkoc90e1be2008-07-30 15:35:05 +000010826 n = 0; /* bash compat, was = shellparam.nparam; */
Denis Vlasenkob012b102007-02-19 22:43:01 +000010827 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +000010828 shellparam.nparam -= n;
Denis Vlasenko2da584f2007-02-19 22:44:05 +000010829 for (ap1 = shellparam.p; --n >= 0; ap1++) {
Denis Vlasenko01631112007-12-16 17:20:38 +000010830 if (shellparam.malloced)
Denis Vlasenkob012b102007-02-19 22:43:01 +000010831 free(*ap1);
Eric Andersencb57d552001-06-28 07:25:16 +000010832 }
10833 ap2 = shellparam.p;
Denis Vlasenkof7d56652008-03-25 05:51:41 +000010834 while ((*ap2++ = *ap1++) != NULL)
10835 continue;
Denis Vlasenko131ae172007-02-18 13:00:19 +000010836#if ENABLE_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +000010837 shellparam.optind = 1;
10838 shellparam.optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +000010839#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +000010840 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +000010841 return 0;
10842}
10843
Eric Andersencb57d552001-06-28 07:25:16 +000010844/*
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010845 * POSIX requires that 'set' (but not export or readonly) output the
10846 * variables in lexicographic order - by the locale's collating order (sigh).
10847 * Maybe we could keep them in an ordered balanced binary tree
10848 * instead of hashed lists.
10849 * For now just roll 'em through qsort for printing...
10850 */
10851static int
10852showvars(const char *sep_prefix, int on, int off)
10853{
10854 const char *sep;
10855 char **ep, **epend;
10856
10857 ep = listvars(on, off, &epend);
10858 qsort(ep, epend - ep, sizeof(char *), vpcmp);
10859
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010860 sep = *sep_prefix ? " " : sep_prefix;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010861
10862 for (; ep < epend; ep++) {
10863 const char *p;
10864 const char *q;
10865
Denys Vlasenko9c143ce2017-11-02 12:56:24 +010010866 p = endofname(*ep);
10867/* Used to have simple "p = strchrnul(*ep, '=')" here instead, but this
10868 * makes "export -p" to have output not suitable for "eval":
10869 * import os
10870 * os.environ["test-test"]="test"
10871 * if os.fork() == 0:
10872 * os.execv("ash", [ 'ash', '-c', 'eval $(export -p); echo OK' ]) # fixes this
10873 * os.execv("ash", [ 'ash', '-c', 'env | grep test-test' ])
10874 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010875 q = nullstr;
Denys Vlasenko9c143ce2017-11-02 12:56:24 +010010876 if (*p == '=')
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010877 q = single_quote(++p);
10878 out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
10879 }
10880 return 0;
10881}
10882
10883/*
Eric Andersencb57d552001-06-28 07:25:16 +000010884 * The set command builtin.
10885 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010886static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010887setcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +000010888{
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010889 int retval;
10890
Denis Vlasenko68404f12008-03-17 09:00:54 +000010891 if (!argv[1])
Eric Andersenc470f442003-07-28 09:56:35 +000010892 return showvars(nullstr, 0, VUNSET);
Denys Vlasenkob0b83432011-03-07 12:34:59 +010010893
Denis Vlasenkob012b102007-02-19 22:43:01 +000010894 INT_OFF;
Denys Vlasenkoec05df12017-07-31 19:43:47 +020010895 retval = options(/*cmdline:*/ 0, NULL);
Denys Vlasenkob0b83432011-03-07 12:34:59 +010010896 if (retval == 0) { /* if no parse error... */
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010897 optschanged();
10898 if (*argptr != NULL) {
10899 setparam(argptr);
10900 }
Eric Andersencb57d552001-06-28 07:25:16 +000010901 }
Denis Vlasenkob012b102007-02-19 22:43:01 +000010902 INT_ON;
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010903 return retval;
Eric Andersencb57d552001-06-28 07:25:16 +000010904}
10905
Denis Vlasenko131ae172007-02-18 13:00:19 +000010906#if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010907static void FAST_FUNC
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000010908change_random(const char *value)
Eric Andersenef02f822004-03-11 13:34:24 +000010909{
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020010910 uint32_t t;
10911
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000010912 if (value == NULL) {
Eric Andersen16767e22004-03-16 05:14:10 +000010913 /* "get", generate */
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020010914 t = next_random(&random_gen);
Eric Andersen16767e22004-03-16 05:14:10 +000010915 /* set without recursion */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +020010916 setvar(vrandom.var_text, utoa(t), VNOFUNC);
Eric Andersen16767e22004-03-16 05:14:10 +000010917 vrandom.flags &= ~VNOFUNC;
10918 } else {
10919 /* set/reset */
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020010920 t = strtoul(value, NULL, 10);
10921 INIT_RANDOM_T(&random_gen, (t ? t : 1), t);
Eric Andersen16767e22004-03-16 05:14:10 +000010922 }
Eric Andersenef02f822004-03-11 13:34:24 +000010923}
Eric Andersen16767e22004-03-16 05:14:10 +000010924#endif
10925
Denis Vlasenko131ae172007-02-18 13:00:19 +000010926#if ENABLE_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +000010927static int
Denys Vlasenko35c2a132016-10-26 17:34:26 +020010928getopts(char *optstr, char *optvar, char **optfirst)
Eric Andersencb57d552001-06-28 07:25:16 +000010929{
10930 char *p, *q;
10931 char c = '?';
10932 int done = 0;
Denys Vlasenko9c541002015-10-07 15:44:36 +020010933 char sbuf[2];
Eric Andersena48b0a32003-10-22 10:56:47 +000010934 char **optnext;
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010935 int ind = shellparam.optind;
10936 int off = shellparam.optoff;
Eric Andersencb57d552001-06-28 07:25:16 +000010937
Denys Vlasenko9c541002015-10-07 15:44:36 +020010938 sbuf[1] = '\0';
10939
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010940 shellparam.optind = -1;
10941 optnext = optfirst + ind - 1;
Eric Andersena48b0a32003-10-22 10:56:47 +000010942
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010943 if (ind <= 1 || off < 0 || (int)strlen(optnext[-1]) < off)
Eric Andersencb57d552001-06-28 07:25:16 +000010944 p = NULL;
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010945 else
10946 p = optnext[-1] + off;
Eric Andersencb57d552001-06-28 07:25:16 +000010947 if (p == NULL || *p == '\0') {
10948 /* Current word is done, advance */
Eric Andersencb57d552001-06-28 07:25:16 +000010949 p = *optnext;
10950 if (p == NULL || *p != '-' || *++p == '\0') {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010951 atend:
Denys Vlasenko9832bba2017-08-15 15:44:41 +020010952 unsetvar("OPTARG");
Eric Andersencb57d552001-06-28 07:25:16 +000010953 p = NULL;
10954 done = 1;
10955 goto out;
10956 }
10957 optnext++;
Denis Vlasenko9f739442006-12-16 23:49:13 +000010958 if (LONE_DASH(p)) /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +000010959 goto atend;
10960 }
10961
10962 c = *p++;
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +000010963 for (q = optstr; *q != c;) {
Eric Andersencb57d552001-06-28 07:25:16 +000010964 if (*q == '\0') {
Denys Vlasenko9832bba2017-08-15 15:44:41 +020010965 /* OPTERR is a bashism */
10966 const char *cp = lookupvar("OPTERR");
10967 if ((cp && LONE_CHAR(cp, '0'))
10968 || (optstr[0] == ':')
10969 ) {
Denys Vlasenko9c541002015-10-07 15:44:36 +020010970 sbuf[0] = c;
10971 /*sbuf[1] = '\0'; - already is */
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010972 setvar0("OPTARG", sbuf);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010973 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010974 fprintf(stderr, "Illegal option -%c\n", c);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010975 unsetvar("OPTARG");
Eric Andersencb57d552001-06-28 07:25:16 +000010976 }
10977 c = '?';
Eric Andersenc470f442003-07-28 09:56:35 +000010978 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +000010979 }
10980 if (*++q == ':')
10981 q++;
10982 }
10983
10984 if (*++q == ':') {
10985 if (*p == '\0' && (p = *optnext) == NULL) {
Denys Vlasenko9832bba2017-08-15 15:44:41 +020010986 /* OPTERR is a bashism */
10987 const char *cp = lookupvar("OPTERR");
10988 if ((cp && LONE_CHAR(cp, '0'))
10989 || (optstr[0] == ':')
10990 ) {
Denys Vlasenko9c541002015-10-07 15:44:36 +020010991 sbuf[0] = c;
10992 /*sbuf[1] = '\0'; - already is */
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010993 setvar0("OPTARG", sbuf);
Eric Andersencb57d552001-06-28 07:25:16 +000010994 c = ':';
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010995 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010996 fprintf(stderr, "No arg for -%c option\n", c);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010997 unsetvar("OPTARG");
Eric Andersencb57d552001-06-28 07:25:16 +000010998 c = '?';
10999 }
Eric Andersenc470f442003-07-28 09:56:35 +000011000 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +000011001 }
11002
11003 if (p == *optnext)
11004 optnext++;
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020011005 setvar0("OPTARG", p);
Eric Andersencb57d552001-06-28 07:25:16 +000011006 p = NULL;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011007 } else
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020011008 setvar0("OPTARG", nullstr);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011009 out:
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020011010 ind = optnext - optfirst + 1;
11011 setvar("OPTIND", itoa(ind), VNOFUNC);
Denys Vlasenko9c541002015-10-07 15:44:36 +020011012 sbuf[0] = c;
11013 /*sbuf[1] = '\0'; - already is */
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020011014 setvar0(optvar, sbuf);
11015
11016 shellparam.optoff = p ? p - *(optnext - 1) : -1;
11017 shellparam.optind = ind;
11018
Eric Andersencb57d552001-06-28 07:25:16 +000011019 return done;
11020}
Eric Andersenc470f442003-07-28 09:56:35 +000011021
11022/*
11023 * The getopts builtin. Shellparam.optnext points to the next argument
11024 * to be processed. Shellparam.optptr points to the next character to
11025 * be processed in the current argument. If shellparam.optnext is NULL,
11026 * then it's the first time getopts has been called.
11027 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020011028static int FAST_FUNC
Eric Andersenc470f442003-07-28 09:56:35 +000011029getoptscmd(int argc, char **argv)
11030{
11031 char **optbase;
11032
11033 if (argc < 3)
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +000011034 ash_msg_and_raise_error("usage: getopts optstring var [arg]");
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011035 if (argc == 3) {
Eric Andersenc470f442003-07-28 09:56:35 +000011036 optbase = shellparam.p;
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020011037 if ((unsigned)shellparam.optind > shellparam.nparam + 1) {
Eric Andersenc470f442003-07-28 09:56:35 +000011038 shellparam.optind = 1;
11039 shellparam.optoff = -1;
11040 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011041 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000011042 optbase = &argv[3];
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020011043 if ((unsigned)shellparam.optind > argc - 2) {
Eric Andersenc470f442003-07-28 09:56:35 +000011044 shellparam.optind = 1;
11045 shellparam.optoff = -1;
11046 }
11047 }
11048
Denys Vlasenko35c2a132016-10-26 17:34:26 +020011049 return getopts(argv[1], argv[2], optbase);
Eric Andersenc470f442003-07-28 09:56:35 +000011050}
Denis Vlasenko131ae172007-02-18 13:00:19 +000011051#endif /* ASH_GETOPTS */
Eric Andersencb57d552001-06-28 07:25:16 +000011052
Eric Andersencb57d552001-06-28 07:25:16 +000011053
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011054/* ============ Shell parser */
Eric Andersencb57d552001-06-28 07:25:16 +000011055
Denis Vlasenkob07a4962008-06-22 13:16:23 +000011056struct heredoc {
11057 struct heredoc *next; /* next here document in list */
11058 union node *here; /* redirection node */
11059 char *eofmark; /* string indicating end of input */
11060 smallint striptabs; /* if set, strip leading tabs */
11061};
11062
11063static smallint tokpushback; /* last token pushed back */
Denis Vlasenkob07a4962008-06-22 13:16:23 +000011064static smallint quoteflag; /* set if (part of) last token was quoted */
11065static token_id_t lasttoken; /* last token read (integer id Txxx) */
11066static struct heredoc *heredoclist; /* list of here documents to read */
11067static char *wordtext; /* text of last word returned by readtoken */
11068static struct nodelist *backquotelist;
11069static union node *redirnode;
11070static struct heredoc *heredoc;
Denis Vlasenko99eb8502007-02-23 21:09:49 +000011071
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020011072static const char *
11073tokname(char *buf, int tok)
11074{
11075 if (tok < TSEMI)
Denys Vlasenko888527c2016-10-02 16:54:17 +020011076 return tokname_array[tok];
11077 sprintf(buf, "\"%s\"", tokname_array[tok]);
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020011078 return buf;
11079}
11080
11081/* raise_error_unexpected_syntax:
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011082 * Called when an unexpected token is read during the parse. The argument
11083 * is the token that is expected, or -1 if more than one type of token can
11084 * occur at this point.
11085 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000011086static void raise_error_unexpected_syntax(int) NORETURN;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011087static void
11088raise_error_unexpected_syntax(int token)
11089{
11090 char msg[64];
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020011091 char buf[16];
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011092 int l;
11093
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020011094 l = sprintf(msg, "unexpected %s", tokname(buf, lasttoken));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011095 if (token >= 0)
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020011096 sprintf(msg + l, " (expecting %s)", tokname(buf, token));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011097 raise_error_syntax(msg);
11098 /* NOTREACHED */
11099}
Eric Andersencb57d552001-06-28 07:25:16 +000011100
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011101/* parsing is heavily cross-recursive, need these forward decls */
11102static union node *andor(void);
11103static union node *pipeline(void);
11104static union node *parse_command(void);
11105static void parseheredoc(void);
Ron Yorstonc0e00762015-10-29 11:30:55 +000011106static int peektoken(void);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011107static int readtoken(void);
Eric Andersencb57d552001-06-28 07:25:16 +000011108
Eric Andersenc470f442003-07-28 09:56:35 +000011109static union node *
11110list(int nlflag)
Eric Andersencb57d552001-06-28 07:25:16 +000011111{
11112 union node *n1, *n2, *n3;
11113 int tok;
11114
Eric Andersencb57d552001-06-28 07:25:16 +000011115 n1 = NULL;
11116 for (;;) {
Ron Yorstonc0e00762015-10-29 11:30:55 +000011117 switch (peektoken()) {
11118 case TNL:
11119 if (!(nlflag & 1))
11120 break;
11121 parseheredoc();
11122 return n1;
11123
11124 case TEOF:
11125 if (!n1 && (nlflag & 1))
11126 n1 = NODE_EOF;
11127 parseheredoc();
11128 return n1;
11129 }
11130
11131 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Denys Vlasenko888527c2016-10-02 16:54:17 +020011132 if (nlflag == 2 && ((1 << peektoken()) & tokendlist))
Ron Yorstonc0e00762015-10-29 11:30:55 +000011133 return n1;
11134 nlflag |= 2;
11135
Eric Andersencb57d552001-06-28 07:25:16 +000011136 n2 = andor();
11137 tok = readtoken();
11138 if (tok == TBACKGND) {
Eric Andersenc470f442003-07-28 09:56:35 +000011139 if (n2->type == NPIPE) {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +000011140 n2->npipe.pipe_backgnd = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011141 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000011142 if (n2->type != NREDIR) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011143 n3 = stzalloc(sizeof(struct nredir));
Eric Andersenc470f442003-07-28 09:56:35 +000011144 n3->nredir.n = n2;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011145 /*n3->nredir.redirect = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011146 n2 = n3;
11147 }
11148 n2->type = NBACKGND;
Eric Andersencb57d552001-06-28 07:25:16 +000011149 }
11150 }
11151 if (n1 == NULL) {
11152 n1 = n2;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011153 } else {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011154 n3 = stzalloc(sizeof(struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +000011155 n3->type = NSEMI;
11156 n3->nbinary.ch1 = n1;
11157 n3->nbinary.ch2 = n2;
11158 n1 = n3;
11159 }
11160 switch (tok) {
Ron Yorstonc0e00762015-10-29 11:30:55 +000011161 case TNL:
11162 case TEOF:
11163 tokpushback = 1;
11164 /* fall through */
Eric Andersencb57d552001-06-28 07:25:16 +000011165 case TBACKGND:
11166 case TSEMI:
Eric Andersencb57d552001-06-28 07:25:16 +000011167 break;
Eric Andersencb57d552001-06-28 07:25:16 +000011168 default:
Ron Yorstonc0e00762015-10-29 11:30:55 +000011169 if ((nlflag & 1))
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011170 raise_error_unexpected_syntax(-1);
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011171 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011172 return n1;
11173 }
11174 }
11175}
11176
Eric Andersenc470f442003-07-28 09:56:35 +000011177static union node *
11178andor(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011179{
Eric Andersencb57d552001-06-28 07:25:16 +000011180 union node *n1, *n2, *n3;
11181 int t;
11182
Eric Andersencb57d552001-06-28 07:25:16 +000011183 n1 = pipeline();
11184 for (;;) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011185 t = readtoken();
11186 if (t == TAND) {
Eric Andersencb57d552001-06-28 07:25:16 +000011187 t = NAND;
11188 } else if (t == TOR) {
11189 t = NOR;
11190 } else {
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011191 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011192 return n1;
11193 }
Eric Andersenc470f442003-07-28 09:56:35 +000011194 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000011195 n2 = pipeline();
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011196 n3 = stzalloc(sizeof(struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +000011197 n3->type = t;
11198 n3->nbinary.ch1 = n1;
11199 n3->nbinary.ch2 = n2;
11200 n1 = n3;
11201 }
11202}
11203
Eric Andersenc470f442003-07-28 09:56:35 +000011204static union node *
11205pipeline(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011206{
Eric Andersencb57d552001-06-28 07:25:16 +000011207 union node *n1, *n2, *pipenode;
11208 struct nodelist *lp, *prev;
11209 int negate;
11210
11211 negate = 0;
11212 TRACE(("pipeline: entered\n"));
11213 if (readtoken() == TNOT) {
11214 negate = !negate;
Eric Andersenc470f442003-07-28 09:56:35 +000011215 checkkwd = CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000011216 } else
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011217 tokpushback = 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011218 n1 = parse_command();
Eric Andersencb57d552001-06-28 07:25:16 +000011219 if (readtoken() == TPIPE) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011220 pipenode = stzalloc(sizeof(struct npipe));
Eric Andersencb57d552001-06-28 07:25:16 +000011221 pipenode->type = NPIPE;
Denis Vlasenko2dc240c2008-07-24 06:07:50 +000011222 /*pipenode->npipe.pipe_backgnd = 0; - stzalloc did it */
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011223 lp = stzalloc(sizeof(struct nodelist));
Eric Andersencb57d552001-06-28 07:25:16 +000011224 pipenode->npipe.cmdlist = lp;
11225 lp->n = n1;
11226 do {
11227 prev = lp;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011228 lp = stzalloc(sizeof(struct nodelist));
Eric Andersenc470f442003-07-28 09:56:35 +000011229 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011230 lp->n = parse_command();
Eric Andersencb57d552001-06-28 07:25:16 +000011231 prev->next = lp;
11232 } while (readtoken() == TPIPE);
11233 lp->next = NULL;
11234 n1 = pipenode;
11235 }
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011236 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011237 if (negate) {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011238 n2 = stzalloc(sizeof(struct nnot));
Eric Andersencb57d552001-06-28 07:25:16 +000011239 n2->type = NNOT;
11240 n2->nnot.com = n1;
11241 return n2;
Denis Vlasenko2da584f2007-02-19 22:44:05 +000011242 }
11243 return n1;
Eric Andersencb57d552001-06-28 07:25:16 +000011244}
11245
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011246static union node *
11247makename(void)
11248{
11249 union node *n;
11250
Denis Vlasenko597906c2008-02-20 16:38:54 +000011251 n = stzalloc(sizeof(struct narg));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011252 n->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011253 /*n->narg.next = NULL; - stzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011254 n->narg.text = wordtext;
11255 n->narg.backquote = backquotelist;
11256 return n;
11257}
11258
11259static void
11260fixredir(union node *n, const char *text, int err)
11261{
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000011262 int fd;
11263
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011264 TRACE(("Fix redir %s %d\n", text, err));
11265 if (!err)
11266 n->ndup.vname = NULL;
11267
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000011268 fd = bb_strtou(text, NULL, 10);
11269 if (!errno && fd >= 0)
11270 n->ndup.dupfd = fd;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011271 else if (LONE_DASH(text))
11272 n->ndup.dupfd = -1;
11273 else {
11274 if (err)
Denis Vlasenko559691a2008-10-05 18:39:31 +000011275 raise_error_syntax("bad fd number");
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011276 n->ndup.vname = makename();
11277 }
11278}
11279
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011280static void
11281parsefname(void)
11282{
11283 union node *n = redirnode;
11284
Denys Vlasenkoa7328982017-07-29 19:57:28 +020011285 if (n->type == NHERE)
11286 checkkwd = CHKEOFMARK;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011287 if (readtoken() != TWORD)
11288 raise_error_unexpected_syntax(-1);
11289 if (n->type == NHERE) {
11290 struct heredoc *here = heredoc;
11291 struct heredoc *p;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011292
11293 if (quoteflag == 0)
11294 n->type = NXHERE;
11295 TRACE(("Here document %d\n", n->type));
Denys Vlasenkob6c84342009-08-29 20:23:20 +020011296 rmescapes(wordtext, 0);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011297 here->eofmark = wordtext;
11298 here->next = NULL;
11299 if (heredoclist == NULL)
11300 heredoclist = here;
11301 else {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011302 for (p = heredoclist; p->next; p = p->next)
11303 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011304 p->next = here;
11305 }
11306 } else if (n->type == NTOFD || n->type == NFROMFD) {
11307 fixredir(n, wordtext, 0);
11308 } else {
11309 n->nfile.fname = makename();
11310 }
11311}
Eric Andersencb57d552001-06-28 07:25:16 +000011312
Eric Andersenc470f442003-07-28 09:56:35 +000011313static union node *
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011314simplecmd(void)
11315{
11316 union node *args, **app;
11317 union node *n = NULL;
11318 union node *vars, **vpp;
11319 union node **rpp, *redir;
11320 int savecheckkwd;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011321#if BASH_TEST2
Denis Vlasenko80591b02008-03-25 07:49:43 +000011322 smallint double_brackets_flag = 0;
11323#endif
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011324 IF_BASH_FUNCTION(smallint function_flag = 0;)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011325
11326 args = NULL;
11327 app = &args;
11328 vars = NULL;
11329 vpp = &vars;
11330 redir = NULL;
11331 rpp = &redir;
11332
11333 savecheckkwd = CHKALIAS;
11334 for (;;) {
Denis Vlasenko80591b02008-03-25 07:49:43 +000011335 int t;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011336 checkkwd = savecheckkwd;
Denis Vlasenko80591b02008-03-25 07:49:43 +000011337 t = readtoken();
11338 switch (t) {
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011339#if BASH_FUNCTION
Ron Yorston95ebcf72015-11-03 09:42:23 +000011340 case TFUNCTION:
11341 if (peektoken() != TWORD)
11342 raise_error_unexpected_syntax(TWORD);
11343 function_flag = 1;
11344 break;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011345#endif
11346#if BASH_TEST2
Denis Vlasenko80591b02008-03-25 07:49:43 +000011347 case TAND: /* "&&" */
11348 case TOR: /* "||" */
11349 if (!double_brackets_flag) {
11350 tokpushback = 1;
11351 goto out;
11352 }
11353 wordtext = (char *) (t == TAND ? "-a" : "-o");
11354#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011355 case TWORD:
Denis Vlasenko597906c2008-02-20 16:38:54 +000011356 n = stzalloc(sizeof(struct narg));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011357 n->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011358 /*n->narg.next = NULL; - stzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011359 n->narg.text = wordtext;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011360#if BASH_TEST2
Denis Vlasenko80591b02008-03-25 07:49:43 +000011361 if (strcmp("[[", wordtext) == 0)
11362 double_brackets_flag = 1;
11363 else if (strcmp("]]", wordtext) == 0)
11364 double_brackets_flag = 0;
11365#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011366 n->narg.backquote = backquotelist;
11367 if (savecheckkwd && isassignment(wordtext)) {
11368 *vpp = n;
11369 vpp = &n->narg.next;
11370 } else {
11371 *app = n;
11372 app = &n->narg.next;
11373 savecheckkwd = 0;
11374 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011375#if BASH_FUNCTION
Ron Yorston95ebcf72015-11-03 09:42:23 +000011376 if (function_flag) {
11377 checkkwd = CHKNL | CHKKWD;
11378 switch (peektoken()) {
11379 case TBEGIN:
11380 case TIF:
11381 case TCASE:
11382 case TUNTIL:
11383 case TWHILE:
11384 case TFOR:
11385 goto do_func;
11386 case TLP:
11387 function_flag = 0;
11388 break;
11389 case TWORD:
11390 if (strcmp("[[", wordtext) == 0)
11391 goto do_func;
11392 /* fall through */
11393 default:
11394 raise_error_unexpected_syntax(-1);
11395 }
11396 }
11397#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011398 break;
11399 case TREDIR:
11400 *rpp = n = redirnode;
11401 rpp = &n->nfile.next;
11402 parsefname(); /* read name of redirection file */
11403 break;
11404 case TLP:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011405 IF_BASH_FUNCTION(do_func:)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011406 if (args && app == &args->narg.next
11407 && !vars && !redir
11408 ) {
11409 struct builtincmd *bcmd;
11410 const char *name;
11411
11412 /* We have a function */
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011413 if (IF_BASH_FUNCTION(!function_flag &&) readtoken() != TRP)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011414 raise_error_unexpected_syntax(TRP);
11415 name = n->narg.text;
11416 if (!goodname(name)
11417 || ((bcmd = find_builtin(name)) && IS_BUILTIN_SPECIAL(bcmd))
11418 ) {
Denis Vlasenko559691a2008-10-05 18:39:31 +000011419 raise_error_syntax("bad function name");
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011420 }
11421 n->type = NDEFUN;
11422 checkkwd = CHKNL | CHKKWD | CHKALIAS;
11423 n->narg.next = parse_command();
11424 return n;
11425 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011426 IF_BASH_FUNCTION(function_flag = 0;)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011427 /* fall through */
11428 default:
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011429 tokpushback = 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011430 goto out;
11431 }
11432 }
11433 out:
11434 *app = NULL;
11435 *vpp = NULL;
11436 *rpp = NULL;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011437 n = stzalloc(sizeof(struct ncmd));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011438 n->type = NCMD;
11439 n->ncmd.args = args;
11440 n->ncmd.assign = vars;
11441 n->ncmd.redirect = redir;
11442 return n;
11443}
11444
11445static union node *
11446parse_command(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011447{
Eric Andersencb57d552001-06-28 07:25:16 +000011448 union node *n1, *n2;
11449 union node *ap, **app;
11450 union node *cp, **cpp;
11451 union node *redir, **rpp;
Eric Andersenc470f442003-07-28 09:56:35 +000011452 union node **rpp2;
Eric Andersencb57d552001-06-28 07:25:16 +000011453 int t;
11454
11455 redir = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +000011456 rpp2 = &redir;
Eric Andersen88cec252001-09-06 17:35:20 +000011457
Eric Andersencb57d552001-06-28 07:25:16 +000011458 switch (readtoken()) {
Eric Andersenc470f442003-07-28 09:56:35 +000011459 default:
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011460 raise_error_unexpected_syntax(-1);
Eric Andersenc470f442003-07-28 09:56:35 +000011461 /* NOTREACHED */
Eric Andersencb57d552001-06-28 07:25:16 +000011462 case TIF:
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011463 n1 = stzalloc(sizeof(struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +000011464 n1->type = NIF;
11465 n1->nif.test = list(0);
11466 if (readtoken() != TTHEN)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011467 raise_error_unexpected_syntax(TTHEN);
Eric Andersencb57d552001-06-28 07:25:16 +000011468 n1->nif.ifpart = list(0);
11469 n2 = n1;
11470 while (readtoken() == TELIF) {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011471 n2->nif.elsepart = stzalloc(sizeof(struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +000011472 n2 = n2->nif.elsepart;
11473 n2->type = NIF;
11474 n2->nif.test = list(0);
11475 if (readtoken() != TTHEN)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011476 raise_error_unexpected_syntax(TTHEN);
Eric Andersencb57d552001-06-28 07:25:16 +000011477 n2->nif.ifpart = list(0);
11478 }
11479 if (lasttoken == TELSE)
11480 n2->nif.elsepart = list(0);
11481 else {
11482 n2->nif.elsepart = NULL;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011483 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011484 }
Eric Andersenc470f442003-07-28 09:56:35 +000011485 t = TFI;
Eric Andersencb57d552001-06-28 07:25:16 +000011486 break;
11487 case TWHILE:
Eric Andersenc470f442003-07-28 09:56:35 +000011488 case TUNTIL: {
Eric Andersencb57d552001-06-28 07:25:16 +000011489 int got;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011490 n1 = stzalloc(sizeof(struct nbinary));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011491 n1->type = (lasttoken == TWHILE) ? NWHILE : NUNTIL;
Eric Andersencb57d552001-06-28 07:25:16 +000011492 n1->nbinary.ch1 = list(0);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011493 got = readtoken();
11494 if (got != TDO) {
Denys Vlasenko888527c2016-10-02 16:54:17 +020011495 TRACE(("expecting DO got '%s' %s\n", tokname_array[got],
Denis Vlasenko131ae172007-02-18 13:00:19 +000011496 got == TWORD ? wordtext : ""));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011497 raise_error_unexpected_syntax(TDO);
Eric Andersencb57d552001-06-28 07:25:16 +000011498 }
11499 n1->nbinary.ch2 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +000011500 t = TDONE;
Eric Andersencb57d552001-06-28 07:25:16 +000011501 break;
11502 }
11503 case TFOR:
Denis Vlasenko2dc240c2008-07-24 06:07:50 +000011504 if (readtoken() != TWORD || quoteflag || !goodname(wordtext))
Denis Vlasenko559691a2008-10-05 18:39:31 +000011505 raise_error_syntax("bad for loop variable");
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011506 n1 = stzalloc(sizeof(struct nfor));
Eric Andersencb57d552001-06-28 07:25:16 +000011507 n1->type = NFOR;
11508 n1->nfor.var = wordtext;
Ron Yorstonab80e012015-08-03 13:46:00 +010011509 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000011510 if (readtoken() == TIN) {
11511 app = &ap;
11512 while (readtoken() == TWORD) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011513 n2 = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000011514 n2->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011515 /*n2->narg.next = NULL; - stzalloc did it */
Eric Andersencb57d552001-06-28 07:25:16 +000011516 n2->narg.text = wordtext;
11517 n2->narg.backquote = backquotelist;
11518 *app = n2;
11519 app = &n2->narg.next;
11520 }
11521 *app = NULL;
11522 n1->nfor.args = ap;
11523 if (lasttoken != TNL && lasttoken != TSEMI)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011524 raise_error_unexpected_syntax(-1);
Eric Andersencb57d552001-06-28 07:25:16 +000011525 } else {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011526 n2 = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000011527 n2->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011528 /*n2->narg.next = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011529 n2->narg.text = (char *)dolatstr;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011530 /*n2->narg.backquote = NULL;*/
Eric Andersencb57d552001-06-28 07:25:16 +000011531 n1->nfor.args = n2;
11532 /*
11533 * Newline or semicolon here is optional (but note
11534 * that the original Bourne shell only allowed NL).
11535 */
Ron Yorstonab80e012015-08-03 13:46:00 +010011536 if (lasttoken != TSEMI)
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011537 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011538 }
Eric Andersenc470f442003-07-28 09:56:35 +000011539 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000011540 if (readtoken() != TDO)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011541 raise_error_unexpected_syntax(TDO);
Eric Andersencb57d552001-06-28 07:25:16 +000011542 n1->nfor.body = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +000011543 t = TDONE;
Eric Andersencb57d552001-06-28 07:25:16 +000011544 break;
11545 case TCASE:
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011546 n1 = stzalloc(sizeof(struct ncase));
Eric Andersencb57d552001-06-28 07:25:16 +000011547 n1->type = NCASE;
11548 if (readtoken() != TWORD)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011549 raise_error_unexpected_syntax(TWORD);
Denis Vlasenko597906c2008-02-20 16:38:54 +000011550 n1->ncase.expr = n2 = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000011551 n2->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011552 /*n2->narg.next = NULL; - stzalloc did it */
Eric Andersencb57d552001-06-28 07:25:16 +000011553 n2->narg.text = wordtext;
11554 n2->narg.backquote = backquotelist;
Ron Yorston383b8852015-08-03 13:46:25 +010011555 checkkwd = CHKNL | CHKKWD | CHKALIAS;
11556 if (readtoken() != TIN)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011557 raise_error_unexpected_syntax(TIN);
Eric Andersencb57d552001-06-28 07:25:16 +000011558 cpp = &n1->ncase.cases;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011559 next_case:
Eric Andersenc470f442003-07-28 09:56:35 +000011560 checkkwd = CHKNL | CHKKWD;
11561 t = readtoken();
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011562 while (t != TESAC) {
Eric Andersencb57d552001-06-28 07:25:16 +000011563 if (lasttoken == TLP)
11564 readtoken();
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011565 *cpp = cp = stzalloc(sizeof(struct nclist));
Eric Andersencb57d552001-06-28 07:25:16 +000011566 cp->type = NCLIST;
11567 app = &cp->nclist.pattern;
11568 for (;;) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011569 *app = ap = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000011570 ap->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011571 /*ap->narg.next = NULL; - stzalloc did it */
Eric Andersencb57d552001-06-28 07:25:16 +000011572 ap->narg.text = wordtext;
11573 ap->narg.backquote = backquotelist;
Eric Andersenc470f442003-07-28 09:56:35 +000011574 if (readtoken() != TPIPE)
Eric Andersencb57d552001-06-28 07:25:16 +000011575 break;
11576 app = &ap->narg.next;
11577 readtoken();
11578 }
Denis Vlasenko597906c2008-02-20 16:38:54 +000011579 //ap->narg.next = NULL;
Eric Andersencb57d552001-06-28 07:25:16 +000011580 if (lasttoken != TRP)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011581 raise_error_unexpected_syntax(TRP);
Eric Andersenc470f442003-07-28 09:56:35 +000011582 cp->nclist.body = list(2);
Eric Andersencb57d552001-06-28 07:25:16 +000011583
Eric Andersenc470f442003-07-28 09:56:35 +000011584 cpp = &cp->nclist.next;
11585
11586 checkkwd = CHKNL | CHKKWD;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011587 t = readtoken();
11588 if (t != TESAC) {
Eric Andersencb57d552001-06-28 07:25:16 +000011589 if (t != TENDCASE)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011590 raise_error_unexpected_syntax(TENDCASE);
11591 goto next_case;
Eric Andersencb57d552001-06-28 07:25:16 +000011592 }
Eric Andersenc470f442003-07-28 09:56:35 +000011593 }
Eric Andersencb57d552001-06-28 07:25:16 +000011594 *cpp = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +000011595 goto redir;
Eric Andersencb57d552001-06-28 07:25:16 +000011596 case TLP:
Denis Vlasenko597906c2008-02-20 16:38:54 +000011597 n1 = stzalloc(sizeof(struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +000011598 n1->type = NSUBSHELL;
11599 n1->nredir.n = list(0);
Denis Vlasenko597906c2008-02-20 16:38:54 +000011600 /*n1->nredir.redirect = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011601 t = TRP;
Eric Andersencb57d552001-06-28 07:25:16 +000011602 break;
11603 case TBEGIN:
11604 n1 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +000011605 t = TEND;
Eric Andersencb57d552001-06-28 07:25:16 +000011606 break;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011607 IF_BASH_FUNCTION(case TFUNCTION:)
Eric Andersencb57d552001-06-28 07:25:16 +000011608 case TWORD:
Eric Andersenc470f442003-07-28 09:56:35 +000011609 case TREDIR:
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011610 tokpushback = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000011611 return simplecmd();
Eric Andersencb57d552001-06-28 07:25:16 +000011612 }
11613
Eric Andersenc470f442003-07-28 09:56:35 +000011614 if (readtoken() != t)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011615 raise_error_unexpected_syntax(t);
Eric Andersenc470f442003-07-28 09:56:35 +000011616
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011617 redir:
Eric Andersencb57d552001-06-28 07:25:16 +000011618 /* Now check for redirection which may follow command */
Eric Andersenc470f442003-07-28 09:56:35 +000011619 checkkwd = CHKKWD | CHKALIAS;
11620 rpp = rpp2;
Eric Andersencb57d552001-06-28 07:25:16 +000011621 while (readtoken() == TREDIR) {
11622 *rpp = n2 = redirnode;
11623 rpp = &n2->nfile.next;
11624 parsefname();
11625 }
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011626 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011627 *rpp = NULL;
11628 if (redir) {
11629 if (n1->type != NSUBSHELL) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011630 n2 = stzalloc(sizeof(struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +000011631 n2->type = NREDIR;
11632 n2->nredir.n = n1;
11633 n1 = n2;
11634 }
11635 n1->nredir.redirect = redir;
11636 }
Eric Andersencb57d552001-06-28 07:25:16 +000011637 return n1;
11638}
11639
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011640#if BASH_DOLLAR_SQUOTE
Denys Vlasenko37dc08b2016-10-02 04:38:07 +020011641static int
11642decode_dollar_squote(void)
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011643{
11644 static const char C_escapes[] ALIGN1 = "nrbtfav""x\\01234567";
11645 int c, cnt;
11646 char *p;
11647 char buf[4];
11648
11649 c = pgetc();
11650 p = strchr(C_escapes, c);
11651 if (p) {
11652 buf[0] = c;
11653 p = buf;
11654 cnt = 3;
11655 if ((unsigned char)(c - '0') <= 7) { /* \ooo */
11656 do {
11657 c = pgetc();
11658 *++p = c;
11659 } while ((unsigned char)(c - '0') <= 7 && --cnt);
11660 pungetc();
11661 } else if (c == 'x') { /* \xHH */
11662 do {
11663 c = pgetc();
11664 *++p = c;
11665 } while (isxdigit(c) && --cnt);
11666 pungetc();
11667 if (cnt == 3) { /* \x but next char is "bad" */
11668 c = 'x';
11669 goto unrecognized;
11670 }
11671 } else { /* simple seq like \\ or \t */
11672 p++;
11673 }
11674 *p = '\0';
11675 p = buf;
11676 c = bb_process_escape_sequence((void*)&p);
11677 } else { /* unrecognized "\z": print both chars unless ' or " */
11678 if (c != '\'' && c != '"') {
11679 unrecognized:
11680 c |= 0x100; /* "please encode \, then me" */
11681 }
11682 }
11683 return c;
11684}
11685#endif
11686
Denys Vlasenko46999802017-07-29 21:12:29 +020011687/* Used by expandstr to get here-doc like behaviour. */
11688#define FAKEEOFMARK ((char*)(uintptr_t)1)
11689
11690static ALWAYS_INLINE int
11691realeofmark(const char *eofmark)
11692{
11693 return eofmark && eofmark != FAKEEOFMARK;
11694}
11695
Eric Andersencb57d552001-06-28 07:25:16 +000011696/*
11697 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
11698 * is not NULL, read a here document. In the latter case, eofmark is the
11699 * word which marks the end of the document and striptabs is true if
Denys Vlasenkocd716832009-11-28 22:14:02 +010011700 * leading tabs should be stripped from the document. The argument c
Eric Andersencb57d552001-06-28 07:25:16 +000011701 * is the first character of the input token or document.
11702 *
11703 * Because C does not have internal subroutines, I have simulated them
11704 * using goto's to implement the subroutine linkage. The following macros
11705 * will run code that appears at the end of readtoken1.
11706 */
Eric Andersen2870d962001-07-02 17:27:21 +000011707#define CHECKEND() {goto checkend; checkend_return:;}
11708#define PARSEREDIR() {goto parseredir; parseredir_return:;}
11709#define PARSESUB() {goto parsesub; parsesub_return:;}
11710#define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
11711#define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
11712#define PARSEARITH() {goto parsearith; parsearith_return:;}
Eric Andersencb57d552001-06-28 07:25:16 +000011713static int
Denys Vlasenkocd716832009-11-28 22:14:02 +010011714readtoken1(int c, int syntax, char *eofmark, int striptabs)
Manuel Novoa III 16815d42001-08-10 19:36:07 +000011715{
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011716 /* NB: syntax parameter fits into smallint */
Denys Vlasenkocd716832009-11-28 22:14:02 +010011717 /* c parameter is an unsigned char or PEOF or PEOA */
Eric Andersencb57d552001-06-28 07:25:16 +000011718 char *out;
Denys Vlasenko50e6d422016-09-30 11:35:54 +020011719 size_t len;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011720 struct nodelist *bqlist;
11721 smallint quotef;
11722 smallint dblquote;
11723 smallint oldstyle;
Denys Vlasenko0b883582016-12-23 16:49:07 +010011724 IF_FEATURE_SH_MATH(smallint prevsyntax;) /* syntax before arithmetic */
Denis Vlasenko46a53062007-09-24 18:30:02 +000011725 smallint pssyntax; /* we are expanding a prompt string */
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011726 int varnest; /* levels of variables expansion */
Denys Vlasenko0b883582016-12-23 16:49:07 +010011727 IF_FEATURE_SH_MATH(int arinest;) /* levels of arithmetic expansion */
11728 IF_FEATURE_SH_MATH(int parenlevel;) /* levels of parens in arithmetic */
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011729 int dqvarnest; /* levels of variables expansion within double quotes */
11730
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011731 IF_BASH_DOLLAR_SQUOTE(smallint bash_dollar_squote = 0;)
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011732
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011733 startlinno = g_parsefile->linno;
Eric Andersencb57d552001-06-28 07:25:16 +000011734 bqlist = NULL;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011735 quotef = 0;
Denys Vlasenko0b883582016-12-23 16:49:07 +010011736 IF_FEATURE_SH_MATH(prevsyntax = 0;)
Denys Vlasenko5f0a75f2017-07-29 22:58:44 +020011737#if ENABLE_ASH_EXPAND_PRMT
Denis Vlasenko46a53062007-09-24 18:30:02 +000011738 pssyntax = (syntax == PSSYNTAX);
11739 if (pssyntax)
11740 syntax = DQSYNTAX;
Denys Vlasenko5f0a75f2017-07-29 22:58:44 +020011741#else
11742 pssyntax = 0; /* constant */
11743#endif
Denis Vlasenko46a53062007-09-24 18:30:02 +000011744 dblquote = (syntax == DQSYNTAX);
Eric Andersencb57d552001-06-28 07:25:16 +000011745 varnest = 0;
Denys Vlasenko0b883582016-12-23 16:49:07 +010011746 IF_FEATURE_SH_MATH(arinest = 0;)
11747 IF_FEATURE_SH_MATH(parenlevel = 0;)
Eric Andersencb57d552001-06-28 07:25:16 +000011748 dqvarnest = 0;
11749
11750 STARTSTACKSTR(out);
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011751 loop:
11752 /* For each line, until end of word */
Denys Vlasenko958581a2010-09-12 15:04:27 +020011753 CHECKEND(); /* set c to PEOF if at end of here document */
11754 for (;;) { /* until end of line or end of word */
11755 CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */
11756 switch (SIT(c, syntax)) {
11757 case CNL: /* '\n' */
11758 if (syntax == BASESYNTAX)
11759 goto endword; /* exit outer loop */
11760 USTPUTC(c, out);
Denys Vlasenkoce332a22016-10-02 23:47:34 +020011761 nlprompt();
Denys Vlasenko958581a2010-09-12 15:04:27 +020011762 c = pgetc();
11763 goto loop; /* continue outer loop */
11764 case CWORD:
11765 USTPUTC(c, out);
11766 break;
11767 case CCTL:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011768#if BASH_DOLLAR_SQUOTE
Denys Vlasenko958581a2010-09-12 15:04:27 +020011769 if (c == '\\' && bash_dollar_squote) {
11770 c = decode_dollar_squote();
Denys Vlasenko13f20912016-09-25 20:54:25 +020011771 if (c == '\0') {
11772 /* skip $'\000', $'\x00' (like bash) */
11773 break;
11774 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020011775 if (c & 0x100) {
Denys Vlasenko13f20912016-09-25 20:54:25 +020011776 /* Unknown escape. Encode as '\z' */
Denys Vlasenko958581a2010-09-12 15:04:27 +020011777 c = (unsigned char)c;
Denys Vlasenko13f20912016-09-25 20:54:25 +020011778 if (eofmark == NULL || dblquote)
11779 USTPUTC(CTLESC, out);
11780 USTPUTC('\\', out);
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011781 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020011782 }
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011783#endif
Denys Vlasenko13f20912016-09-25 20:54:25 +020011784 if (eofmark == NULL || dblquote)
11785 USTPUTC(CTLESC, out);
Denys Vlasenko958581a2010-09-12 15:04:27 +020011786 USTPUTC(c, out);
11787 break;
11788 case CBACK: /* backslash */
11789 c = pgetc_without_PEOA();
11790 if (c == PEOF) {
11791 USTPUTC(CTLESC, out);
11792 USTPUTC('\\', out);
11793 pungetc();
11794 } else if (c == '\n') {
Denys Vlasenkoce332a22016-10-02 23:47:34 +020011795 nlprompt();
Denys Vlasenko958581a2010-09-12 15:04:27 +020011796 } else {
Denys Vlasenko5f0a75f2017-07-29 22:58:44 +020011797 if (pssyntax && c == '$') {
Eric Andersenc470f442003-07-28 09:56:35 +000011798 USTPUTC(CTLESC, out);
Eric Andersencb57d552001-06-28 07:25:16 +000011799 USTPUTC('\\', out);
Denys Vlasenko958581a2010-09-12 15:04:27 +020011800 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020011801 /* Backslash is retained if we are in "str" and next char isn't special */
11802 if (dblquote
11803 && c != '\\'
11804 && c != '`'
11805 && c != '$'
11806 && (c != '"' || eofmark != NULL)
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011807 ) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020011808 USTPUTC('\\', out);
Eric Andersencb57d552001-06-28 07:25:16 +000011809 }
Ron Yorston549deab2015-05-18 09:57:51 +020011810 USTPUTC(CTLESC, out);
Denys Vlasenko0ff78a02010-08-30 15:20:07 +020011811 USTPUTC(c, out);
Denys Vlasenko958581a2010-09-12 15:04:27 +020011812 quotef = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011813 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020011814 break;
11815 case CSQUOTE:
11816 syntax = SQSYNTAX;
11817 quotemark:
11818 if (eofmark == NULL) {
11819 USTPUTC(CTLQUOTEMARK, out);
11820 }
11821 break;
11822 case CDQUOTE:
11823 syntax = DQSYNTAX;
11824 dblquote = 1;
11825 goto quotemark;
11826 case CENDQUOTE:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011827 IF_BASH_DOLLAR_SQUOTE(bash_dollar_squote = 0;)
Ron Yorston7e4ed262015-05-18 09:54:43 +020011828 if (eofmark != NULL && varnest == 0) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020011829 USTPUTC(c, out);
11830 } else {
11831 if (dqvarnest == 0) {
11832 syntax = BASESYNTAX;
11833 dblquote = 0;
11834 }
11835 quotef = 1;
11836 goto quotemark;
11837 }
11838 break;
11839 case CVAR: /* '$' */
11840 PARSESUB(); /* parse substitution */
11841 break;
11842 case CENDVAR: /* '}' */
11843 if (varnest > 0) {
11844 varnest--;
11845 if (dqvarnest > 0) {
11846 dqvarnest--;
11847 }
11848 c = CTLENDVAR;
11849 }
11850 USTPUTC(c, out);
11851 break;
Denys Vlasenko0b883582016-12-23 16:49:07 +010011852#if ENABLE_FEATURE_SH_MATH
Denys Vlasenko958581a2010-09-12 15:04:27 +020011853 case CLP: /* '(' in arithmetic */
11854 parenlevel++;
11855 USTPUTC(c, out);
11856 break;
11857 case CRP: /* ')' in arithmetic */
11858 if (parenlevel > 0) {
11859 parenlevel--;
11860 } else {
Denys Vlasenko459293b2016-09-29 17:58:58 +020011861 if (pgetc_eatbnl() == ')') {
Ron Yorstonad88bde2015-05-18 09:56:16 +020011862 c = CTLENDARI;
Denys Vlasenko958581a2010-09-12 15:04:27 +020011863 if (--arinest == 0) {
11864 syntax = prevsyntax;
Denys Vlasenko958581a2010-09-12 15:04:27 +020011865 }
11866 } else {
11867 /*
11868 * unbalanced parens
11869 * (don't 2nd guess - no error)
11870 */
11871 pungetc();
11872 }
11873 }
11874 USTPUTC(c, out);
11875 break;
11876#endif
11877 case CBQUOTE: /* '`' */
11878 PARSEBACKQOLD();
11879 break;
11880 case CENDFILE:
11881 goto endword; /* exit outer loop */
11882 case CIGN:
11883 break;
11884 default:
11885 if (varnest == 0) {
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011886#if BASH_REDIR_OUTPUT
Denys Vlasenko958581a2010-09-12 15:04:27 +020011887 if (c == '&') {
Denys Vlasenko459293b2016-09-29 17:58:58 +020011888//Can't call pgetc_eatbnl() here, this requires three-deep pungetc()
Denys Vlasenko958581a2010-09-12 15:04:27 +020011889 if (pgetc() == '>')
11890 c = 0x100 + '>'; /* flag &> */
11891 pungetc();
11892 }
11893#endif
11894 goto endword; /* exit outer loop */
11895 }
11896 IF_ASH_ALIAS(if (c != PEOA))
11897 USTPUTC(c, out);
11898 }
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020011899 c = pgetc();
Denys Vlasenko958581a2010-09-12 15:04:27 +020011900 } /* for (;;) */
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011901 endword:
Denys Vlasenko958581a2010-09-12 15:04:27 +020011902
Denys Vlasenko0b883582016-12-23 16:49:07 +010011903#if ENABLE_FEATURE_SH_MATH
Eric Andersencb57d552001-06-28 07:25:16 +000011904 if (syntax == ARISYNTAX)
Denis Vlasenko559691a2008-10-05 18:39:31 +000011905 raise_error_syntax("missing '))'");
Eric Andersenc470f442003-07-28 09:56:35 +000011906#endif
Ron Yorston0e056f72015-07-01 16:45:40 +010011907 if (syntax != BASESYNTAX && eofmark == NULL)
Denis Vlasenko559691a2008-10-05 18:39:31 +000011908 raise_error_syntax("unterminated quoted string");
Eric Andersencb57d552001-06-28 07:25:16 +000011909 if (varnest != 0) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011910 startlinno = g_parsefile->linno;
Eric Andersenc470f442003-07-28 09:56:35 +000011911 /* { */
Denis Vlasenko559691a2008-10-05 18:39:31 +000011912 raise_error_syntax("missing '}'");
Eric Andersencb57d552001-06-28 07:25:16 +000011913 }
11914 USTPUTC('\0', out);
Eric Andersenc470f442003-07-28 09:56:35 +000011915 len = out - (char *)stackblock();
Eric Andersencb57d552001-06-28 07:25:16 +000011916 out = stackblock();
11917 if (eofmark == NULL) {
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011918 if ((c == '>' || c == '<' IF_BASH_REDIR_OUTPUT( || c == 0x100 + '>'))
Denis Vlasenko834dee72008-10-07 09:18:30 +000011919 && quotef == 0
11920 ) {
Denis Vlasenko559691a2008-10-05 18:39:31 +000011921 if (isdigit_str9(out)) {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000011922 PARSEREDIR(); /* passed as params: out, c */
11923 lasttoken = TREDIR;
11924 return lasttoken;
11925 }
11926 /* else: non-number X seen, interpret it
11927 * as "NNNX>file" = "NNNX >file" */
Eric Andersencb57d552001-06-28 07:25:16 +000011928 }
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011929 pungetc();
Eric Andersencb57d552001-06-28 07:25:16 +000011930 }
11931 quoteflag = quotef;
11932 backquotelist = bqlist;
11933 grabstackblock(len);
11934 wordtext = out;
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011935 lasttoken = TWORD;
11936 return lasttoken;
Eric Andersencb57d552001-06-28 07:25:16 +000011937/* end of readtoken routine */
11938
Eric Andersencb57d552001-06-28 07:25:16 +000011939/*
11940 * Check to see whether we are at the end of the here document. When this
11941 * is called, c is set to the first character of the next input line. If
11942 * we are at the end of the here document, this routine sets the c to PEOF.
11943 */
Eric Andersenc470f442003-07-28 09:56:35 +000011944checkend: {
Denys Vlasenko46999802017-07-29 21:12:29 +020011945 if (realeofmark(eofmark)) {
Denys Vlasenkoa7328982017-07-29 19:57:28 +020011946 int markloc;
11947 char *p;
11948
Denis Vlasenko131ae172007-02-18 13:00:19 +000011949#if ENABLE_ASH_ALIAS
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010011950 if (c == PEOA)
11951 c = pgetc_without_PEOA();
Eric Andersenc470f442003-07-28 09:56:35 +000011952#endif
11953 if (striptabs) {
11954 while (c == '\t') {
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010011955 c = pgetc_without_PEOA();
Eric Andersencb57d552001-06-28 07:25:16 +000011956 }
Eric Andersenc470f442003-07-28 09:56:35 +000011957 }
Eric Andersencb57d552001-06-28 07:25:16 +000011958
Denys Vlasenkoa7328982017-07-29 19:57:28 +020011959 markloc = out - (char *)stackblock();
11960 for (p = eofmark; STPUTC(c, out), *p; p++) {
11961 if (c != *p)
11962 goto more_heredoc;
11963
11964 c = pgetc_without_PEOA();
11965 }
11966
11967 if (c == '\n' || c == PEOF) {
11968 c = PEOF;
11969 g_parsefile->linno++;
11970 needprompt = doprompt;
11971 } else {
11972 int len_here;
11973
11974 more_heredoc:
11975 p = (char *)stackblock() + markloc + 1;
11976 len_here = out - p;
11977
11978 if (len_here) {
11979 len_here -= (c >= PEOF);
11980 c = p[-1];
11981
11982 if (len_here) {
11983 char *str;
11984
11985 str = alloca(len_here + 1);
11986 *(char *)mempcpy(str, p, len_here) = '\0';
11987
11988 pushstring(str, NULL);
Eric Andersencb57d552001-06-28 07:25:16 +000011989 }
11990 }
11991 }
Denys Vlasenkoa7328982017-07-29 19:57:28 +020011992
11993 STADJUST((char *)stackblock() + markloc - out, out);
Eric Andersencb57d552001-06-28 07:25:16 +000011994 }
Eric Andersenc470f442003-07-28 09:56:35 +000011995 goto checkend_return;
11996}
Eric Andersencb57d552001-06-28 07:25:16 +000011997
Eric Andersencb57d552001-06-28 07:25:16 +000011998/*
11999 * Parse a redirection operator. The variable "out" points to a string
12000 * specifying the fd to be redirected. The variable "c" contains the
12001 * first character of the redirection operator.
12002 */
Eric Andersenc470f442003-07-28 09:56:35 +000012003parseredir: {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000012004 /* out is already checked to be a valid number or "" */
12005 int fd = (*out == '\0' ? -1 : atoi(out));
Eric Andersenc470f442003-07-28 09:56:35 +000012006 union node *np;
Eric Andersencb57d552001-06-28 07:25:16 +000012007
Denis Vlasenko597906c2008-02-20 16:38:54 +000012008 np = stzalloc(sizeof(struct nfile));
Eric Andersenc470f442003-07-28 09:56:35 +000012009 if (c == '>') {
12010 np->nfile.fd = 1;
12011 c = pgetc();
12012 if (c == '>')
12013 np->type = NAPPEND;
12014 else if (c == '|')
12015 np->type = NCLOBBER;
12016 else if (c == '&')
12017 np->type = NTOFD;
Denis Vlasenko559691a2008-10-05 18:39:31 +000012018 /* it also can be NTO2 (>&file), but we can't figure it out yet */
Eric Andersenc470f442003-07-28 09:56:35 +000012019 else {
12020 np->type = NTO;
12021 pungetc();
Eric Andersencb57d552001-06-28 07:25:16 +000012022 }
Denis Vlasenko834dee72008-10-07 09:18:30 +000012023 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010012024#if BASH_REDIR_OUTPUT
Denis Vlasenko834dee72008-10-07 09:18:30 +000012025 else if (c == 0x100 + '>') { /* this flags &> redirection */
12026 np->nfile.fd = 1;
12027 pgetc(); /* this is '>', no need to check */
12028 np->type = NTO2;
12029 }
12030#endif
12031 else { /* c == '<' */
Denis Vlasenko597906c2008-02-20 16:38:54 +000012032 /*np->nfile.fd = 0; - stzalloc did it */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000012033 c = pgetc();
12034 switch (c) {
Eric Andersenc470f442003-07-28 09:56:35 +000012035 case '<':
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000012036 if (sizeof(struct nfile) != sizeof(struct nhere)) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000012037 np = stzalloc(sizeof(struct nhere));
12038 /*np->nfile.fd = 0; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000012039 }
12040 np->type = NHERE;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000012041 heredoc = stzalloc(sizeof(struct heredoc));
Eric Andersenc470f442003-07-28 09:56:35 +000012042 heredoc->here = np;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000012043 c = pgetc();
12044 if (c == '-') {
Eric Andersenc470f442003-07-28 09:56:35 +000012045 heredoc->striptabs = 1;
12046 } else {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000012047 /*heredoc->striptabs = 0; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000012048 pungetc();
12049 }
12050 break;
12051
12052 case '&':
12053 np->type = NFROMFD;
12054 break;
12055
12056 case '>':
12057 np->type = NFROMTO;
12058 break;
12059
12060 default:
12061 np->type = NFROM;
12062 pungetc();
12063 break;
12064 }
Eric Andersencb57d552001-06-28 07:25:16 +000012065 }
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000012066 if (fd >= 0)
12067 np->nfile.fd = fd;
Eric Andersenc470f442003-07-28 09:56:35 +000012068 redirnode = np;
12069 goto parseredir_return;
12070}
Eric Andersencb57d552001-06-28 07:25:16 +000012071
Eric Andersencb57d552001-06-28 07:25:16 +000012072/*
12073 * Parse a substitution. At this point, we have read the dollar sign
12074 * and nothing else.
12075 */
Denis Vlasenkocc571512007-02-23 21:10:35 +000012076
12077/* is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise
12078 * (assuming ascii char codes, as the original implementation did) */
12079#define is_special(c) \
Denis Vlasenkoef527f52008-06-23 01:52:30 +000012080 (((unsigned)(c) - 33 < 32) \
12081 && ((0xc1ff920dU >> ((unsigned)(c) - 33)) & 1))
Eric Andersenc470f442003-07-28 09:56:35 +000012082parsesub: {
Denys Vlasenkocd716832009-11-28 22:14:02 +010012083 unsigned char subtype;
Eric Andersenc470f442003-07-28 09:56:35 +000012084 int typeloc;
Eric Andersencb57d552001-06-28 07:25:16 +000012085
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012086 c = pgetc_eatbnl();
Denys Vlasenkoa7328982017-07-29 19:57:28 +020012087 if ((checkkwd & CHKEOFMARK)
12088 || c > 255 /* PEOA or PEOF */
Denis Vlasenkoef527f52008-06-23 01:52:30 +000012089 || (c != '(' && c != '{' && !is_name(c) && !is_special(c))
Eric Andersenc470f442003-07-28 09:56:35 +000012090 ) {
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010012091#if BASH_DOLLAR_SQUOTE
Ron Yorston84ba50c2016-04-03 22:43:14 +010012092 if (syntax != DQSYNTAX && c == '\'')
Denis Vlasenkoef527f52008-06-23 01:52:30 +000012093 bash_dollar_squote = 1;
12094 else
12095#endif
12096 USTPUTC('$', out);
Eric Andersenc470f442003-07-28 09:56:35 +000012097 pungetc();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012098 } else if (c == '(') {
12099 /* $(command) or $((arith)) */
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012100 if (pgetc_eatbnl() == '(') {
Denys Vlasenko0b883582016-12-23 16:49:07 +010012101#if ENABLE_FEATURE_SH_MATH
Eric Andersenc470f442003-07-28 09:56:35 +000012102 PARSEARITH();
12103#else
Denys Vlasenko4f8079d2017-07-17 17:11:48 +020012104 raise_error_syntax("support for $((arith)) is disabled");
Eric Andersenc470f442003-07-28 09:56:35 +000012105#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012106 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000012107 pungetc();
12108 PARSEBACKQNEW();
12109 }
12110 } else {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012111 /* $VAR, $<specialchar>, ${...}, or PEOA/PEOF */
Eric Andersenc470f442003-07-28 09:56:35 +000012112 USTPUTC(CTLVAR, out);
12113 typeloc = out - (char *)stackblock();
Denys Vlasenko3df14102016-10-26 16:41:13 +020012114 STADJUST(1, out);
Eric Andersenc470f442003-07-28 09:56:35 +000012115 subtype = VSNORMAL;
12116 if (c == '{') {
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012117 c = pgetc_eatbnl();
Denys Vlasenkof15aa572016-10-26 15:56:53 +020012118 subtype = 0;
Eric Andersenc470f442003-07-28 09:56:35 +000012119 }
Denys Vlasenkof15aa572016-10-26 15:56:53 +020012120 varname:
Denys Vlasenko3df14102016-10-26 16:41:13 +020012121 if (is_name(c)) {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012122 /* $[{[#]]NAME[}] */
Eric Andersenc470f442003-07-28 09:56:35 +000012123 do {
12124 STPUTC(c, out);
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012125 c = pgetc_eatbnl();
Denys Vlasenko3df14102016-10-26 16:41:13 +020012126 } while (is_in_name(c));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012127 } else if (isdigit(c)) {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012128 /* $[{[#]]NUM[}] */
Eric Andersenc470f442003-07-28 09:56:35 +000012129 do {
12130 STPUTC(c, out);
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012131 c = pgetc_eatbnl();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012132 } while (isdigit(c));
Denys Vlasenko452cc1d2017-08-14 14:23:45 +020012133 } else {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012134 /* $[{[#]]<specialchar>[}] */
Denys Vlasenkof15aa572016-10-26 15:56:53 +020012135 int cc = c;
12136
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012137 c = pgetc_eatbnl();
Denys Vlasenkof15aa572016-10-26 15:56:53 +020012138 if (!subtype && cc == '#') {
12139 subtype = VSLENGTH;
12140 if (c == '_' || isalnum(c))
12141 goto varname;
12142 cc = c;
12143 c = pgetc_eatbnl();
12144 if (cc == '}' || c != '}') {
12145 pungetc();
12146 subtype = 0;
12147 c = cc;
12148 cc = '#';
12149 }
12150 }
Denys Vlasenko452cc1d2017-08-14 14:23:45 +020012151
12152 if (!is_special(cc)) {
12153 if (subtype == VSLENGTH)
12154 subtype = 0;
12155 goto badsub;
12156 }
12157
Denys Vlasenkof15aa572016-10-26 15:56:53 +020012158 USTPUTC(cc, out);
Denis Vlasenko559691a2008-10-05 18:39:31 +000012159 }
Denys Vlasenko452cc1d2017-08-14 14:23:45 +020012160
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012161 if (c != '}' && subtype == VSLENGTH) {
12162 /* ${#VAR didn't end with } */
Cristian Ionescu-Idbohrn301f5ec2009-10-05 02:07:23 +020012163 goto badsub;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012164 }
Eric Andersencb57d552001-06-28 07:25:16 +000012165
Eric Andersenc470f442003-07-28 09:56:35 +000012166 if (subtype == 0) {
Denys Vlasenkof8ddbe12016-07-25 03:56:00 +020012167 static const char types[] ALIGN1 = "}-+?=";
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012168 /* ${VAR...} but not $VAR or ${#VAR} */
12169 /* c == first char after VAR */
Eric Andersenc470f442003-07-28 09:56:35 +000012170 switch (c) {
12171 case ':':
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012172 c = pgetc_eatbnl();
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010012173#if BASH_SUBSTR
Denys Vlasenkof8ddbe12016-07-25 03:56:00 +020012174 /* This check is only needed to not misinterpret
12175 * ${VAR:-WORD}, ${VAR:+WORD}, ${VAR:=WORD}, ${VAR:?WORD}
12176 * constructs.
12177 */
12178 if (!strchr(types, c)) {
Denis Vlasenko92e13c22008-03-25 01:17:40 +000012179 subtype = VSSUBSTR;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012180 pungetc();
Denys Vlasenko88e15702016-10-26 01:55:56 +020012181 break; /* "goto badsub" is bigger (!) */
Denis Vlasenko92e13c22008-03-25 01:17:40 +000012182 }
12183#endif
Denys Vlasenko3df14102016-10-26 16:41:13 +020012184 subtype = VSNUL;
Eric Andersenc470f442003-07-28 09:56:35 +000012185 /*FALLTHROUGH*/
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012186 default: {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012187 const char *p = strchr(types, c);
Eric Andersenc470f442003-07-28 09:56:35 +000012188 if (p == NULL)
Denys Vlasenko88e15702016-10-26 01:55:56 +020012189 break;
Denys Vlasenko3df14102016-10-26 16:41:13 +020012190 subtype |= p - types + VSNORMAL;
Eric Andersenc470f442003-07-28 09:56:35 +000012191 break;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012192 }
Eric Andersenc470f442003-07-28 09:56:35 +000012193 case '%':
Denis Vlasenko92e13c22008-03-25 01:17:40 +000012194 case '#': {
12195 int cc = c;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012196 subtype = (c == '#' ? VSTRIMLEFT : VSTRIMRIGHT);
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012197 c = pgetc_eatbnl();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012198 if (c != cc)
Denys Vlasenko88e15702016-10-26 01:55:56 +020012199 goto badsub;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012200 subtype++;
Denis Vlasenko92e13c22008-03-25 01:17:40 +000012201 break;
12202 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010012203#if BASH_PATTERN_SUBST
Denis Vlasenko92e13c22008-03-25 01:17:40 +000012204 case '/':
Denys Vlasenko6040fe82010-09-12 15:03:16 +020012205 /* ${v/[/]pattern/repl} */
12206//TODO: encode pattern and repl separately.
12207// Currently ${v/$var_with_slash/repl} is horribly broken
Denis Vlasenko92e13c22008-03-25 01:17:40 +000012208 subtype = VSREPLACE;
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012209 c = pgetc_eatbnl();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012210 if (c != '/')
Denys Vlasenko88e15702016-10-26 01:55:56 +020012211 goto badsub;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012212 subtype++; /* VSREPLACEALL */
Denis Vlasenko92e13c22008-03-25 01:17:40 +000012213 break;
12214#endif
Eric Andersencb57d552001-06-28 07:25:16 +000012215 }
Eric Andersenc470f442003-07-28 09:56:35 +000012216 } else {
Denys Vlasenko88e15702016-10-26 01:55:56 +020012217 badsub:
Eric Andersenc470f442003-07-28 09:56:35 +000012218 pungetc();
12219 }
Denys Vlasenko3df14102016-10-26 16:41:13 +020012220 ((unsigned char *)stackblock())[typeloc] = subtype;
Eric Andersenc470f442003-07-28 09:56:35 +000012221 if (subtype != VSNORMAL) {
12222 varnest++;
Denys Vlasenko3df14102016-10-26 16:41:13 +020012223 if (dblquote)
Eric Andersenc470f442003-07-28 09:56:35 +000012224 dqvarnest++;
Eric Andersencb57d552001-06-28 07:25:16 +000012225 }
Denys Vlasenko88e15702016-10-26 01:55:56 +020012226 STPUTC('=', out);
Eric Andersencb57d552001-06-28 07:25:16 +000012227 }
Eric Andersenc470f442003-07-28 09:56:35 +000012228 goto parsesub_return;
12229}
Eric Andersencb57d552001-06-28 07:25:16 +000012230
Eric Andersencb57d552001-06-28 07:25:16 +000012231/*
12232 * Called to parse command substitutions. Newstyle is set if the command
12233 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
12234 * list of commands (passed by reference), and savelen is the number of
12235 * characters on the top of the stack which must be preserved.
12236 */
Eric Andersenc470f442003-07-28 09:56:35 +000012237parsebackq: {
12238 struct nodelist **nlpp;
Eric Andersenc470f442003-07-28 09:56:35 +000012239 union node *n;
Ron Yorston072fc602015-07-01 16:46:18 +010012240 char *str;
Eric Andersenc470f442003-07-28 09:56:35 +000012241 size_t savelen;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000012242 smallint saveprompt = 0;
12243
Eric Andersenc470f442003-07-28 09:56:35 +000012244 str = NULL;
12245 savelen = out - (char *)stackblock();
12246 if (savelen > 0) {
Denys Vlasenko7bc3d392016-09-17 20:53:47 +020012247 /*
12248 * FIXME: this can allocate very large block on stack and SEGV.
12249 * Example:
12250 * echo "..<100kbytes>..`true` $(true) `true` ..."
Denys Vlasenko73737592016-09-17 20:58:22 +020012251 * allocates 100kb for every command subst. With about
Denys Vlasenko7bc3d392016-09-17 20:53:47 +020012252 * a hundred command substitutions stack overflows.
12253 * With larger prepended string, SEGV happens sooner.
12254 */
Ron Yorston072fc602015-07-01 16:46:18 +010012255 str = alloca(savelen);
Eric Andersenc470f442003-07-28 09:56:35 +000012256 memcpy(str, stackblock(), savelen);
12257 }
Denys Vlasenko7bc3d392016-09-17 20:53:47 +020012258
Eric Andersenc470f442003-07-28 09:56:35 +000012259 if (oldstyle) {
12260 /* We must read until the closing backquote, giving special
Denys Vlasenko60cb48c2013-01-14 15:57:44 +010012261 * treatment to some slashes, and then push the string and
12262 * reread it as input, interpreting it normally.
12263 */
Eric Andersenc470f442003-07-28 09:56:35 +000012264 char *pout;
Eric Andersenc470f442003-07-28 09:56:35 +000012265 size_t psavelen;
12266 char *pstr;
12267
Eric Andersenc470f442003-07-28 09:56:35 +000012268 STARTSTACKSTR(pout);
12269 for (;;) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020012270 int pc;
12271
12272 setprompt_if(needprompt, 2);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000012273 pc = pgetc();
12274 switch (pc) {
Eric Andersenc470f442003-07-28 09:56:35 +000012275 case '`':
12276 goto done;
12277
12278 case '\\':
Denis Vlasenko5cedb752007-02-18 19:56:41 +000012279 pc = pgetc();
12280 if (pc == '\n') {
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012281 nlprompt();
Eric Andersenc470f442003-07-28 09:56:35 +000012282 /*
12283 * If eating a newline, avoid putting
12284 * the newline into the new character
12285 * stream (via the STPUTC after the
12286 * switch).
12287 */
12288 continue;
12289 }
12290 if (pc != '\\' && pc != '`' && pc != '$'
Denys Vlasenko76bc2d62009-11-29 01:37:46 +010012291 && (!dblquote || pc != '"')
12292 ) {
Eric Andersenc470f442003-07-28 09:56:35 +000012293 STPUTC('\\', pout);
Denys Vlasenko76bc2d62009-11-29 01:37:46 +010012294 }
Denys Vlasenkocd716832009-11-28 22:14:02 +010012295 if (pc <= 255 /* not PEOA or PEOF */) {
Eric Andersenc470f442003-07-28 09:56:35 +000012296 break;
12297 }
12298 /* fall through */
12299
12300 case PEOF:
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010012301 IF_ASH_ALIAS(case PEOA:)
Denis Vlasenko41eb3002008-11-28 03:42:31 +000012302 startlinno = g_parsefile->linno;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000012303 raise_error_syntax("EOF in backquote substitution");
Eric Andersenc470f442003-07-28 09:56:35 +000012304
12305 case '\n':
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012306 nlnoprompt();
Eric Andersenc470f442003-07-28 09:56:35 +000012307 break;
12308
12309 default:
12310 break;
12311 }
12312 STPUTC(pc, pout);
12313 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +000012314 done:
Eric Andersenc470f442003-07-28 09:56:35 +000012315 STPUTC('\0', pout);
12316 psavelen = pout - (char *)stackblock();
12317 if (psavelen > 0) {
12318 pstr = grabstackstr(pout);
12319 setinputstring(pstr);
12320 }
12321 }
12322 nlpp = &bqlist;
12323 while (*nlpp)
12324 nlpp = &(*nlpp)->next;
Denis Vlasenko597906c2008-02-20 16:38:54 +000012325 *nlpp = stzalloc(sizeof(**nlpp));
12326 /* (*nlpp)->next = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000012327
12328 if (oldstyle) {
12329 saveprompt = doprompt;
12330 doprompt = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000012331 }
12332
Eric Andersenc470f442003-07-28 09:56:35 +000012333 n = list(2);
12334
12335 if (oldstyle)
12336 doprompt = saveprompt;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012337 else if (readtoken() != TRP)
12338 raise_error_unexpected_syntax(TRP);
Eric Andersenc470f442003-07-28 09:56:35 +000012339
12340 (*nlpp)->n = n;
12341 if (oldstyle) {
12342 /*
12343 * Start reading from old file again, ignoring any pushed back
12344 * tokens left from the backquote parsing
12345 */
12346 popfile();
12347 tokpushback = 0;
12348 }
12349 while (stackblocksize() <= savelen)
12350 growstackblock();
12351 STARTSTACKSTR(out);
12352 if (str) {
12353 memcpy(out, str, savelen);
12354 STADJUST(savelen, out);
Eric Andersenc470f442003-07-28 09:56:35 +000012355 }
Ron Yorston549deab2015-05-18 09:57:51 +020012356 USTPUTC(CTLBACKQ, out);
Eric Andersenc470f442003-07-28 09:56:35 +000012357 if (oldstyle)
12358 goto parsebackq_oldreturn;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000012359 goto parsebackq_newreturn;
Eric Andersenc470f442003-07-28 09:56:35 +000012360}
12361
Denys Vlasenko0b883582016-12-23 16:49:07 +010012362#if ENABLE_FEATURE_SH_MATH
Eric Andersencb57d552001-06-28 07:25:16 +000012363/*
12364 * Parse an arithmetic expansion (indicate start of one and set state)
12365 */
Eric Andersenc470f442003-07-28 09:56:35 +000012366parsearith: {
Eric Andersenc470f442003-07-28 09:56:35 +000012367 if (++arinest == 1) {
12368 prevsyntax = syntax;
12369 syntax = ARISYNTAX;
Eric Andersencb57d552001-06-28 07:25:16 +000012370 }
Ron Yorstonad88bde2015-05-18 09:56:16 +020012371 USTPUTC(CTLARI, out);
Eric Andersenc470f442003-07-28 09:56:35 +000012372 goto parsearith_return;
12373}
12374#endif
Eric Andersenc470f442003-07-28 09:56:35 +000012375} /* end of readtoken */
12376
Eric Andersencb57d552001-06-28 07:25:16 +000012377/*
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012378 * Read the next input token.
12379 * If the token is a word, we set backquotelist to the list of cmds in
12380 * backquotes. We set quoteflag to true if any part of the word was
12381 * quoted.
12382 * If the token is TREDIR, then we set redirnode to a structure containing
12383 * the redirection.
12384 * In all cases, the variable startlinno is set to the number of the line
12385 * on which the token starts.
12386 *
12387 * [Change comment: here documents and internal procedures]
12388 * [Readtoken shouldn't have any arguments. Perhaps we should make the
12389 * word parsing code into a separate routine. In this case, readtoken
12390 * doesn't need to have any internal procedures, but parseword does.
12391 * We could also make parseoperator in essence the main routine, and
12392 * have parseword (readtoken1?) handle both words and redirection.]
Eric Andersencb57d552001-06-28 07:25:16 +000012393 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012394#define NEW_xxreadtoken
12395#ifdef NEW_xxreadtoken
12396/* singles must be first! */
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000012397static const char xxreadtoken_chars[7] ALIGN1 = {
Denis Vlasenko834dee72008-10-07 09:18:30 +000012398 '\n', '(', ')', /* singles */
12399 '&', '|', ';', /* doubles */
12400 0
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000012401};
Eric Andersencb57d552001-06-28 07:25:16 +000012402
Denis Vlasenko834dee72008-10-07 09:18:30 +000012403#define xxreadtoken_singles 3
12404#define xxreadtoken_doubles 3
12405
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000012406static const char xxreadtoken_tokens[] ALIGN1 = {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012407 TNL, TLP, TRP, /* only single occurrence allowed */
12408 TBACKGND, TPIPE, TSEMI, /* if single occurrence */
12409 TEOF, /* corresponds to trailing nul */
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000012410 TAND, TOR, TENDCASE /* if double occurrence */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012411};
12412
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012413static int
12414xxreadtoken(void)
12415{
12416 int c;
12417
12418 if (tokpushback) {
12419 tokpushback = 0;
12420 return lasttoken;
Eric Andersencb57d552001-06-28 07:25:16 +000012421 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020012422 setprompt_if(needprompt, 2);
Denis Vlasenko41eb3002008-11-28 03:42:31 +000012423 startlinno = g_parsefile->linno;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012424 for (;;) { /* until token or start of word found */
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020012425 c = pgetc();
Denis Vlasenko5e34ff22009-04-21 11:09:40 +000012426 if (c == ' ' || c == '\t' IF_ASH_ALIAS( || c == PEOA))
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012427 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012428
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012429 if (c == '#') {
12430 while ((c = pgetc()) != '\n' && c != PEOF)
12431 continue;
12432 pungetc();
12433 } else if (c == '\\') {
12434 if (pgetc() != '\n') {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012435 pungetc();
Denis Vlasenko834dee72008-10-07 09:18:30 +000012436 break; /* return readtoken1(...) */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012437 }
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012438 nlprompt();
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012439 } else {
12440 const char *p;
12441
12442 p = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
12443 if (c != PEOF) {
12444 if (c == '\n') {
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012445 nlnoprompt();
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012446 }
12447
12448 p = strchr(xxreadtoken_chars, c);
Denis Vlasenko834dee72008-10-07 09:18:30 +000012449 if (p == NULL)
12450 break; /* return readtoken1(...) */
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012451
Denis Vlasenko834dee72008-10-07 09:18:30 +000012452 if ((int)(p - xxreadtoken_chars) >= xxreadtoken_singles) {
12453 int cc = pgetc();
12454 if (cc == c) { /* double occurrence? */
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012455 p += xxreadtoken_doubles + 1;
12456 } else {
12457 pungetc();
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010012458#if BASH_REDIR_OUTPUT
Denis Vlasenko834dee72008-10-07 09:18:30 +000012459 if (c == '&' && cc == '>') /* &> */
12460 break; /* return readtoken1(...) */
12461#endif
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012462 }
12463 }
12464 }
12465 lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
12466 return lasttoken;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012467 }
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012468 } /* for (;;) */
Denis Vlasenko834dee72008-10-07 09:18:30 +000012469
12470 return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012471}
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012472#else /* old xxreadtoken */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012473#define RETURN(token) return lasttoken = token
12474static int
12475xxreadtoken(void)
12476{
12477 int c;
12478
12479 if (tokpushback) {
12480 tokpushback = 0;
12481 return lasttoken;
12482 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020012483 setprompt_if(needprompt, 2);
Denis Vlasenko41eb3002008-11-28 03:42:31 +000012484 startlinno = g_parsefile->linno;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012485 for (;;) { /* until token or start of word found */
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020012486 c = pgetc();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012487 switch (c) {
12488 case ' ': case '\t':
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010012489 IF_ASH_ALIAS(case PEOA:)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012490 continue;
12491 case '#':
Denis Vlasenkof7d56652008-03-25 05:51:41 +000012492 while ((c = pgetc()) != '\n' && c != PEOF)
12493 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012494 pungetc();
12495 continue;
12496 case '\\':
12497 if (pgetc() == '\n') {
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012498 nlprompt();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012499 continue;
12500 }
12501 pungetc();
12502 goto breakloop;
12503 case '\n':
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012504 nlnoprompt();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012505 RETURN(TNL);
12506 case PEOF:
12507 RETURN(TEOF);
12508 case '&':
12509 if (pgetc() == '&')
12510 RETURN(TAND);
12511 pungetc();
12512 RETURN(TBACKGND);
12513 case '|':
12514 if (pgetc() == '|')
12515 RETURN(TOR);
12516 pungetc();
12517 RETURN(TPIPE);
12518 case ';':
12519 if (pgetc() == ';')
12520 RETURN(TENDCASE);
12521 pungetc();
12522 RETURN(TSEMI);
12523 case '(':
12524 RETURN(TLP);
12525 case ')':
12526 RETURN(TRP);
12527 default:
12528 goto breakloop;
12529 }
12530 }
12531 breakloop:
12532 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
12533#undef RETURN
12534}
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012535#endif /* old xxreadtoken */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012536
12537static int
12538readtoken(void)
12539{
12540 int t;
Ron Yorston713f07d2015-10-29 16:44:56 +000012541 int kwd = checkkwd;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012542#if DEBUG
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000012543 smallint alreadyseen = tokpushback;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012544#endif
12545
12546#if ENABLE_ASH_ALIAS
12547 top:
12548#endif
12549
12550 t = xxreadtoken();
12551
12552 /*
12553 * eat newlines
12554 */
Ron Yorston713f07d2015-10-29 16:44:56 +000012555 if (kwd & CHKNL) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012556 while (t == TNL) {
12557 parseheredoc();
12558 t = xxreadtoken();
12559 }
12560 }
12561
12562 if (t != TWORD || quoteflag) {
12563 goto out;
12564 }
12565
12566 /*
12567 * check for keywords
12568 */
Ron Yorston713f07d2015-10-29 16:44:56 +000012569 if (kwd & CHKKWD) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012570 const char *const *pp;
12571
12572 pp = findkwd(wordtext);
12573 if (pp) {
12574 lasttoken = t = pp - tokname_array;
Denys Vlasenko888527c2016-10-02 16:54:17 +020012575 TRACE(("keyword '%s' recognized\n", tokname_array[t]));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012576 goto out;
12577 }
12578 }
12579
12580 if (checkkwd & CHKALIAS) {
12581#if ENABLE_ASH_ALIAS
12582 struct alias *ap;
12583 ap = lookupalias(wordtext, 1);
12584 if (ap != NULL) {
12585 if (*ap->val) {
12586 pushstring(ap->val, ap);
12587 }
12588 goto top;
12589 }
12590#endif
12591 }
12592 out:
12593 checkkwd = 0;
12594#if DEBUG
12595 if (!alreadyseen)
Denys Vlasenko888527c2016-10-02 16:54:17 +020012596 TRACE(("token '%s' %s\n", tokname_array[t], t == TWORD ? wordtext : ""));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012597 else
Denys Vlasenko888527c2016-10-02 16:54:17 +020012598 TRACE(("reread token '%s' %s\n", tokname_array[t], t == TWORD ? wordtext : ""));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012599#endif
12600 return t;
Eric Andersencb57d552001-06-28 07:25:16 +000012601}
12602
Ron Yorstonc0e00762015-10-29 11:30:55 +000012603static int
Ron Yorston6bd2fab2015-10-29 11:30:22 +000012604peektoken(void)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012605{
12606 int t;
12607
12608 t = readtoken();
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000012609 tokpushback = 1;
Ron Yorstonc0e00762015-10-29 11:30:55 +000012610 return t;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012611}
Eric Andersencb57d552001-06-28 07:25:16 +000012612
12613/*
Denys Vlasenko86e83ec2009-07-23 22:07:07 +020012614 * Read and parse a command. Returns NODE_EOF on end of file.
12615 * (NULL is a valid parse tree indicating a blank line.)
Eric Andersencb57d552001-06-28 07:25:16 +000012616 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012617static union node *
12618parsecmd(int interact)
Eric Andersen90898442003-08-06 11:20:52 +000012619{
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012620 tokpushback = 0;
Ron Yorstonc0e00762015-10-29 11:30:55 +000012621 checkkwd = 0;
12622 heredoclist = 0;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012623 doprompt = interact;
Denys Vlasenko958581a2010-09-12 15:04:27 +020012624 setprompt_if(doprompt, doprompt);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012625 needprompt = 0;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012626 return list(1);
12627}
12628
12629/*
12630 * Input any here documents.
12631 */
12632static void
12633parseheredoc(void)
12634{
12635 struct heredoc *here;
12636 union node *n;
12637
12638 here = heredoclist;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000012639 heredoclist = NULL;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012640
12641 while (here) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020012642 setprompt_if(needprompt, 2);
12643 readtoken1(pgetc(), here->here->type == NHERE ? SQSYNTAX : DQSYNTAX,
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012644 here->eofmark, here->striptabs);
Denis Vlasenko597906c2008-02-20 16:38:54 +000012645 n = stzalloc(sizeof(struct narg));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012646 n->narg.type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000012647 /*n->narg.next = NULL; - stzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012648 n->narg.text = wordtext;
12649 n->narg.backquote = backquotelist;
12650 here->here->nhere.doc = n;
12651 here = here->next;
Eric Andersencb57d552001-06-28 07:25:16 +000012652 }
Eric Andersencb57d552001-06-28 07:25:16 +000012653}
12654
12655
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012656static const char *
Denys Vlasenko46999802017-07-29 21:12:29 +020012657expandstr(const char *ps, int syntax_type)
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012658{
12659 union node n;
Denys Vlasenko2a6d29a2016-10-25 21:17:52 +020012660 int saveprompt;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012661
Denys Vlasenko46999802017-07-29 21:12:29 +020012662 /* XXX Fix (char *) cast. */
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012663 setinputstring((char *)ps);
Denys Vlasenko2a6d29a2016-10-25 21:17:52 +020012664
12665 saveprompt = doprompt;
12666 doprompt = 0;
Denys Vlasenkoa2e32b32017-10-12 19:20:13 +020012667
12668 /* readtoken1() might die horribly.
Denys Vlasenko3c183a82017-10-12 19:35:42 +020012669 * Try a prompt with syntactically wrong command:
Denys Vlasenkoa2e32b32017-10-12 19:20:13 +020012670 * PS1='$(date "+%H:%M:%S) > '
12671 */
12672 {
12673 volatile int saveint;
12674 struct jmploc *volatile savehandler = exception_handler;
12675 struct jmploc jmploc;
12676 SAVE_INT(saveint);
12677 if (setjmp(jmploc.loc) == 0) {
12678 exception_handler = &jmploc;
12679 readtoken1(pgetc(), syntax_type, FAKEEOFMARK, 0);
12680 }
12681 exception_handler = savehandler;
12682 RESTORE_INT(saveint);
12683 }
12684
Denys Vlasenko2a6d29a2016-10-25 21:17:52 +020012685 doprompt = saveprompt;
12686
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012687 popfile();
12688
12689 n.narg.type = NARG;
12690 n.narg.next = NULL;
12691 n.narg.text = wordtext;
12692 n.narg.backquote = backquotelist;
12693
Ron Yorston549deab2015-05-18 09:57:51 +020012694 expandarg(&n, NULL, EXP_QUOTED);
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012695 return stackblock();
12696}
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012697
Denys Vlasenko1e3e2cc2017-07-25 20:31:14 +020012698static inline int
12699parser_eof(void)
12700{
12701 return tokpushback && lasttoken == TEOF;
12702}
12703
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012704/*
12705 * Execute a command or commands contained in a string.
12706 */
12707static int
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020012708evalstring(char *s, int flags)
Eric Andersenc470f442003-07-28 09:56:35 +000012709{
Denys Vlasenko493b9ca2016-10-30 18:27:14 +010012710 struct jmploc *volatile savehandler;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012711 struct jmploc jmploc;
12712 int ex;
12713
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012714 union node *n;
12715 struct stackmark smark;
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012716 int status;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012717
Denys Vlasenko8e2bc472016-09-28 23:02:57 +020012718 s = sstrdup(s);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012719 setinputstring(s);
12720 setstackmark(&smark);
12721
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012722 status = 0;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012723 /* On exception inside execution loop, we must popfile().
12724 * Try interactively:
12725 * readonly a=a
12726 * command eval "a=b" # throws "is read only" error
12727 * "command BLTIN" is not supposed to abort (even in non-interactive use).
12728 * But if we skip popfile(), we hit EOF in eval's string, and exit.
12729 */
12730 savehandler = exception_handler;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012731 ex = setjmp(jmploc.loc);
12732 if (ex)
12733 goto out;
Denys Vlasenko493b9ca2016-10-30 18:27:14 +010012734 exception_handler = &jmploc;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012735
Denys Vlasenko86e83ec2009-07-23 22:07:07 +020012736 while ((n = parsecmd(0)) != NODE_EOF) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020012737 int i;
12738
Denys Vlasenko1e3e2cc2017-07-25 20:31:14 +020012739 i = evaltree(n, flags & ~(parser_eof() ? 0 : EV_EXIT));
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012740 if (n)
12741 status = i;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012742 popstackmark(&smark);
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012743 if (evalskip)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012744 break;
12745 }
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012746 out:
Denys Vlasenko8e2bc472016-09-28 23:02:57 +020012747 popstackmark(&smark);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012748 popfile();
Denys Vlasenko8e2bc472016-09-28 23:02:57 +020012749 stunalloc(s);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012750
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012751 exception_handler = savehandler;
12752 if (ex)
Denys Vlasenko14c85eb2017-10-12 19:40:47 +020012753 longjmp(exception_handler->loc, ex);
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012754
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012755 return status;
Eric Andersenc470f442003-07-28 09:56:35 +000012756}
12757
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012758/*
12759 * The eval command.
12760 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012761static int FAST_FUNC
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020012762evalcmd(int argc UNUSED_PARAM, char **argv, int flags)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012763{
12764 char *p;
12765 char *concat;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012766
Denis Vlasenko68404f12008-03-17 09:00:54 +000012767 if (argv[1]) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012768 p = argv[1];
Denis Vlasenko68404f12008-03-17 09:00:54 +000012769 argv += 2;
12770 if (argv[0]) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012771 STARTSTACKSTR(concat);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012772 for (;;) {
12773 concat = stack_putstr(p, concat);
Denis Vlasenko68404f12008-03-17 09:00:54 +000012774 p = *argv++;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012775 if (p == NULL)
12776 break;
12777 STPUTC(' ', concat);
12778 }
12779 STPUTC('\0', concat);
12780 p = grabstackstr(concat);
12781 }
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020012782 return evalstring(p, flags & EV_TESTED);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012783 }
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012784 return 0;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012785}
12786
12787/*
Denys Vlasenko285ad152009-12-04 23:02:27 +010012788 * Read and execute commands.
12789 * "Top" is nonzero for the top level command loop;
12790 * it turns on prompting if the shell is interactive.
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012791 */
12792static int
12793cmdloop(int top)
12794{
12795 union node *n;
12796 struct stackmark smark;
12797 int inter;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020012798 int status = 0;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012799 int numeof = 0;
12800
12801 TRACE(("cmdloop(%d) called\n", top));
12802 for (;;) {
12803 int skip;
12804
12805 setstackmark(&smark);
12806#if JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +000012807 if (doing_jobctl)
Denys Vlasenko9c541002015-10-07 15:44:36 +020012808 showjobs(SHOW_CHANGED|SHOW_STDERR);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012809#endif
12810 inter = 0;
12811 if (iflag && top) {
12812 inter++;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012813 chkmail();
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012814 }
12815 n = parsecmd(inter);
Denys Vlasenko7cee00e2009-07-24 01:08:03 +020012816#if DEBUG
12817 if (DEBUG > 2 && debug && (n != NODE_EOF))
Denys Vlasenko883cea42009-07-11 15:31:59 +020012818 showtree(n);
Denis Vlasenko135cecb2009-04-12 00:00:57 +000012819#endif
Denys Vlasenko86e83ec2009-07-23 22:07:07 +020012820 if (n == NODE_EOF) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012821 if (!top || numeof >= 50)
12822 break;
12823 if (!stoppedjobs()) {
12824 if (!Iflag)
12825 break;
12826 out2str("\nUse \"exit\" to leave shell.\n");
12827 }
12828 numeof++;
12829 } else if (nflag == 0) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020012830 int i;
12831
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +000012832 /* job_warning can only be 2,1,0. Here 2->1, 1/0->0 */
12833 job_warning >>= 1;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012834 numeof = 0;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020012835 i = evaltree(n, 0);
12836 if (n)
12837 status = i;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012838 }
12839 popstackmark(&smark);
12840 skip = evalskip;
12841
12842 if (skip) {
Denys Vlasenko6a0710e2016-09-30 14:18:34 +020012843 evalskip &= ~SKIPFUNC;
Denys Vlasenko0840c912016-10-01 15:27:44 +020012844 break;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012845 }
12846 }
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020012847 return status;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012848}
12849
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000012850/*
12851 * Take commands from a file. To be compatible we should do a path
12852 * search for the file, which is necessary to find sub-commands.
12853 */
12854static char *
12855find_dot_file(char *name)
12856{
12857 char *fullname;
12858 const char *path = pathval();
12859 struct stat statb;
12860
12861 /* don't try this for absolute or relative paths */
12862 if (strchr(name, '/'))
12863 return name;
12864
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020012865 while ((fullname = path_advance(&path, name)) != NULL) {
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000012866 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
12867 /*
12868 * Don't bother freeing here, since it will
12869 * be freed by the caller.
12870 */
12871 return fullname;
12872 }
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020012873 if (fullname != name)
12874 stunalloc(fullname);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000012875 }
12876
12877 /* not found in the PATH */
12878 ash_msg_and_raise_error("%s: not found", name);
12879 /* NOTREACHED */
12880}
12881
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012882static int FAST_FUNC
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012883dotcmd(int argc_ UNUSED_PARAM, char **argv_ UNUSED_PARAM)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012884{
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012885 /* "false; . empty_file; echo $?" should print 0, not 1: */
12886 int status = 0;
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012887 char *fullname;
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012888 char **argv;
Denys Vlasenkofb87d932017-01-09 08:22:06 +010012889 char *args_need_save;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012890 volatile struct shparam saveparam;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012891
Denys Vlasenko981a0562017-07-26 19:53:11 +020012892//???
12893// struct strlist *sp;
12894// for (sp = cmdenviron; sp; sp = sp->next)
12895// setvareq(ckstrdup(sp->text), VSTRFIXED | VTEXTFIXED);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012896
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012897 nextopt(nullstr); /* handle possible "--" */
12898 argv = argptr;
12899
12900 if (!argv[0]) {
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012901 /* bash says: "bash: .: filename argument required" */
12902 return 2; /* bash compat */
12903 }
12904
Denys Vlasenko091f8312013-03-17 14:25:22 +010012905 /* This aborts if file isn't found, which is POSIXly correct.
12906 * bash returns exitcode 1 instead.
12907 */
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012908 fullname = find_dot_file(argv[0]);
12909 argv++;
Denys Vlasenkofb87d932017-01-09 08:22:06 +010012910 args_need_save = argv[0];
Denys Vlasenko5f7c82b2017-02-03 13:00:06 +010012911 if (args_need_save) { /* ". FILE ARGS", and ARGS are not empty */
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012912 int argc;
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012913 saveparam = shellparam;
12914 shellparam.malloced = 0;
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012915 argc = 1;
12916 while (argv[argc])
12917 argc++;
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012918 shellparam.nparam = argc;
12919 shellparam.p = argv;
12920 };
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012921
Denys Vlasenko091f8312013-03-17 14:25:22 +010012922 /* This aborts if file can't be opened, which is POSIXly correct.
12923 * bash returns exitcode 1 instead.
12924 */
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012925 setinputfile(fullname, INPUT_PUSH_FILE);
12926 commandname = fullname;
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012927 status = cmdloop(0);
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012928 popfile();
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012929
Denys Vlasenkofb87d932017-01-09 08:22:06 +010012930 if (args_need_save) {
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012931 freeparam(&shellparam);
12932 shellparam = saveparam;
12933 };
12934
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012935 return status;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012936}
12937
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012938static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012939exitcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012940{
12941 if (stoppedjobs())
12942 return 0;
Denis Vlasenko68404f12008-03-17 09:00:54 +000012943 if (argv[1])
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012944 exitstatus = number(argv[1]);
12945 raise_exception(EXEXIT);
12946 /* NOTREACHED */
12947}
12948
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012949/*
12950 * Read a file containing shell functions.
12951 */
12952static void
12953readcmdfile(char *name)
12954{
12955 setinputfile(name, INPUT_PUSH_FILE);
12956 cmdloop(0);
12957 popfile();
12958}
12959
12960
Denis Vlasenkocc571512007-02-23 21:10:35 +000012961/* ============ find_command inplementation */
12962
12963/*
12964 * Resolve a command name. If you change this routine, you may have to
12965 * change the shellexec routine as well.
12966 */
12967static void
12968find_command(char *name, struct cmdentry *entry, int act, const char *path)
12969{
12970 struct tblentry *cmdp;
12971 int idx;
12972 int prev;
12973 char *fullname;
12974 struct stat statb;
12975 int e;
12976 int updatetbl;
12977 struct builtincmd *bcmd;
12978
12979 /* If name contains a slash, don't use PATH or hash table */
12980 if (strchr(name, '/') != NULL) {
12981 entry->u.index = -1;
12982 if (act & DO_ABS) {
12983 while (stat(name, &statb) < 0) {
12984#ifdef SYSV
12985 if (errno == EINTR)
12986 continue;
12987#endif
12988 entry->cmdtype = CMDUNKNOWN;
12989 return;
12990 }
12991 }
12992 entry->cmdtype = CMDNORMAL;
12993 return;
12994 }
12995
Denis Vlasenkof20de5b2007-04-29 23:42:54 +000012996/* #if ENABLE_FEATURE_SH_STANDALONE... moved after builtin check */
Denis Vlasenkocc571512007-02-23 21:10:35 +000012997
12998 updatetbl = (path == pathval());
12999 if (!updatetbl) {
13000 act |= DO_ALTPATH;
13001 if (strstr(path, "%builtin") != NULL)
13002 act |= DO_ALTBLTIN;
13003 }
13004
13005 /* If name is in the table, check answer will be ok */
13006 cmdp = cmdlookup(name, 0);
13007 if (cmdp != NULL) {
13008 int bit;
13009
13010 switch (cmdp->cmdtype) {
13011 default:
13012#if DEBUG
13013 abort();
13014#endif
13015 case CMDNORMAL:
13016 bit = DO_ALTPATH;
13017 break;
13018 case CMDFUNCTION:
13019 bit = DO_NOFUNC;
13020 break;
13021 case CMDBUILTIN:
13022 bit = DO_ALTBLTIN;
13023 break;
13024 }
13025 if (act & bit) {
13026 updatetbl = 0;
13027 cmdp = NULL;
13028 } else if (cmdp->rehash == 0)
13029 /* if not invalidated by cd, we're done */
13030 goto success;
13031 }
13032
13033 /* If %builtin not in path, check for builtin next */
13034 bcmd = find_builtin(name);
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000013035 if (bcmd) {
13036 if (IS_BUILTIN_REGULAR(bcmd))
13037 goto builtin_success;
13038 if (act & DO_ALTPATH) {
13039 if (!(act & DO_ALTBLTIN))
13040 goto builtin_success;
13041 } else if (builtinloc <= 0) {
13042 goto builtin_success;
Denis Vlasenko8e858e22007-03-07 09:35:43 +000013043 }
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000013044 }
Denis Vlasenkocc571512007-02-23 21:10:35 +000013045
Denis Vlasenkof20de5b2007-04-29 23:42:54 +000013046#if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko7465dbc2008-04-13 02:25:53 +000013047 {
13048 int applet_no = find_applet_by_name(name);
13049 if (applet_no >= 0) {
13050 entry->cmdtype = CMDNORMAL;
13051 entry->u.index = -2 - applet_no;
13052 return;
13053 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +000013054 }
13055#endif
13056
Denis Vlasenkocc571512007-02-23 21:10:35 +000013057 /* We have to search path. */
13058 prev = -1; /* where to start */
13059 if (cmdp && cmdp->rehash) { /* doing a rehash */
13060 if (cmdp->cmdtype == CMDBUILTIN)
13061 prev = builtinloc;
13062 else
13063 prev = cmdp->param.index;
13064 }
13065
13066 e = ENOENT;
13067 idx = -1;
13068 loop:
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020013069 while ((fullname = path_advance(&path, name)) != NULL) {
Denis Vlasenkocc571512007-02-23 21:10:35 +000013070 stunalloc(fullname);
Denis Vlasenkodee82b62007-07-29 14:05:27 +000013071 /* NB: code below will still use fullname
13072 * despite it being "unallocated" */
Denis Vlasenkocc571512007-02-23 21:10:35 +000013073 idx++;
13074 if (pathopt) {
13075 if (prefix(pathopt, "builtin")) {
13076 if (bcmd)
13077 goto builtin_success;
13078 continue;
Denis Vlasenko4a9ca132008-04-12 20:07:08 +000013079 }
13080 if ((act & DO_NOFUNC)
13081 || !prefix(pathopt, "func")
Denys Vlasenkoe4dcba12010-10-28 18:57:19 +020013082 ) { /* ignore unimplemented options */
Denis Vlasenkocc571512007-02-23 21:10:35 +000013083 continue;
13084 }
13085 }
13086 /* if rehash, don't redo absolute path names */
13087 if (fullname[0] == '/' && idx <= prev) {
13088 if (idx < prev)
13089 continue;
13090 TRACE(("searchexec \"%s\": no change\n", name));
13091 goto success;
13092 }
13093 while (stat(fullname, &statb) < 0) {
13094#ifdef SYSV
13095 if (errno == EINTR)
13096 continue;
13097#endif
13098 if (errno != ENOENT && errno != ENOTDIR)
13099 e = errno;
13100 goto loop;
13101 }
13102 e = EACCES; /* if we fail, this will be the error */
13103 if (!S_ISREG(statb.st_mode))
13104 continue;
13105 if (pathopt) { /* this is a %func directory */
13106 stalloc(strlen(fullname) + 1);
Denis Vlasenkodee82b62007-07-29 14:05:27 +000013107 /* NB: stalloc will return space pointed by fullname
13108 * (because we don't have any intervening allocations
13109 * between stunalloc above and this stalloc) */
Denis Vlasenkocc571512007-02-23 21:10:35 +000013110 readcmdfile(fullname);
13111 cmdp = cmdlookup(name, 0);
13112 if (cmdp == NULL || cmdp->cmdtype != CMDFUNCTION)
13113 ash_msg_and_raise_error("%s not defined in %s", name, fullname);
13114 stunalloc(fullname);
13115 goto success;
13116 }
13117 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
13118 if (!updatetbl) {
13119 entry->cmdtype = CMDNORMAL;
13120 entry->u.index = idx;
13121 return;
13122 }
13123 INT_OFF;
13124 cmdp = cmdlookup(name, 1);
13125 cmdp->cmdtype = CMDNORMAL;
13126 cmdp->param.index = idx;
13127 INT_ON;
13128 goto success;
13129 }
13130
13131 /* We failed. If there was an entry for this command, delete it */
13132 if (cmdp && updatetbl)
13133 delete_cmd_entry();
13134 if (act & DO_ERR)
13135 ash_msg("%s: %s", name, errmsg(e, "not found"));
13136 entry->cmdtype = CMDUNKNOWN;
13137 return;
13138
13139 builtin_success:
13140 if (!updatetbl) {
13141 entry->cmdtype = CMDBUILTIN;
13142 entry->u.cmd = bcmd;
13143 return;
13144 }
13145 INT_OFF;
13146 cmdp = cmdlookup(name, 1);
13147 cmdp->cmdtype = CMDBUILTIN;
13148 cmdp->param.cmd = bcmd;
13149 INT_ON;
13150 success:
13151 cmdp->rehash = 0;
13152 entry->cmdtype = cmdp->cmdtype;
13153 entry->u = cmdp->param;
13154}
13155
13156
Eric Andersencb57d552001-06-28 07:25:16 +000013157/*
Eric Andersencb57d552001-06-28 07:25:16 +000013158 * The trap builtin.
13159 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013160static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013161trapcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +000013162{
13163 char *action;
13164 char **ap;
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010013165 int signo, exitcode;
Eric Andersencb57d552001-06-28 07:25:16 +000013166
Eric Andersenc470f442003-07-28 09:56:35 +000013167 nextopt(nullstr);
13168 ap = argptr;
13169 if (!*ap) {
Denis Vlasenko2da584f2007-02-19 22:44:05 +000013170 for (signo = 0; signo < NSIG; signo++) {
Denys Vlasenko21d87d42009-09-25 00:06:51 +020013171 char *tr = trap_ptr[signo];
13172 if (tr) {
Denys Vlasenkoe74aaf92009-09-27 02:05:45 +020013173 /* note: bash adds "SIG", but only if invoked
13174 * as "bash". If called as "sh", or if set -o posix,
13175 * then it prints short signal names.
13176 * We are printing short names: */
13177 out1fmt("trap -- %s %s\n",
Denys Vlasenko21d87d42009-09-25 00:06:51 +020013178 single_quote(tr),
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +000013179 get_signame(signo));
Denys Vlasenko726e1a02009-09-25 02:58:20 +020013180 /* trap_ptr != trap only if we are in special-cased `trap` code.
13181 * In this case, we will exit very soon, no need to free(). */
Denys Vlasenkoe74aaf92009-09-27 02:05:45 +020013182 /* if (trap_ptr != trap && tp[0]) */
Denys Vlasenko726e1a02009-09-25 02:58:20 +020013183 /* free(tr); */
Eric Andersencb57d552001-06-28 07:25:16 +000013184 }
13185 }
Denys Vlasenko726e1a02009-09-25 02:58:20 +020013186 /*
Denys Vlasenko21d87d42009-09-25 00:06:51 +020013187 if (trap_ptr != trap) {
13188 free(trap_ptr);
13189 trap_ptr = trap;
13190 }
Denys Vlasenko726e1a02009-09-25 02:58:20 +020013191 */
Eric Andersencb57d552001-06-28 07:25:16 +000013192 return 0;
13193 }
Denys Vlasenko21d87d42009-09-25 00:06:51 +020013194
Denys Vlasenko86981e32017-07-25 20:06:17 +020013195 /* Why the second check?
13196 * "trap NUM [sig2]..." is the same as "trap - NUM [sig2]..."
13197 * In this case, NUM is signal no, not an action.
13198 */
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +000013199 action = NULL;
Denys Vlasenko86981e32017-07-25 20:06:17 +020013200 if (ap[1] && !is_number(ap[0]))
Eric Andersencb57d552001-06-28 07:25:16 +000013201 action = *ap++;
Denys Vlasenko86981e32017-07-25 20:06:17 +020013202
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010013203 exitcode = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000013204 while (*ap) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000013205 signo = get_signum(*ap);
Denys Vlasenko86981e32017-07-25 20:06:17 +020013206 if (signo < 0) {
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010013207 /* Mimic bash message exactly */
13208 ash_msg("%s: invalid signal specification", *ap);
13209 exitcode = 1;
13210 goto next;
13211 }
Denis Vlasenkob012b102007-02-19 22:43:01 +000013212 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +000013213 if (action) {
Denis Vlasenko9f739442006-12-16 23:49:13 +000013214 if (LONE_DASH(action))
Eric Andersencb57d552001-06-28 07:25:16 +000013215 action = NULL;
Denys Vlasenkob4f51d32016-10-27 12:55:09 +020013216 else {
13217 if (action[0]) /* not NULL and not "" and not "-" */
13218 may_have_traps = 1;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013219 action = ckstrdup(action);
Denys Vlasenkob4f51d32016-10-27 12:55:09 +020013220 }
Eric Andersencb57d552001-06-28 07:25:16 +000013221 }
Denis Vlasenko60818682007-09-28 22:07:23 +000013222 free(trap[signo]);
Eric Andersencb57d552001-06-28 07:25:16 +000013223 trap[signo] = action;
13224 if (signo != 0)
13225 setsignal(signo);
Denis Vlasenkob012b102007-02-19 22:43:01 +000013226 INT_ON;
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010013227 next:
Eric Andersencb57d552001-06-28 07:25:16 +000013228 ap++;
13229 }
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010013230 return exitcode;
Eric Andersencb57d552001-06-28 07:25:16 +000013231}
13232
Eric Andersenc470f442003-07-28 09:56:35 +000013233
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013234/* ============ Builtins */
Eric Andersenc470f442003-07-28 09:56:35 +000013235
Denys Vlasenko2ec34962014-09-08 16:52:39 +020013236#if ENABLE_ASH_HELP
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013237static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013238helpcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000013239{
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000013240 unsigned col;
13241 unsigned i;
Eric Andersenc470f442003-07-28 09:56:35 +000013242
Denys Vlasenkod6b05eb2009-06-06 20:59:55 +020013243 out1fmt(
Denis Vlasenko34d4d892009-04-04 20:24:37 +000013244 "Built-in commands:\n"
13245 "------------------\n");
Denis Vlasenkob71c6682007-07-21 15:08:09 +000013246 for (col = 0, i = 0; i < ARRAY_SIZE(builtintab); i++) {
Eric Andersenc470f442003-07-28 09:56:35 +000013247 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
Denis Vlasenko52764022007-02-24 13:42:56 +000013248 builtintab[i].name + 1);
Eric Andersenc470f442003-07-28 09:56:35 +000013249 if (col > 60) {
13250 out1fmt("\n");
13251 col = 0;
13252 }
13253 }
Denys Vlasenko2ec34962014-09-08 16:52:39 +020013254# if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko1aa7e472007-11-28 06:49:03 +000013255 {
13256 const char *a = applet_names;
13257 while (*a) {
13258 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), a);
13259 if (col > 60) {
13260 out1fmt("\n");
13261 col = 0;
13262 }
Ron Yorston2b919582016-04-08 11:57:20 +010013263 while (*a++ != '\0')
13264 continue;
Eric Andersenc470f442003-07-28 09:56:35 +000013265 }
13266 }
Denys Vlasenko2ec34962014-09-08 16:52:39 +020013267# endif
Denys Vlasenkoebedb942016-10-02 18:45:09 +020013268 newline_and_flush(stdout);
Eric Andersenc470f442003-07-28 09:56:35 +000013269 return EXIT_SUCCESS;
13270}
Denys Vlasenko2ec34962014-09-08 16:52:39 +020013271#endif
Eric Andersenc470f442003-07-28 09:56:35 +000013272
Flemming Madsend96ffda2013-04-07 18:47:24 +020013273#if MAX_HISTORY
13274static int FAST_FUNC
13275historycmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
13276{
13277 show_history(line_input_state);
13278 return EXIT_SUCCESS;
13279}
13280#endif
13281
Eric Andersencb57d552001-06-28 07:25:16 +000013282/*
Eric Andersencb57d552001-06-28 07:25:16 +000013283 * The export and readonly commands.
13284 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013285static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013286exportcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000013287{
13288 struct var *vp;
13289 char *name;
13290 const char *p;
Eric Andersenc470f442003-07-28 09:56:35 +000013291 char **aptr;
Denys Vlasenkod5275882012-10-01 13:41:17 +020013292 char opt;
13293 int flag;
13294 int flag_off;
Eric Andersencb57d552001-06-28 07:25:16 +000013295
Denys Vlasenkod5275882012-10-01 13:41:17 +020013296 /* "readonly" in bash accepts, but ignores -n.
13297 * We do the same: it saves a conditional in nextopt's param.
13298 */
13299 flag_off = 0;
13300 while ((opt = nextopt("np")) != '\0') {
13301 if (opt == 'n')
13302 flag_off = VEXPORT;
13303 }
13304 flag = VEXPORT;
13305 if (argv[0][0] == 'r') {
13306 flag = VREADONLY;
13307 flag_off = 0; /* readonly ignores -n */
13308 }
13309 flag_off = ~flag_off;
13310
Denys Vlasenko10ad6222017-04-17 16:13:32 +020013311 /*if (opt_p_not_specified) - bash doesn't check this. Try "export -p NAME" */
Denys Vlasenkod5275882012-10-01 13:41:17 +020013312 {
Denis Vlasenko2da584f2007-02-19 22:44:05 +000013313 aptr = argptr;
13314 name = *aptr;
13315 if (name) {
13316 do {
13317 p = strchr(name, '=');
13318 if (p != NULL) {
13319 p++;
13320 } else {
13321 vp = *findvar(hashvar(name), name);
13322 if (vp) {
Denys Vlasenkod5275882012-10-01 13:41:17 +020013323 vp->flags = ((vp->flags | flag) & flag_off);
Denis Vlasenko2da584f2007-02-19 22:44:05 +000013324 continue;
13325 }
Eric Andersencb57d552001-06-28 07:25:16 +000013326 }
Denys Vlasenkod5275882012-10-01 13:41:17 +020013327 setvar(name, p, (flag & flag_off));
Denis Vlasenko2da584f2007-02-19 22:44:05 +000013328 } while ((name = *++aptr) != NULL);
13329 return 0;
13330 }
Eric Andersencb57d552001-06-28 07:25:16 +000013331 }
Denys Vlasenkod5275882012-10-01 13:41:17 +020013332
13333 /* No arguments. Show the list of exported or readonly vars.
13334 * -n is ignored.
13335 */
Denis Vlasenko2da584f2007-02-19 22:44:05 +000013336 showvars(argv[0], flag, 0);
Eric Andersencb57d552001-06-28 07:25:16 +000013337 return 0;
13338}
13339
Eric Andersencb57d552001-06-28 07:25:16 +000013340/*
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000013341 * Delete a function if it exists.
Eric Andersencb57d552001-06-28 07:25:16 +000013342 */
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +000013343static void
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000013344unsetfunc(const char *name)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000013345{
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000013346 struct tblentry *cmdp;
Eric Andersencb57d552001-06-28 07:25:16 +000013347
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000013348 cmdp = cmdlookup(name, 0);
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020013349 if (cmdp != NULL && cmdp->cmdtype == CMDFUNCTION)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000013350 delete_cmd_entry();
Eric Andersenc470f442003-07-28 09:56:35 +000013351}
13352
Eric Andersencb57d552001-06-28 07:25:16 +000013353/*
Eric Andersencb57d552001-06-28 07:25:16 +000013354 * The unset builtin command. We unset the function before we unset the
13355 * variable to allow a function to be unset when there is a readonly variable
13356 * with the same name.
13357 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013358static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013359unsetcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +000013360{
13361 char **ap;
13362 int i;
Eric Andersenc470f442003-07-28 09:56:35 +000013363 int flag = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000013364
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020013365 while ((i = nextopt("vf")) != 0) {
Eric Andersenc470f442003-07-28 09:56:35 +000013366 flag = i;
Eric Andersencb57d552001-06-28 07:25:16 +000013367 }
Eric Andersencb57d552001-06-28 07:25:16 +000013368
Denis Vlasenko2da584f2007-02-19 22:44:05 +000013369 for (ap = argptr; *ap; ap++) {
Eric Andersenc470f442003-07-28 09:56:35 +000013370 if (flag != 'f') {
Denys Vlasenkob28d4c32017-07-25 16:29:36 +020013371 unsetvar(*ap);
13372 continue;
Eric Andersenc470f442003-07-28 09:56:35 +000013373 }
13374 if (flag != 'v')
Eric Andersencb57d552001-06-28 07:25:16 +000013375 unsetfunc(*ap);
Eric Andersencb57d552001-06-28 07:25:16 +000013376 }
Denys Vlasenkob28d4c32017-07-25 16:29:36 +020013377 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +000013378}
13379
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000013380static const unsigned char timescmd_str[] ALIGN1 = {
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013381 ' ', offsetof(struct tms, tms_utime),
13382 '\n', offsetof(struct tms, tms_stime),
13383 ' ', offsetof(struct tms, tms_cutime),
13384 '\n', offsetof(struct tms, tms_cstime),
13385 0
13386};
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013387static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013388timescmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013389{
Denys Vlasenko11f2e992017-08-10 16:34:03 +020013390 unsigned clk_tck;
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013391 const unsigned char *p;
13392 struct tms buf;
13393
Bartosz Golaszewski5d2e4092014-06-22 14:01:13 +020013394 clk_tck = bb_clk_tck();
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013395
Denys Vlasenko11f2e992017-08-10 16:34:03 +020013396 times(&buf);
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013397 p = timescmd_str;
13398 do {
Denys Vlasenko11f2e992017-08-10 16:34:03 +020013399 unsigned sec, frac;
13400 unsigned long t;
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013401 t = *(clock_t *)(((char *) &buf) + p[1]);
Denys Vlasenko11f2e992017-08-10 16:34:03 +020013402 sec = t / clk_tck;
13403 frac = t % clk_tck;
13404 out1fmt("%um%u.%03us%c",
13405 sec / 60, sec % 60,
13406 (frac * 1000) / clk_tck,
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013407 p[0]);
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020013408 p += 2;
13409 } while (*p);
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013410
Eric Andersencb57d552001-06-28 07:25:16 +000013411 return 0;
13412}
13413
Denys Vlasenko0b883582016-12-23 16:49:07 +010013414#if ENABLE_FEATURE_SH_MATH
Eric Andersenc470f442003-07-28 09:56:35 +000013415/*
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020013416 * The let builtin. Partially stolen from GNU Bash, the Bourne Again SHell.
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +000013417 * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
Eric Andersen90898442003-08-06 11:20:52 +000013418 *
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +000013419 * Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
Eric Andersenc470f442003-07-28 09:56:35 +000013420 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013421static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013422letcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersenc470f442003-07-28 09:56:35 +000013423{
Denis Vlasenko68404f12008-03-17 09:00:54 +000013424 arith_t i;
Eric Andersenc470f442003-07-28 09:56:35 +000013425
Denis Vlasenko68404f12008-03-17 09:00:54 +000013426 argv++;
13427 if (!*argv)
Denis Vlasenkob012b102007-02-19 22:43:01 +000013428 ash_msg_and_raise_error("expression expected");
Denis Vlasenko68404f12008-03-17 09:00:54 +000013429 do {
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +000013430 i = ash_arith(*argv);
Denis Vlasenko68404f12008-03-17 09:00:54 +000013431 } while (*++argv);
Eric Andersenc470f442003-07-28 09:56:35 +000013432
Denis Vlasenkod9e15f22006-11-27 16:49:55 +000013433 return !i;
Eric Andersenc470f442003-07-28 09:56:35 +000013434}
Eric Andersenc470f442003-07-28 09:56:35 +000013435#endif
Eric Andersen74bcd162001-07-30 21:41:37 +000013436
Eric Andersenc470f442003-07-28 09:56:35 +000013437/*
Denis Vlasenko59f351c2008-03-25 00:07:12 +000013438 * The read builtin. Options:
13439 * -r Do not interpret '\' specially
13440 * -s Turn off echo (tty only)
13441 * -n NCHARS Read NCHARS max
13442 * -p PROMPT Display PROMPT on stderr (if input is from tty)
13443 * -t SECONDS Timeout after SECONDS (tty or pipe only)
13444 * -u FD Read from given FD instead of fd 0
Johannes Schindelin3bef5d82017-08-08 16:46:39 +020013445 * -d DELIM End on DELIM char, not newline
Eric Andersenc470f442003-07-28 09:56:35 +000013446 * This uses unbuffered input, which may be avoidable in some cases.
Denis Vlasenko59f351c2008-03-25 00:07:12 +000013447 * TODO: bash also has:
13448 * -a ARRAY Read into array[0],[1],etc
Denis Vlasenko59f351c2008-03-25 00:07:12 +000013449 * -e Use line editing (tty only)
Eric Andersenc470f442003-07-28 09:56:35 +000013450 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013451static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013452readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000013453{
Denys Vlasenko73067272010-01-12 22:11:24 +010013454 char *opt_n = NULL;
13455 char *opt_p = NULL;
13456 char *opt_t = NULL;
13457 char *opt_u = NULL;
Johannes Schindelin3bef5d82017-08-08 16:46:39 +020013458 char *opt_d = NULL; /* optimized out if !BASH */
Denys Vlasenko73067272010-01-12 22:11:24 +010013459 int read_flags = 0;
13460 const char *r;
Eric Andersenc470f442003-07-28 09:56:35 +000013461 int i;
13462
Johannes Schindelin3bef5d82017-08-08 16:46:39 +020013463 while ((i = nextopt("p:u:rt:n:sd:")) != '\0') {
Denis Vlasenkobf0a2012006-12-26 10:42:51 +000013464 switch (i) {
Paul Fox02eb9342005-09-07 16:56:02 +000013465 case 'p':
Denys Vlasenko73067272010-01-12 22:11:24 +010013466 opt_p = optionarg;
Paul Fox02eb9342005-09-07 16:56:02 +000013467 break;
Paul Fox02eb9342005-09-07 16:56:02 +000013468 case 'n':
Denys Vlasenko73067272010-01-12 22:11:24 +010013469 opt_n = optionarg;
Paul Fox02eb9342005-09-07 16:56:02 +000013470 break;
13471 case 's':
Denys Vlasenko73067272010-01-12 22:11:24 +010013472 read_flags |= BUILTIN_READ_SILENT;
Paul Fox02eb9342005-09-07 16:56:02 +000013473 break;
Paul Fox02eb9342005-09-07 16:56:02 +000013474 case 't':
Denys Vlasenko73067272010-01-12 22:11:24 +010013475 opt_t = optionarg;
Paul Fox02eb9342005-09-07 16:56:02 +000013476 break;
Paul Fox02eb9342005-09-07 16:56:02 +000013477 case 'r':
Denys Vlasenko73067272010-01-12 22:11:24 +010013478 read_flags |= BUILTIN_READ_RAW;
Paul Fox02eb9342005-09-07 16:56:02 +000013479 break;
Denis Vlasenko59f351c2008-03-25 00:07:12 +000013480 case 'u':
Denys Vlasenko73067272010-01-12 22:11:24 +010013481 opt_u = optionarg;
Denis Vlasenko59f351c2008-03-25 00:07:12 +000013482 break;
Johannes Schindelin3bef5d82017-08-08 16:46:39 +020013483#if BASH_READ_D
13484 case 'd':
13485 opt_d = optionarg;
13486 break;
13487#endif
Paul Fox02eb9342005-09-07 16:56:02 +000013488 default:
13489 break;
13490 }
Eric Andersenc470f442003-07-28 09:56:35 +000013491 }
Paul Fox02eb9342005-09-07 16:56:02 +000013492
Denys Vlasenko9e71e3c2012-09-06 13:28:10 +020013493 /* "read -s" needs to save/restore termios, can't allow ^C
13494 * to jump out of it.
13495 */
Denys Vlasenkof5470412017-05-22 19:34:45 +020013496 again:
Denys Vlasenko9e71e3c2012-09-06 13:28:10 +020013497 INT_OFF;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020013498 r = shell_builtin_read(setvar0,
Denys Vlasenko73067272010-01-12 22:11:24 +010013499 argptr,
13500 bltinlookup("IFS"), /* can be NULL */
13501 read_flags,
13502 opt_n,
13503 opt_p,
13504 opt_t,
Johannes Schindelin3bef5d82017-08-08 16:46:39 +020013505 opt_u,
13506 opt_d
Denys Vlasenko73067272010-01-12 22:11:24 +010013507 );
Denys Vlasenko9e71e3c2012-09-06 13:28:10 +020013508 INT_ON;
Denis Vlasenko46aeab92009-03-31 19:18:17 +000013509
Denys Vlasenkof5470412017-05-22 19:34:45 +020013510 if ((uintptr_t)r == 1 && errno == EINTR) {
Denys Vlasenko49e6bf22017-08-04 14:28:16 +020013511 /* To get SIGCHLD: sleep 1 & read x; echo $x
13512 * Correct behavior is to not exit "read"
13513 */
Denys Vlasenkof5470412017-05-22 19:34:45 +020013514 if (pending_sig == 0)
13515 goto again;
13516 }
13517
Denys Vlasenko73067272010-01-12 22:11:24 +010013518 if ((uintptr_t)r > 1)
13519 ash_msg_and_raise_error(r);
Denis Vlasenko037576d2007-10-20 18:30:38 +000013520
Denys Vlasenko73067272010-01-12 22:11:24 +010013521 return (uintptr_t)r;
Eric Andersenc470f442003-07-28 09:56:35 +000013522}
13523
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013524static int FAST_FUNC
Denys Vlasenko6283f982015-10-07 16:56:20 +020013525umaskcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000013526{
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013527 static const char permuser[3] ALIGN1 = "ogu";
Eric Andersenc470f442003-07-28 09:56:35 +000013528
Eric Andersenc470f442003-07-28 09:56:35 +000013529 mode_t mask;
Eric Andersenc470f442003-07-28 09:56:35 +000013530 int symbolic_mode = 0;
13531
13532 while (nextopt("S") != '\0') {
13533 symbolic_mode = 1;
13534 }
13535
Denis Vlasenkob012b102007-02-19 22:43:01 +000013536 INT_OFF;
Eric Andersenc470f442003-07-28 09:56:35 +000013537 mask = umask(0);
13538 umask(mask);
Denis Vlasenkob012b102007-02-19 22:43:01 +000013539 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +000013540
Denys Vlasenko6283f982015-10-07 16:56:20 +020013541 if (*argptr == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +000013542 if (symbolic_mode) {
Denys Vlasenko005c4922015-10-10 20:17:12 +020013543 char buf[sizeof(",u=rwx,g=rwx,o=rwx")];
Eric Andersenc470f442003-07-28 09:56:35 +000013544 char *p = buf;
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013545 int i;
Eric Andersenc470f442003-07-28 09:56:35 +000013546
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013547 i = 2;
13548 for (;;) {
Denys Vlasenko005c4922015-10-10 20:17:12 +020013549 *p++ = ',';
Eric Andersenc470f442003-07-28 09:56:35 +000013550 *p++ = permuser[i];
13551 *p++ = '=';
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013552 /* mask is 0..0uuugggooo. i=2 selects uuu bits */
Denys Vlasenko005c4922015-10-10 20:17:12 +020013553 if (!(mask & 0400)) *p++ = 'r';
13554 if (!(mask & 0200)) *p++ = 'w';
13555 if (!(mask & 0100)) *p++ = 'x';
13556 mask <<= 3;
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013557 if (--i < 0)
13558 break;
Eric Andersenc470f442003-07-28 09:56:35 +000013559 }
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013560 *p = '\0';
Denys Vlasenko005c4922015-10-10 20:17:12 +020013561 puts(buf + 1);
Eric Andersenc470f442003-07-28 09:56:35 +000013562 } else {
Denys Vlasenkoec046f72015-10-07 17:57:53 +020013563 out1fmt("%04o\n", mask);
Eric Andersenc470f442003-07-28 09:56:35 +000013564 }
13565 } else {
Denys Vlasenko6283f982015-10-07 16:56:20 +020013566 char *modestr = *argptr;
Denys Vlasenko14c85eb2017-10-12 19:40:47 +020013567 /* numeric umasks are taken as-is */
13568 /* symbolic umasks are inverted: "umask a=rx" calls umask(222) */
Denys Vlasenko6283f982015-10-07 16:56:20 +020013569 if (!isdigit(modestr[0]))
13570 mask ^= 0777;
Denys Vlasenko5711a2a2015-10-07 17:55:33 +020013571 mask = bb_parse_mode(modestr, mask);
13572 if ((unsigned)mask > 0777) {
Denys Vlasenko6283f982015-10-07 16:56:20 +020013573 ash_msg_and_raise_error("illegal mode: %s", modestr);
Eric Andersenc470f442003-07-28 09:56:35 +000013574 }
Denys Vlasenko6283f982015-10-07 16:56:20 +020013575 if (!isdigit(modestr[0]))
13576 mask ^= 0777;
13577 umask(mask);
Eric Andersenc470f442003-07-28 09:56:35 +000013578 }
13579 return 0;
13580}
13581
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013582static int FAST_FUNC
Denys Vlasenkof3c742f2010-03-06 20:12:00 +010013583ulimitcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersenc470f442003-07-28 09:56:35 +000013584{
Denys Vlasenkof3c742f2010-03-06 20:12:00 +010013585 return shell_builtin_ulimit(argv);
Eric Andersenc470f442003-07-28 09:56:35 +000013586}
13587
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013588/* ============ main() and helpers */
13589
13590/*
13591 * Called to exit the shell.
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013592 */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013593static void
13594exitshell(void)
13595{
13596 struct jmploc loc;
13597 char *p;
13598 int status;
13599
Denys Vlasenkobede2152011-09-04 16:12:33 +020013600#if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT
13601 save_history(line_input_state);
13602#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013603 status = exitstatus;
13604 TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
13605 if (setjmp(loc.loc)) {
Denis Vlasenko7f88e342009-03-19 03:36:18 +000013606 if (exception_type == EXEXIT)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013607 status = exitstatus;
13608 goto out;
13609 }
13610 exception_handler = &loc;
13611 p = trap[0];
13612 if (p) {
13613 trap[0] = NULL;
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020013614 evalskip = 0;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013615 evalstring(p, 0);
Denys Vlasenkof37e1152016-10-07 03:17:28 +020013616 /*free(p); - we'll exit soon */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013617 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013618 out:
Denys Vlasenkof37e1152016-10-07 03:17:28 +020013619 /* dash wraps setjobctl(0) in "if (setjmp(loc.loc) == 0) {...}".
13620 * our setjobctl(0) does not panic if tcsetpgrp fails inside it.
13621 */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013622 setjobctl(0);
Denys Vlasenkocaee80c2016-10-25 20:49:53 +020013623 flush_stdout_stderr();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013624 _exit(status);
13625 /* NOTREACHED */
13626}
13627
Denys Vlasenko49e6bf22017-08-04 14:28:16 +020013628/* Don't inline: conserve stack of caller from having our locals too */
13629static NOINLINE void
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +000013630init(void)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013631{
Denys Vlasenko82dd14a2010-05-17 10:10:01 +020013632 /* we will never free this */
13633 basepf.next_to_pgetc = basepf.buf = ckmalloc(IBUFSIZ);
Denys Vlasenko0485b672017-08-14 19:46:56 +020013634 basepf.linno = 1;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013635
Denys Vlasenko49e6bf22017-08-04 14:28:16 +020013636 sigmode[SIGCHLD - 1] = S_DFL; /* ensure we install handler even if it is SIG_IGNed */
Denys Vlasenko458c1f22016-10-27 23:51:19 +020013637 setsignal(SIGCHLD);
13638
Denys Vlasenko7a7b0342009-12-04 04:18:31 +010013639 /* bash re-enables SIGHUP which is SIG_IGNed on entry.
13640 * Try: "trap '' HUP; bash; echo RET" and type "kill -HUP $$"
13641 */
Denys Vlasenkocacb2cd2010-10-05 00:13:02 +020013642 signal(SIGHUP, SIG_DFL);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013643
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013644 {
13645 char **envp;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013646 const char *p;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013647
13648 initvar();
13649 for (envp = environ; envp && *envp; envp++) {
Denys Vlasenko9c143ce2017-11-02 12:56:24 +010013650/* Used to have
13651 * p = endofname(*envp);
13652 * if (p != *envp && *p == '=') {
13653 * here to weed out badly-named variables, but this breaks
13654 * scenarios where people do want them passed to children:
13655 * import os
13656 * os.environ["test-test"]="test"
13657 * if os.fork() == 0:
13658 * os.execv("ash", [ 'ash', '-c', 'eval $(export -p); echo OK' ]) # fixes this
13659 * os.execv("ash", [ 'ash', '-c', 'env | grep test-test' ]) # breaks this
13660 */
13661 if (strchr(*envp, '=')) {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013662 setvareq(*envp, VEXPORT|VTEXTFIXED);
13663 }
13664 }
13665
Denys Vlasenkoe627ac92016-09-30 14:36:59 +020013666 setvareq((char*)defoptindvar, VTEXTFIXED);
13667
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020013668 setvar0("PPID", utoa(getppid()));
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010013669#if BASH_SHLVL_VAR
Bernhard Reutner-Fischer80f8cdf2013-11-08 14:25:24 +010013670 p = lookupvar("SHLVL");
Denys Vlasenko5680e982014-01-07 16:12:48 +010013671 setvar("SHLVL", utoa((p ? atoi(p) : 0) + 1), VEXPORT);
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010013672#endif
13673#if BASH_HOSTNAME_VAR
Denys Vlasenko3fa97af2014-04-15 11:43:29 +020013674 if (!lookupvar("HOSTNAME")) {
13675 struct utsname uts;
13676 uname(&uts);
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020013677 setvar0("HOSTNAME", uts.nodename);
Denys Vlasenko3fa97af2014-04-15 11:43:29 +020013678 }
Bernhard Reutner-Fischer80f8cdf2013-11-08 14:25:24 +010013679#endif
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013680 p = lookupvar("PWD");
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013681 if (p) {
Denys Vlasenko49e6bf22017-08-04 14:28:16 +020013682 struct stat st1, st2;
Denys Vlasenkoef159702016-09-01 11:16:22 +020013683 if (p[0] != '/' || stat(p, &st1) || stat(".", &st2)
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013684 || st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino
13685 ) {
Denys Vlasenkoef159702016-09-01 11:16:22 +020013686 p = NULL;
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013687 }
13688 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013689 setpwd(p, 0);
13690 }
13691}
13692
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013693
13694//usage:#define ash_trivial_usage
Denys Vlasenko6b6af532011-03-08 10:24:17 +010013695//usage: "[-/+OPTIONS] [-/+o OPT]... [-c 'SCRIPT' [ARG0 [ARGS]] / FILE [ARGS]]"
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013696//usage:#define ash_full_usage "\n\n"
13697//usage: "Unix shell interpreter"
13698
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013699/*
13700 * Process the shell command line arguments.
13701 */
Denys Vlasenkoec05df12017-07-31 19:43:47 +020013702static int
Denis Vlasenko68404f12008-03-17 09:00:54 +000013703procargs(char **argv)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013704{
13705 int i;
13706 const char *xminusc;
13707 char **xargv;
Denys Vlasenkoec05df12017-07-31 19:43:47 +020013708 int login_sh;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013709
13710 xargv = argv;
Denys Vlasenkoec05df12017-07-31 19:43:47 +020013711 login_sh = xargv[0] && xargv[0][0] == '-';
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013712 arg0 = xargv[0];
Denis Vlasenko68404f12008-03-17 09:00:54 +000013713 /* if (xargv[0]) - mmm, this is always true! */
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013714 xargv++;
13715 for (i = 0; i < NOPTS; i++)
13716 optlist[i] = 2;
13717 argptr = xargv;
Denys Vlasenkoec05df12017-07-31 19:43:47 +020013718 if (options(/*cmdline:*/ 1, &login_sh)) {
Denis Vlasenko28bf6712008-02-14 15:01:47 +000013719 /* it already printed err message */
13720 raise_exception(EXERROR);
13721 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013722 xargv = argptr;
13723 xminusc = minusc;
13724 if (*xargv == NULL) {
13725 if (xminusc)
13726 ash_msg_and_raise_error(bb_msg_requires_arg, "-c");
13727 sflag = 1;
13728 }
13729 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
13730 iflag = 1;
13731 if (mflag == 2)
13732 mflag = iflag;
13733 for (i = 0; i < NOPTS; i++)
13734 if (optlist[i] == 2)
13735 optlist[i] = 0;
13736#if DEBUG == 2
13737 debug = 1;
13738#endif
Denys Vlasenko5f7c82b2017-02-03 13:00:06 +010013739 /* POSIX 1003.2: first arg after "-c CMD" is $0, remainder $1... */
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013740 if (xminusc) {
13741 minusc = *xargv++;
13742 if (*xargv)
13743 goto setarg0;
13744 } else if (!sflag) {
13745 setinputfile(*xargv, 0);
13746 setarg0:
13747 arg0 = *xargv++;
13748 commandname = arg0;
13749 }
13750
13751 shellparam.p = xargv;
13752#if ENABLE_ASH_GETOPTS
13753 shellparam.optind = 1;
13754 shellparam.optoff = -1;
13755#endif
Denis Vlasenko01631112007-12-16 17:20:38 +000013756 /* assert(shellparam.malloced == 0 && shellparam.nparam == 0); */
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013757 while (*xargv) {
13758 shellparam.nparam++;
13759 xargv++;
13760 }
13761 optschanged();
Denys Vlasenkoec05df12017-07-31 19:43:47 +020013762
13763 return login_sh;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013764}
13765
13766/*
Denys Vlasenko2eb0a7e2016-10-27 11:28:59 +020013767 * Read /etc/profile, ~/.profile, $ENV.
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013768 */
13769static void
13770read_profile(const char *name)
13771{
Denys Vlasenko46999802017-07-29 21:12:29 +020013772 name = expandstr(name, DQSYNTAX);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013773 if (setinputfile(name, INPUT_PUSH_FILE | INPUT_NOFILE_OK) < 0)
13774 return;
Denys Vlasenko0840c912016-10-01 15:27:44 +020013775 cmdloop(0);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013776 popfile();
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013777}
13778
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013779/*
13780 * This routine is called when an error or an interrupt occurs in an
13781 * interactive shell and control is returned to the main command loop.
Denys Vlasenko5ac04f22016-10-27 14:46:50 +020013782 * (In dash, this function is auto-generated by build machinery).
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013783 */
13784static void
13785reset(void)
13786{
13787 /* from eval.c: */
13788 evalskip = 0;
13789 loopnest = 0;
Denys Vlasenko5ac04f22016-10-27 14:46:50 +020013790
13791 /* from expand.c: */
13792 ifsfree();
13793
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013794 /* from input.c: */
Denis Vlasenko41eb3002008-11-28 03:42:31 +000013795 g_parsefile->left_in_buffer = 0;
13796 g_parsefile->left_in_line = 0; /* clear input buffer */
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013797 popallfiles();
Denys Vlasenko5ac04f22016-10-27 14:46:50 +020013798
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013799 /* from redir.c: */
Denys Vlasenko1c79aeb2017-07-29 22:51:52 +020013800 unwindredir(NULL);
Denys Vlasenkob8ab27b2017-07-26 19:22:34 +020013801
13802 /* from var.c: */
Denys Vlasenko484fc202017-07-26 19:55:31 +020013803 unwindlocalvars(NULL);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013804}
13805
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013806#if PROFILE
13807static short profile_buf[16384];
13808extern int etext();
13809#endif
13810
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013811/*
13812 * Main routine. We initialize things, parse the arguments, execute
13813 * profiles if we're a login shell, and then call cmdloop to execute
13814 * commands. The setjmp call sets up the location to jump to when an
13815 * exception occurs. When an exception occurs the variable "state"
13816 * is used to figure out how far we had gotten.
13817 */
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +000013818int ash_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013819int ash_main(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013820{
Denis Vlasenko4e12b1a2008-12-23 23:36:47 +000013821 volatile smallint state;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013822 struct jmploc jmploc;
13823 struct stackmark smark;
Denys Vlasenkoec05df12017-07-31 19:43:47 +020013824 int login_sh;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013825
Denis Vlasenko01631112007-12-16 17:20:38 +000013826 /* Initialize global data */
13827 INIT_G_misc();
13828 INIT_G_memstack();
13829 INIT_G_var();
Denis Vlasenkoee87ebf2007-12-21 22:18:16 +000013830#if ENABLE_ASH_ALIAS
Denis Vlasenko01631112007-12-16 17:20:38 +000013831 INIT_G_alias();
Denis Vlasenkoee87ebf2007-12-21 22:18:16 +000013832#endif
Denis Vlasenko01631112007-12-16 17:20:38 +000013833 INIT_G_cmdtable();
13834
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013835#if PROFILE
13836 monitor(4, etext, profile_buf, sizeof(profile_buf), 50);
13837#endif
13838
13839#if ENABLE_FEATURE_EDITING
13840 line_input_state = new_line_input_t(FOR_SHELL | WITH_PATH_LOOKUP);
13841#endif
13842 state = 0;
13843 if (setjmp(jmploc.loc)) {
Denis Vlasenko7f88e342009-03-19 03:36:18 +000013844 smallint e;
Denis Vlasenko4e12b1a2008-12-23 23:36:47 +000013845 smallint s;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013846
13847 reset();
13848
Denis Vlasenko7f88e342009-03-19 03:36:18 +000013849 e = exception_type;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013850 s = state;
Denys Vlasenkob563f622010-09-25 17:15:13 +020013851 if (e == EXEXIT || s == 0 || iflag == 0 || shlvl) {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013852 exitshell();
Denys Vlasenkob563f622010-09-25 17:15:13 +020013853 }
13854 if (e == EXINT) {
Denys Vlasenko9c541002015-10-07 15:44:36 +020013855 newline_and_flush(stderr);
Denys Vlasenkob563f622010-09-25 17:15:13 +020013856 }
Denis Vlasenko7f88e342009-03-19 03:36:18 +000013857
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013858 popstackmark(&smark);
13859 FORCE_INT_ON; /* enable interrupts */
13860 if (s == 1)
13861 goto state1;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000013862 if (s == 2)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013863 goto state2;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000013864 if (s == 3)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013865 goto state3;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000013866 goto state4;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013867 }
13868 exception_handler = &jmploc;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013869 rootpid = getpid();
13870
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013871 init();
13872 setstackmark(&smark);
Denys Vlasenkoec05df12017-07-31 19:43:47 +020013873 login_sh = procargs(argv);
Denys Vlasenko474ed062016-10-30 18:30:29 +010013874#if DEBUG
13875 TRACE(("Shell args: "));
13876 trace_puts_args(argv);
13877#endif
Denis Vlasenko68404f12008-03-17 09:00:54 +000013878
Denys Vlasenkoec05df12017-07-31 19:43:47 +020013879 if (login_sh) {
Stefan Hellermann4ef14392013-03-15 02:45:50 +010013880 const char *hp;
13881
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013882 state = 1;
13883 read_profile("/etc/profile");
13884 state1:
13885 state = 2;
Stefan Hellermann4ef14392013-03-15 02:45:50 +010013886 hp = lookupvar("HOME");
Denys Vlasenko2eb0a7e2016-10-27 11:28:59 +020013887 if (hp)
13888 read_profile("$HOME/.profile");
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013889 }
13890 state2:
13891 state = 3;
13892 if (
13893#ifndef linux
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013894 getuid() == geteuid() && getgid() == getegid() &&
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013895#endif
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013896 iflag
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013897 ) {
Denys Vlasenko2eb0a7e2016-10-27 11:28:59 +020013898 const char *shinit = lookupvar("ENV");
13899 if (shinit != NULL && *shinit != '\0')
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013900 read_profile(shinit);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013901 }
Denys Vlasenko2eb0a7e2016-10-27 11:28:59 +020013902 popstackmark(&smark);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013903 state3:
13904 state = 4;
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000013905 if (minusc) {
13906 /* evalstring pushes parsefile stack.
13907 * Ensure we don't falsely claim that 0 (stdin)
Denis Vlasenko5368ad52009-03-20 10:20:08 +000013908 * is one of stacked source fds.
13909 * Testcase: ash -c 'exec 1>&0' must not complain. */
Denys Vlasenko79b3d422010-06-03 04:29:08 +020013910 // if (!sflag) g_parsefile->pf_fd = -1;
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +020013911 // ^^ not necessary since now we special-case fd 0
Denys Vlasenko035486c2017-07-31 04:09:19 +020013912 // in save_fd_on_redirect()
Denys Vlasenko1e3e2cc2017-07-25 20:31:14 +020013913 evalstring(minusc, sflag ? 0 : EV_EXIT);
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000013914 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013915
13916 if (sflag || minusc == NULL) {
Denys Vlasenko4840ae82011-09-04 15:28:03 +020013917#if MAX_HISTORY > 0 && ENABLE_FEATURE_EDITING_SAVEHISTORY
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +000013918 if (iflag) {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013919 const char *hp = lookupvar("HISTFILE");
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010013920 if (!hp) {
13921 hp = lookupvar("HOME");
Stefan Hellermann4ef14392013-03-15 02:45:50 +010013922 if (hp) {
Denys Vlasenko5f7c82b2017-02-03 13:00:06 +010013923 INT_OFF;
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010013924 hp = concat_path_file(hp, ".ash_history");
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020013925 setvar0("HISTFILE", hp);
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010013926 free((char*)hp);
Denys Vlasenko5f7c82b2017-02-03 13:00:06 +010013927 INT_ON;
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010013928 hp = lookupvar("HISTFILE");
13929 }
13930 }
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000013931 if (hp)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013932 line_input_state->hist_file = hp;
Denys Vlasenko2c4de5b2011-03-31 13:16:52 +020013933# if ENABLE_FEATURE_SH_HISTFILESIZE
13934 hp = lookupvar("HISTFILESIZE");
13935 line_input_state->max_history = size_from_HISTFILESIZE(hp);
13936# endif
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013937 }
13938#endif
13939 state4: /* XXX ??? - why isn't this before the "if" statement */
13940 cmdloop(1);
13941 }
13942#if PROFILE
13943 monitor(0);
13944#endif
13945#ifdef GPROF
13946 {
13947 extern void _mcleanup(void);
13948 _mcleanup();
13949 }
13950#endif
Denys Vlasenkob563f622010-09-25 17:15:13 +020013951 TRACE(("End of main reached\n"));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013952 exitshell();
13953 /* NOTREACHED */
13954}
13955
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013956
Eric Andersendf82f612001-06-28 07:46:40 +000013957/*-
13958 * Copyright (c) 1989, 1991, 1993, 1994
Eric Andersen2870d962001-07-02 17:27:21 +000013959 * The Regents of the University of California. All rights reserved.
Eric Andersendf82f612001-06-28 07:46:40 +000013960 *
13961 * This code is derived from software contributed to Berkeley by
13962 * Kenneth Almquist.
13963 *
13964 * Redistribution and use in source and binary forms, with or without
13965 * modification, are permitted provided that the following conditions
13966 * are met:
13967 * 1. Redistributions of source code must retain the above copyright
13968 * notice, this list of conditions and the following disclaimer.
13969 * 2. Redistributions in binary form must reproduce the above copyright
13970 * notice, this list of conditions and the following disclaimer in the
13971 * documentation and/or other materials provided with the distribution.
"Vladimir N. Oleynik"ddc280e2005-12-15 12:01:49 +000013972 * 3. Neither the name of the University nor the names of its contributors
Eric Andersendf82f612001-06-28 07:46:40 +000013973 * may be used to endorse or promote products derived from this software
13974 * without specific prior written permission.
13975 *
Denys Vlasenko95f79532017-08-02 14:26:33 +020013976 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND
Eric Andersendf82f612001-06-28 07:46:40 +000013977 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
13978 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
13979 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
13980 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
13981 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
13982 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
13983 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
13984 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
13985 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
13986 * SUCH DAMAGE.
13987 */