blob: 8c0f3bd8de810bc9e895c648825d7b2a66dc4f23 [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 Vlasenko03c36e02018-01-10 15:18:35 +01001535static ALWAYS_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 */
Denys Vlasenkoa5060b82017-11-03 14:16:25 +01002383#if !ENABLE_FEATURE_SH_NOFORK
2384# define listvars(on, off, lp, end) listvars(on, off, end)
2385#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002386static char **
Denys Vlasenkoa5060b82017-11-03 14:16:25 +01002387listvars(int on, int off, struct strlist *lp, char ***end)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002388{
2389 struct var **vpp;
2390 struct var *vp;
2391 char **ep;
2392 int mask;
2393
2394 STARTSTACKSTR(ep);
2395 vpp = vartab;
2396 mask = on | off;
2397 do {
2398 for (vp = *vpp; vp; vp = vp->next) {
2399 if ((vp->flags & mask) == on) {
Denys Vlasenkoa5060b82017-11-03 14:16:25 +01002400#if ENABLE_FEATURE_SH_NOFORK
2401 /* If variable with the same name is both
2402 * exported and temporarily set for a command:
2403 * export ZVAR=5
2404 * ZVAR=6 printenv
2405 * then "ZVAR=6" will be both in vartab and
2406 * lp lists. Do not pass it twice to printenv.
2407 */
2408 struct strlist *lp1 = lp;
2409 while (lp1) {
2410 if (strcmp(lp1->text, vp->var_text) == 0)
2411 goto skip;
2412 lp1 = lp1->next;
2413 }
2414#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002415 if (ep == stackstrend())
2416 ep = growstackstr();
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002417 *ep++ = (char*)vp->var_text;
Denys Vlasenkoa5060b82017-11-03 14:16:25 +01002418#if ENABLE_FEATURE_SH_NOFORK
2419 skip: ;
2420#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002421 }
2422 }
2423 } while (++vpp < vartab + VTABSIZE);
Denys Vlasenkoa5060b82017-11-03 14:16:25 +01002424
2425#if ENABLE_FEATURE_SH_NOFORK
2426 while (lp) {
2427 if (ep == stackstrend())
2428 ep = growstackstr();
2429 *ep++ = lp->text;
2430 lp = lp->next;
2431 }
2432#endif
2433
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002434 if (ep == stackstrend())
2435 ep = growstackstr();
2436 if (end)
2437 *end = ep;
2438 *ep++ = NULL;
2439 return grabstackstr(ep);
2440}
2441
2442
2443/* ============ Path search helper
2444 *
2445 * The variable path (passed by reference) should be set to the start
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002446 * of the path before the first call; path_advance will update
2447 * this value as it proceeds. Successive calls to path_advance will return
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002448 * the possible path expansions in sequence. If an option (indicated by
2449 * a percent sign) appears in the path entry then the global variable
2450 * pathopt will be set to point to it; otherwise pathopt will be set to
2451 * NULL.
2452 */
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002453static const char *pathopt; /* set by path_advance */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002454
2455static char *
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002456path_advance(const char **path, const char *name)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002457{
2458 const char *p;
2459 char *q;
2460 const char *start;
2461 size_t len;
2462
2463 if (*path == NULL)
2464 return NULL;
2465 start = *path;
Denis Vlasenkof7d56652008-03-25 05:51:41 +00002466 for (p = start; *p && *p != ':' && *p != '%'; p++)
2467 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002468 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
2469 while (stackblocksize() < len)
2470 growstackblock();
2471 q = stackblock();
2472 if (p != start) {
Denys Vlasenko5ace96a2017-07-23 21:46:02 +02002473 q = mempcpy(q, start, p - start);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002474 *q++ = '/';
2475 }
2476 strcpy(q, name);
2477 pathopt = NULL;
2478 if (*p == '%') {
2479 pathopt = ++p;
Denis Vlasenkof7d56652008-03-25 05:51:41 +00002480 while (*p && *p != ':')
2481 p++;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002482 }
2483 if (*p == ':')
2484 *path = p + 1;
2485 else
2486 *path = NULL;
2487 return stalloc(len);
2488}
2489
2490
2491/* ============ Prompt */
2492
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +00002493static smallint doprompt; /* if set, prompt the user */
2494static smallint needprompt; /* true if interactive and at start of line */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002495
2496#if ENABLE_FEATURE_EDITING
2497static line_input_t *line_input_state;
2498static const char *cmdedit_prompt;
2499static void
2500putprompt(const char *s)
2501{
2502 if (ENABLE_ASH_EXPAND_PRMT) {
2503 free((char*)cmdedit_prompt);
Denis Vlasenko4222ae42007-02-25 02:37:49 +00002504 cmdedit_prompt = ckstrdup(s);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002505 return;
2506 }
2507 cmdedit_prompt = s;
2508}
2509#else
2510static void
2511putprompt(const char *s)
2512{
2513 out2str(s);
2514}
2515#endif
2516
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002517/* expandstr() needs parsing machinery, so it is far away ahead... */
Denys Vlasenko46999802017-07-29 21:12:29 +02002518static const char *expandstr(const char *ps, int syntax_type);
2519/* Values for syntax param */
2520#define BASESYNTAX 0 /* not in quotes */
2521#define DQSYNTAX 1 /* in double quotes */
2522#define SQSYNTAX 2 /* in single quotes */
2523#define ARISYNTAX 3 /* in arithmetic */
Denys Vlasenko5f0a75f2017-07-29 22:58:44 +02002524#if ENABLE_ASH_EXPAND_PRMT
2525# define PSSYNTAX 4 /* prompt. never passed to SIT() */
2526#endif
Denys Vlasenko46999802017-07-29 21:12:29 +02002527/* PSSYNTAX expansion is identical to DQSYNTAX, except keeping '\$' as '\$' */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002528
Denys Vlasenko46999802017-07-29 21:12:29 +02002529/*
2530 * called by editline -- any expansions to the prompt should be added here.
2531 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002532static void
Denys Vlasenko958581a2010-09-12 15:04:27 +02002533setprompt_if(smallint do_set, int whichprompt)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002534{
2535 const char *prompt;
Denys Vlasenko958581a2010-09-12 15:04:27 +02002536 IF_ASH_EXPAND_PRMT(struct stackmark smark;)
2537
2538 if (!do_set)
2539 return;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002540
2541 needprompt = 0;
2542
2543 switch (whichprompt) {
2544 case 1:
2545 prompt = ps1val();
2546 break;
2547 case 2:
2548 prompt = ps2val();
2549 break;
2550 default: /* 0 */
2551 prompt = nullstr;
2552 }
2553#if ENABLE_ASH_EXPAND_PRMT
Denys Vlasenko60ca8342016-09-30 11:21:21 +02002554 pushstackmark(&smark, stackblocksize());
Denys Vlasenko46999802017-07-29 21:12:29 +02002555 putprompt(expandstr(prompt, PSSYNTAX));
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002556 popstackmark(&smark);
Denys Vlasenko48c803a2017-07-01 23:24:48 +02002557#else
2558 putprompt(prompt);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002559#endif
2560}
2561
2562
2563/* ============ The cd and pwd commands */
2564
2565#define CD_PHYSICAL 1
2566#define CD_PRINT 2
2567
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002568static int
2569cdopt(void)
2570{
2571 int flags = 0;
2572 int i, j;
2573
2574 j = 'L';
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02002575 while ((i = nextopt("LP")) != '\0') {
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002576 if (i != j) {
2577 flags ^= CD_PHYSICAL;
2578 j = i;
2579 }
2580 }
2581
2582 return flags;
2583}
2584
2585/*
2586 * Update curdir (the name of the current directory) in response to a
2587 * cd command.
2588 */
2589static const char *
2590updatepwd(const char *dir)
2591{
2592 char *new;
2593 char *p;
2594 char *cdcomppath;
2595 const char *lim;
2596
Denys Vlasenko8e2bc472016-09-28 23:02:57 +02002597 cdcomppath = sstrdup(dir);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002598 STARTSTACKSTR(new);
2599 if (*dir != '/') {
2600 if (curdir == nullstr)
2601 return 0;
2602 new = stack_putstr(curdir, new);
2603 }
2604 new = makestrspace(strlen(dir) + 2, new);
Denis Vlasenko29eb3592008-05-18 14:06:08 +00002605 lim = (char *)stackblock() + 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002606 if (*dir != '/') {
2607 if (new[-1] != '/')
2608 USTPUTC('/', new);
2609 if (new > lim && *lim == '/')
2610 lim++;
2611 } else {
2612 USTPUTC('/', new);
2613 cdcomppath++;
2614 if (dir[1] == '/' && dir[2] != '/') {
2615 USTPUTC('/', new);
2616 cdcomppath++;
2617 lim++;
2618 }
2619 }
2620 p = strtok(cdcomppath, "/");
2621 while (p) {
2622 switch (*p) {
2623 case '.':
2624 if (p[1] == '.' && p[2] == '\0') {
2625 while (new > lim) {
2626 STUNPUTC(new);
2627 if (new[-1] == '/')
2628 break;
2629 }
2630 break;
Denis Vlasenko16abcd92007-04-13 23:59:52 +00002631 }
2632 if (p[1] == '\0')
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002633 break;
2634 /* fall through */
2635 default:
2636 new = stack_putstr(p, new);
2637 USTPUTC('/', new);
2638 }
Denys Vlasenko00da72b2015-10-23 18:43:16 +02002639 p = strtok(NULL, "/");
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002640 }
2641 if (new > lim)
2642 STUNPUTC(new);
2643 *new = 0;
2644 return stackblock();
2645}
2646
2647/*
2648 * Find out what the current directory is. If we already know the current
2649 * directory, this routine returns immediately.
2650 */
2651static char *
2652getpwd(void)
2653{
Denis Vlasenko01631112007-12-16 17:20:38 +00002654 char *dir = getcwd(NULL, 0); /* huh, using glibc extension? */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002655 return dir ? dir : nullstr;
2656}
2657
2658static void
2659setpwd(const char *val, int setold)
2660{
2661 char *oldcur, *dir;
2662
2663 oldcur = dir = curdir;
2664
2665 if (setold) {
2666 setvar("OLDPWD", oldcur, VEXPORT);
2667 }
2668 INT_OFF;
2669 if (physdir != nullstr) {
2670 if (physdir != oldcur)
2671 free(physdir);
2672 physdir = nullstr;
2673 }
2674 if (oldcur == val || !val) {
2675 char *s = getpwd();
2676 physdir = s;
2677 if (!val)
2678 dir = s;
2679 } else
2680 dir = ckstrdup(val);
2681 if (oldcur != dir && oldcur != nullstr) {
2682 free(oldcur);
2683 }
2684 curdir = dir;
2685 INT_ON;
2686 setvar("PWD", dir, VEXPORT);
2687}
2688
2689static void hashcd(void);
2690
2691/*
Denys Vlasenko70392332016-10-27 02:31:55 +02002692 * Actually do the chdir. We also call hashcd to let other routines
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002693 * know that the current directory has changed.
2694 */
2695static int
2696docd(const char *dest, int flags)
2697{
Denys Vlasenko4b1100e2010-03-05 14:10:54 +01002698 const char *dir = NULL;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002699 int err;
2700
2701 TRACE(("docd(\"%s\", %d) called\n", dest, flags));
2702
2703 INT_OFF;
2704 if (!(flags & CD_PHYSICAL)) {
2705 dir = updatepwd(dest);
2706 if (dir)
2707 dest = dir;
2708 }
2709 err = chdir(dest);
2710 if (err)
2711 goto out;
2712 setpwd(dir, 1);
2713 hashcd();
2714 out:
2715 INT_ON;
2716 return err;
2717}
2718
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02002719static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00002720cdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002721{
2722 const char *dest;
2723 const char *path;
2724 const char *p;
2725 char c;
2726 struct stat statb;
2727 int flags;
2728
2729 flags = cdopt();
2730 dest = *argptr;
2731 if (!dest)
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02002732 dest = bltinlookup("HOME");
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002733 else if (LONE_DASH(dest)) {
2734 dest = bltinlookup("OLDPWD");
2735 flags |= CD_PRINT;
2736 }
2737 if (!dest)
2738 dest = nullstr;
2739 if (*dest == '/')
Denys Vlasenko0e081d02016-10-26 19:56:05 +02002740 goto step6;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002741 if (*dest == '.') {
2742 c = dest[1];
2743 dotdot:
2744 switch (c) {
2745 case '\0':
2746 case '/':
2747 goto step6;
2748 case '.':
2749 c = dest[2];
2750 if (c != '.')
2751 goto dotdot;
2752 }
2753 }
2754 if (!*dest)
2755 dest = ".";
2756 path = bltinlookup("CDPATH");
Denys Vlasenko0e081d02016-10-26 19:56:05 +02002757 while (path) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002758 c = *path;
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002759 p = path_advance(&path, dest);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002760 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
2761 if (c && c != ':')
2762 flags |= CD_PRINT;
2763 docd:
2764 if (!docd(p, flags))
2765 goto out;
Denys Vlasenko0e081d02016-10-26 19:56:05 +02002766 goto err;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002767 }
Denys Vlasenko0e081d02016-10-26 19:56:05 +02002768 }
2769
2770 step6:
2771 p = dest;
2772 goto docd;
2773
2774 err:
Johannes Schindelin687aac02017-08-22 22:03:22 +02002775 ash_msg_and_raise_perror("can't cd to %s", dest);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002776 /* NOTREACHED */
2777 out:
2778 if (flags & CD_PRINT)
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02002779 out1fmt("%s\n", curdir);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002780 return 0;
2781}
2782
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02002783static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00002784pwdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002785{
2786 int flags;
2787 const char *dir = curdir;
2788
2789 flags = cdopt();
2790 if (flags) {
2791 if (physdir == nullstr)
2792 setpwd(dir, 0);
2793 dir = physdir;
2794 }
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02002795 out1fmt("%s\n", dir);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002796 return 0;
2797}
2798
Denis Vlasenko0c032a42007-02-23 01:03:40 +00002799
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00002800/* ============ ... */
Eric Andersenc470f442003-07-28 09:56:35 +00002801
Denis Vlasenko834dee72008-10-07 09:18:30 +00002802
Denys Vlasenko82dd14a2010-05-17 10:10:01 +02002803#define IBUFSIZ (ENABLE_FEATURE_EDITING ? CONFIG_FEATURE_EDITING_MAX_LEN : 1024)
Eric Andersenc470f442003-07-28 09:56:35 +00002804
Eric Andersenc470f442003-07-28 09:56:35 +00002805/* Syntax classes */
Denis Vlasenko834dee72008-10-07 09:18:30 +00002806#define CWORD 0 /* character is nothing special */
2807#define CNL 1 /* newline character */
2808#define CBACK 2 /* a backslash character */
2809#define CSQUOTE 3 /* single quote */
2810#define CDQUOTE 4 /* double quote */
Eric Andersenc470f442003-07-28 09:56:35 +00002811#define CENDQUOTE 5 /* a terminating quote */
Denis Vlasenko834dee72008-10-07 09:18:30 +00002812#define CBQUOTE 6 /* backwards single quote */
2813#define CVAR 7 /* a dollar sign */
2814#define CENDVAR 8 /* a '}' character */
2815#define CLP 9 /* a left paren in arithmetic */
2816#define CRP 10 /* a right paren in arithmetic */
Eric Andersenc470f442003-07-28 09:56:35 +00002817#define CENDFILE 11 /* end of file */
Denis Vlasenko834dee72008-10-07 09:18:30 +00002818#define CCTL 12 /* like CWORD, except it must be escaped */
2819#define CSPCL 13 /* these terminate a word */
2820#define CIGN 14 /* character should be ignored */
Eric Andersenc470f442003-07-28 09:56:35 +00002821
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002822#define PEOF 256
Denis Vlasenko131ae172007-02-18 13:00:19 +00002823#if ENABLE_ASH_ALIAS
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002824# define PEOA 257
Eric Andersenc470f442003-07-28 09:56:35 +00002825#endif
2826
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002827#define USE_SIT_FUNCTION ENABLE_ASH_OPTIMIZE_FOR_SIZE
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002828
Denys Vlasenko0b883582016-12-23 16:49:07 +01002829#if ENABLE_FEATURE_SH_MATH
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002830# define SIT_ITEM(a,b,c,d) (a | (b << 4) | (c << 8) | (d << 12))
Eric Andersenc470f442003-07-28 09:56:35 +00002831#else
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002832# define SIT_ITEM(a,b,c,d) (a | (b << 4) | (c << 8))
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002833#endif
Denys Vlasenko3e134eb2016-04-22 18:09:21 +02002834static const uint16_t S_I_T[] ALIGN2 = {
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002835#if ENABLE_ASH_ALIAS
2836 SIT_ITEM(CSPCL , CIGN , CIGN , CIGN ), /* 0, PEOA */
2837#endif
2838 SIT_ITEM(CSPCL , CWORD , CWORD, CWORD ), /* 1, ' ' */
2839 SIT_ITEM(CNL , CNL , CNL , CNL ), /* 2, \n */
2840 SIT_ITEM(CWORD , CCTL , CCTL , CWORD ), /* 3, !*-/:=?[]~ */
2841 SIT_ITEM(CDQUOTE , CENDQUOTE, CWORD, CWORD ), /* 4, '"' */
2842 SIT_ITEM(CVAR , CVAR , CWORD, CVAR ), /* 5, $ */
2843 SIT_ITEM(CSQUOTE , CWORD , CENDQUOTE, CWORD), /* 6, "'" */
2844 SIT_ITEM(CSPCL , CWORD , CWORD, CLP ), /* 7, ( */
2845 SIT_ITEM(CSPCL , CWORD , CWORD, CRP ), /* 8, ) */
2846 SIT_ITEM(CBACK , CBACK , CCTL , CBACK ), /* 9, \ */
2847 SIT_ITEM(CBQUOTE , CBQUOTE , CWORD, CBQUOTE), /* 10, ` */
2848 SIT_ITEM(CENDVAR , CENDVAR , CWORD, CENDVAR), /* 11, } */
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002849#if !USE_SIT_FUNCTION
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002850 SIT_ITEM(CENDFILE, CENDFILE , CENDFILE, CENDFILE),/* 12, PEOF */
2851 SIT_ITEM(CWORD , CWORD , CWORD, CWORD ), /* 13, 0-9A-Za-z */
2852 SIT_ITEM(CCTL , CCTL , CCTL , CCTL ) /* 14, CTLESC ... */
2853#endif
2854#undef SIT_ITEM
Eric Andersenc470f442003-07-28 09:56:35 +00002855};
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002856/* Constants below must match table above */
2857enum {
2858#if ENABLE_ASH_ALIAS
2859 CSPCL_CIGN_CIGN_CIGN , /* 0 */
2860#endif
2861 CSPCL_CWORD_CWORD_CWORD , /* 1 */
2862 CNL_CNL_CNL_CNL , /* 2 */
2863 CWORD_CCTL_CCTL_CWORD , /* 3 */
2864 CDQUOTE_CENDQUOTE_CWORD_CWORD , /* 4 */
2865 CVAR_CVAR_CWORD_CVAR , /* 5 */
2866 CSQUOTE_CWORD_CENDQUOTE_CWORD , /* 6 */
2867 CSPCL_CWORD_CWORD_CLP , /* 7 */
2868 CSPCL_CWORD_CWORD_CRP , /* 8 */
2869 CBACK_CBACK_CCTL_CBACK , /* 9 */
2870 CBQUOTE_CBQUOTE_CWORD_CBQUOTE , /* 10 */
2871 CENDVAR_CENDVAR_CWORD_CENDVAR , /* 11 */
2872 CENDFILE_CENDFILE_CENDFILE_CENDFILE, /* 12 */
2873 CWORD_CWORD_CWORD_CWORD , /* 13 */
2874 CCTL_CCTL_CCTL_CCTL , /* 14 */
2875};
Eric Andersen2870d962001-07-02 17:27:21 +00002876
Denys Vlasenkocd716832009-11-28 22:14:02 +01002877/* c in SIT(c, syntax) must be an *unsigned char* or PEOA or PEOF,
2878 * caller must ensure proper cast on it if c is *char_ptr!
2879 */
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002880#if USE_SIT_FUNCTION
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002881
Denis Vlasenko0c032a42007-02-23 01:03:40 +00002882static int
2883SIT(int c, int syntax)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002884{
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02002885 /* Used to also have '/' in this string: "\t\n !\"$&'()*-/:;<=>?[\\]`|}~" */
2886 static const char spec_symbls[] ALIGN1 = "\t\n !\"$&'()*-:;<=>?[\\]`|}~";
2887 /*
2888 * This causes '/' to be prepended with CTLESC in dquoted string,
2889 * making "./file"* treated incorrectly because we feed
2890 * ".\/file*" string to glob(), confusing it (see expandmeta func).
2891 * The "homegrown" glob implementation is okay with that,
2892 * but glibc one isn't. With '/' always treated as CWORD,
2893 * both work fine.
2894 */
Denys Vlasenkocd716832009-11-28 22:14:02 +01002895# if ENABLE_ASH_ALIAS
2896 static const uint8_t syntax_index_table[] ALIGN1 = {
Eric Andersenc470f442003-07-28 09:56:35 +00002897 1, 2, 1, 3, 4, 5, 1, 6, /* "\t\n !\"$&'" */
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02002898 7, 8, 3, 3,/*3,*/3, 1, 1, /* "()*-/:;<" */
Eric Andersenc470f442003-07-28 09:56:35 +00002899 3, 1, 3, 3, 9, 3, 10, 1, /* "=>?[\\]`|" */
2900 11, 3 /* "}~" */
2901 };
Denys Vlasenkocd716832009-11-28 22:14:02 +01002902# else
2903 static const uint8_t syntax_index_table[] ALIGN1 = {
Eric Andersenc470f442003-07-28 09:56:35 +00002904 0, 1, 0, 2, 3, 4, 0, 5, /* "\t\n !\"$&'" */
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02002905 6, 7, 2, 2,/*2,*/2, 0, 0, /* "()*-/:;<" */
Eric Andersenc470f442003-07-28 09:56:35 +00002906 2, 0, 2, 2, 8, 2, 9, 0, /* "=>?[\\]`|" */
2907 10, 2 /* "}~" */
2908 };
Denys Vlasenkocd716832009-11-28 22:14:02 +01002909# endif
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002910 const char *s;
2911 int indx;
2912
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002913 if (c == PEOF)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002914 return CENDFILE;
Denys Vlasenkocd716832009-11-28 22:14:02 +01002915# if ENABLE_ASH_ALIAS
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002916 if (c == PEOA)
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002917 indx = 0;
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002918 else
Denys Vlasenkocd716832009-11-28 22:14:02 +01002919# endif
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002920 {
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002921 /* Cast is purely for paranoia here,
2922 * just in case someone passed signed char to us */
2923 if ((unsigned char)c >= CTL_FIRST
2924 && (unsigned char)c <= CTL_LAST
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002925 ) {
2926 return CCTL;
2927 }
2928 s = strchrnul(spec_symbls, c);
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002929 if (*s == '\0')
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002930 return CWORD;
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002931 indx = syntax_index_table[s - spec_symbls];
2932 }
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002933 return (S_I_T[indx] >> (syntax*4)) & 0xf;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002934}
2935
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00002936#else /* !USE_SIT_FUNCTION */
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002937
Denys Vlasenko3e134eb2016-04-22 18:09:21 +02002938static const uint8_t syntax_index_table[] ALIGN1 = {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002939 /* BASESYNTAX_DQSYNTAX_SQSYNTAX_ARISYNTAX */
Denys Vlasenkocd716832009-11-28 22:14:02 +01002940 /* 0 */ CWORD_CWORD_CWORD_CWORD,
2941 /* 1 */ CWORD_CWORD_CWORD_CWORD,
2942 /* 2 */ CWORD_CWORD_CWORD_CWORD,
2943 /* 3 */ CWORD_CWORD_CWORD_CWORD,
2944 /* 4 */ CWORD_CWORD_CWORD_CWORD,
2945 /* 5 */ CWORD_CWORD_CWORD_CWORD,
2946 /* 6 */ CWORD_CWORD_CWORD_CWORD,
2947 /* 7 */ CWORD_CWORD_CWORD_CWORD,
2948 /* 8 */ CWORD_CWORD_CWORD_CWORD,
2949 /* 9 "\t" */ CSPCL_CWORD_CWORD_CWORD,
2950 /* 10 "\n" */ CNL_CNL_CNL_CNL,
2951 /* 11 */ CWORD_CWORD_CWORD_CWORD,
2952 /* 12 */ CWORD_CWORD_CWORD_CWORD,
2953 /* 13 */ CWORD_CWORD_CWORD_CWORD,
2954 /* 14 */ CWORD_CWORD_CWORD_CWORD,
2955 /* 15 */ CWORD_CWORD_CWORD_CWORD,
2956 /* 16 */ CWORD_CWORD_CWORD_CWORD,
2957 /* 17 */ CWORD_CWORD_CWORD_CWORD,
2958 /* 18 */ CWORD_CWORD_CWORD_CWORD,
2959 /* 19 */ CWORD_CWORD_CWORD_CWORD,
2960 /* 20 */ CWORD_CWORD_CWORD_CWORD,
2961 /* 21 */ CWORD_CWORD_CWORD_CWORD,
2962 /* 22 */ CWORD_CWORD_CWORD_CWORD,
2963 /* 23 */ CWORD_CWORD_CWORD_CWORD,
2964 /* 24 */ CWORD_CWORD_CWORD_CWORD,
2965 /* 25 */ CWORD_CWORD_CWORD_CWORD,
2966 /* 26 */ CWORD_CWORD_CWORD_CWORD,
2967 /* 27 */ CWORD_CWORD_CWORD_CWORD,
2968 /* 28 */ CWORD_CWORD_CWORD_CWORD,
2969 /* 29 */ CWORD_CWORD_CWORD_CWORD,
2970 /* 30 */ CWORD_CWORD_CWORD_CWORD,
2971 /* 31 */ CWORD_CWORD_CWORD_CWORD,
2972 /* 32 " " */ CSPCL_CWORD_CWORD_CWORD,
2973 /* 33 "!" */ CWORD_CCTL_CCTL_CWORD,
2974 /* 34 """ */ CDQUOTE_CENDQUOTE_CWORD_CWORD,
2975 /* 35 "#" */ CWORD_CWORD_CWORD_CWORD,
2976 /* 36 "$" */ CVAR_CVAR_CWORD_CVAR,
2977 /* 37 "%" */ CWORD_CWORD_CWORD_CWORD,
2978 /* 38 "&" */ CSPCL_CWORD_CWORD_CWORD,
2979 /* 39 "'" */ CSQUOTE_CWORD_CENDQUOTE_CWORD,
2980 /* 40 "(" */ CSPCL_CWORD_CWORD_CLP,
2981 /* 41 ")" */ CSPCL_CWORD_CWORD_CRP,
2982 /* 42 "*" */ CWORD_CCTL_CCTL_CWORD,
2983 /* 43 "+" */ CWORD_CWORD_CWORD_CWORD,
2984 /* 44 "," */ CWORD_CWORD_CWORD_CWORD,
2985 /* 45 "-" */ CWORD_CCTL_CCTL_CWORD,
2986 /* 46 "." */ CWORD_CWORD_CWORD_CWORD,
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02002987/* "/" was CWORD_CCTL_CCTL_CWORD, see comment in SIT() function why this is changed: */
2988 /* 47 "/" */ CWORD_CWORD_CWORD_CWORD,
Denys Vlasenkocd716832009-11-28 22:14:02 +01002989 /* 48 "0" */ CWORD_CWORD_CWORD_CWORD,
2990 /* 49 "1" */ CWORD_CWORD_CWORD_CWORD,
2991 /* 50 "2" */ CWORD_CWORD_CWORD_CWORD,
2992 /* 51 "3" */ CWORD_CWORD_CWORD_CWORD,
2993 /* 52 "4" */ CWORD_CWORD_CWORD_CWORD,
2994 /* 53 "5" */ CWORD_CWORD_CWORD_CWORD,
2995 /* 54 "6" */ CWORD_CWORD_CWORD_CWORD,
2996 /* 55 "7" */ CWORD_CWORD_CWORD_CWORD,
2997 /* 56 "8" */ CWORD_CWORD_CWORD_CWORD,
2998 /* 57 "9" */ CWORD_CWORD_CWORD_CWORD,
2999 /* 58 ":" */ CWORD_CCTL_CCTL_CWORD,
3000 /* 59 ";" */ CSPCL_CWORD_CWORD_CWORD,
3001 /* 60 "<" */ CSPCL_CWORD_CWORD_CWORD,
3002 /* 61 "=" */ CWORD_CCTL_CCTL_CWORD,
3003 /* 62 ">" */ CSPCL_CWORD_CWORD_CWORD,
3004 /* 63 "?" */ CWORD_CCTL_CCTL_CWORD,
3005 /* 64 "@" */ CWORD_CWORD_CWORD_CWORD,
3006 /* 65 "A" */ CWORD_CWORD_CWORD_CWORD,
3007 /* 66 "B" */ CWORD_CWORD_CWORD_CWORD,
3008 /* 67 "C" */ CWORD_CWORD_CWORD_CWORD,
3009 /* 68 "D" */ CWORD_CWORD_CWORD_CWORD,
3010 /* 69 "E" */ CWORD_CWORD_CWORD_CWORD,
3011 /* 70 "F" */ CWORD_CWORD_CWORD_CWORD,
3012 /* 71 "G" */ CWORD_CWORD_CWORD_CWORD,
3013 /* 72 "H" */ CWORD_CWORD_CWORD_CWORD,
3014 /* 73 "I" */ CWORD_CWORD_CWORD_CWORD,
3015 /* 74 "J" */ CWORD_CWORD_CWORD_CWORD,
3016 /* 75 "K" */ CWORD_CWORD_CWORD_CWORD,
3017 /* 76 "L" */ CWORD_CWORD_CWORD_CWORD,
3018 /* 77 "M" */ CWORD_CWORD_CWORD_CWORD,
3019 /* 78 "N" */ CWORD_CWORD_CWORD_CWORD,
3020 /* 79 "O" */ CWORD_CWORD_CWORD_CWORD,
3021 /* 80 "P" */ CWORD_CWORD_CWORD_CWORD,
3022 /* 81 "Q" */ CWORD_CWORD_CWORD_CWORD,
3023 /* 82 "R" */ CWORD_CWORD_CWORD_CWORD,
3024 /* 83 "S" */ CWORD_CWORD_CWORD_CWORD,
3025 /* 84 "T" */ CWORD_CWORD_CWORD_CWORD,
3026 /* 85 "U" */ CWORD_CWORD_CWORD_CWORD,
3027 /* 86 "V" */ CWORD_CWORD_CWORD_CWORD,
3028 /* 87 "W" */ CWORD_CWORD_CWORD_CWORD,
3029 /* 88 "X" */ CWORD_CWORD_CWORD_CWORD,
3030 /* 89 "Y" */ CWORD_CWORD_CWORD_CWORD,
3031 /* 90 "Z" */ CWORD_CWORD_CWORD_CWORD,
3032 /* 91 "[" */ CWORD_CCTL_CCTL_CWORD,
3033 /* 92 "\" */ CBACK_CBACK_CCTL_CBACK,
3034 /* 93 "]" */ CWORD_CCTL_CCTL_CWORD,
3035 /* 94 "^" */ CWORD_CWORD_CWORD_CWORD,
3036 /* 95 "_" */ CWORD_CWORD_CWORD_CWORD,
3037 /* 96 "`" */ CBQUOTE_CBQUOTE_CWORD_CBQUOTE,
3038 /* 97 "a" */ CWORD_CWORD_CWORD_CWORD,
3039 /* 98 "b" */ CWORD_CWORD_CWORD_CWORD,
3040 /* 99 "c" */ CWORD_CWORD_CWORD_CWORD,
3041 /* 100 "d" */ CWORD_CWORD_CWORD_CWORD,
3042 /* 101 "e" */ CWORD_CWORD_CWORD_CWORD,
3043 /* 102 "f" */ CWORD_CWORD_CWORD_CWORD,
3044 /* 103 "g" */ CWORD_CWORD_CWORD_CWORD,
3045 /* 104 "h" */ CWORD_CWORD_CWORD_CWORD,
3046 /* 105 "i" */ CWORD_CWORD_CWORD_CWORD,
3047 /* 106 "j" */ CWORD_CWORD_CWORD_CWORD,
3048 /* 107 "k" */ CWORD_CWORD_CWORD_CWORD,
3049 /* 108 "l" */ CWORD_CWORD_CWORD_CWORD,
3050 /* 109 "m" */ CWORD_CWORD_CWORD_CWORD,
3051 /* 110 "n" */ CWORD_CWORD_CWORD_CWORD,
3052 /* 111 "o" */ CWORD_CWORD_CWORD_CWORD,
3053 /* 112 "p" */ CWORD_CWORD_CWORD_CWORD,
3054 /* 113 "q" */ CWORD_CWORD_CWORD_CWORD,
3055 /* 114 "r" */ CWORD_CWORD_CWORD_CWORD,
3056 /* 115 "s" */ CWORD_CWORD_CWORD_CWORD,
3057 /* 116 "t" */ CWORD_CWORD_CWORD_CWORD,
3058 /* 117 "u" */ CWORD_CWORD_CWORD_CWORD,
3059 /* 118 "v" */ CWORD_CWORD_CWORD_CWORD,
3060 /* 119 "w" */ CWORD_CWORD_CWORD_CWORD,
3061 /* 120 "x" */ CWORD_CWORD_CWORD_CWORD,
3062 /* 121 "y" */ CWORD_CWORD_CWORD_CWORD,
3063 /* 122 "z" */ CWORD_CWORD_CWORD_CWORD,
3064 /* 123 "{" */ CWORD_CWORD_CWORD_CWORD,
3065 /* 124 "|" */ CSPCL_CWORD_CWORD_CWORD,
3066 /* 125 "}" */ CENDVAR_CENDVAR_CWORD_CENDVAR,
3067 /* 126 "~" */ CWORD_CCTL_CCTL_CWORD,
3068 /* 127 del */ CWORD_CWORD_CWORD_CWORD,
3069 /* 128 0x80 */ CWORD_CWORD_CWORD_CWORD,
3070 /* 129 CTLESC */ CCTL_CCTL_CCTL_CCTL,
3071 /* 130 CTLVAR */ CCTL_CCTL_CCTL_CCTL,
3072 /* 131 CTLENDVAR */ CCTL_CCTL_CCTL_CCTL,
3073 /* 132 CTLBACKQ */ CCTL_CCTL_CCTL_CCTL,
3074 /* 133 CTLQUOTE */ CCTL_CCTL_CCTL_CCTL,
3075 /* 134 CTLARI */ CCTL_CCTL_CCTL_CCTL,
3076 /* 135 CTLENDARI */ CCTL_CCTL_CCTL_CCTL,
3077 /* 136 CTLQUOTEMARK */ CCTL_CCTL_CCTL_CCTL,
3078 /* 137 */ CWORD_CWORD_CWORD_CWORD,
3079 /* 138 */ CWORD_CWORD_CWORD_CWORD,
3080 /* 139 */ CWORD_CWORD_CWORD_CWORD,
3081 /* 140 */ CWORD_CWORD_CWORD_CWORD,
3082 /* 141 */ CWORD_CWORD_CWORD_CWORD,
3083 /* 142 */ CWORD_CWORD_CWORD_CWORD,
3084 /* 143 */ CWORD_CWORD_CWORD_CWORD,
3085 /* 144 */ CWORD_CWORD_CWORD_CWORD,
3086 /* 145 */ CWORD_CWORD_CWORD_CWORD,
3087 /* 146 */ CWORD_CWORD_CWORD_CWORD,
3088 /* 147 */ CWORD_CWORD_CWORD_CWORD,
3089 /* 148 */ CWORD_CWORD_CWORD_CWORD,
3090 /* 149 */ CWORD_CWORD_CWORD_CWORD,
3091 /* 150 */ CWORD_CWORD_CWORD_CWORD,
3092 /* 151 */ CWORD_CWORD_CWORD_CWORD,
3093 /* 152 */ CWORD_CWORD_CWORD_CWORD,
3094 /* 153 */ CWORD_CWORD_CWORD_CWORD,
3095 /* 154 */ CWORD_CWORD_CWORD_CWORD,
3096 /* 155 */ CWORD_CWORD_CWORD_CWORD,
3097 /* 156 */ CWORD_CWORD_CWORD_CWORD,
3098 /* 157 */ CWORD_CWORD_CWORD_CWORD,
3099 /* 158 */ CWORD_CWORD_CWORD_CWORD,
3100 /* 159 */ CWORD_CWORD_CWORD_CWORD,
3101 /* 160 */ CWORD_CWORD_CWORD_CWORD,
3102 /* 161 */ CWORD_CWORD_CWORD_CWORD,
3103 /* 162 */ CWORD_CWORD_CWORD_CWORD,
3104 /* 163 */ CWORD_CWORD_CWORD_CWORD,
3105 /* 164 */ CWORD_CWORD_CWORD_CWORD,
3106 /* 165 */ CWORD_CWORD_CWORD_CWORD,
3107 /* 166 */ CWORD_CWORD_CWORD_CWORD,
3108 /* 167 */ CWORD_CWORD_CWORD_CWORD,
3109 /* 168 */ CWORD_CWORD_CWORD_CWORD,
3110 /* 169 */ CWORD_CWORD_CWORD_CWORD,
3111 /* 170 */ CWORD_CWORD_CWORD_CWORD,
3112 /* 171 */ CWORD_CWORD_CWORD_CWORD,
3113 /* 172 */ CWORD_CWORD_CWORD_CWORD,
3114 /* 173 */ CWORD_CWORD_CWORD_CWORD,
3115 /* 174 */ CWORD_CWORD_CWORD_CWORD,
3116 /* 175 */ CWORD_CWORD_CWORD_CWORD,
3117 /* 176 */ CWORD_CWORD_CWORD_CWORD,
3118 /* 177 */ CWORD_CWORD_CWORD_CWORD,
3119 /* 178 */ CWORD_CWORD_CWORD_CWORD,
3120 /* 179 */ CWORD_CWORD_CWORD_CWORD,
3121 /* 180 */ CWORD_CWORD_CWORD_CWORD,
3122 /* 181 */ CWORD_CWORD_CWORD_CWORD,
3123 /* 182 */ CWORD_CWORD_CWORD_CWORD,
3124 /* 183 */ CWORD_CWORD_CWORD_CWORD,
3125 /* 184 */ CWORD_CWORD_CWORD_CWORD,
3126 /* 185 */ CWORD_CWORD_CWORD_CWORD,
3127 /* 186 */ CWORD_CWORD_CWORD_CWORD,
3128 /* 187 */ CWORD_CWORD_CWORD_CWORD,
3129 /* 188 */ CWORD_CWORD_CWORD_CWORD,
3130 /* 189 */ CWORD_CWORD_CWORD_CWORD,
3131 /* 190 */ CWORD_CWORD_CWORD_CWORD,
3132 /* 191 */ CWORD_CWORD_CWORD_CWORD,
3133 /* 192 */ CWORD_CWORD_CWORD_CWORD,
3134 /* 193 */ CWORD_CWORD_CWORD_CWORD,
3135 /* 194 */ CWORD_CWORD_CWORD_CWORD,
3136 /* 195 */ CWORD_CWORD_CWORD_CWORD,
3137 /* 196 */ CWORD_CWORD_CWORD_CWORD,
3138 /* 197 */ CWORD_CWORD_CWORD_CWORD,
3139 /* 198 */ CWORD_CWORD_CWORD_CWORD,
3140 /* 199 */ CWORD_CWORD_CWORD_CWORD,
3141 /* 200 */ CWORD_CWORD_CWORD_CWORD,
3142 /* 201 */ CWORD_CWORD_CWORD_CWORD,
3143 /* 202 */ CWORD_CWORD_CWORD_CWORD,
3144 /* 203 */ CWORD_CWORD_CWORD_CWORD,
3145 /* 204 */ CWORD_CWORD_CWORD_CWORD,
3146 /* 205 */ CWORD_CWORD_CWORD_CWORD,
3147 /* 206 */ CWORD_CWORD_CWORD_CWORD,
3148 /* 207 */ CWORD_CWORD_CWORD_CWORD,
3149 /* 208 */ CWORD_CWORD_CWORD_CWORD,
3150 /* 209 */ CWORD_CWORD_CWORD_CWORD,
3151 /* 210 */ CWORD_CWORD_CWORD_CWORD,
3152 /* 211 */ CWORD_CWORD_CWORD_CWORD,
3153 /* 212 */ CWORD_CWORD_CWORD_CWORD,
3154 /* 213 */ CWORD_CWORD_CWORD_CWORD,
3155 /* 214 */ CWORD_CWORD_CWORD_CWORD,
3156 /* 215 */ CWORD_CWORD_CWORD_CWORD,
3157 /* 216 */ CWORD_CWORD_CWORD_CWORD,
3158 /* 217 */ CWORD_CWORD_CWORD_CWORD,
3159 /* 218 */ CWORD_CWORD_CWORD_CWORD,
3160 /* 219 */ CWORD_CWORD_CWORD_CWORD,
3161 /* 220 */ CWORD_CWORD_CWORD_CWORD,
3162 /* 221 */ CWORD_CWORD_CWORD_CWORD,
3163 /* 222 */ CWORD_CWORD_CWORD_CWORD,
3164 /* 223 */ CWORD_CWORD_CWORD_CWORD,
3165 /* 224 */ CWORD_CWORD_CWORD_CWORD,
3166 /* 225 */ CWORD_CWORD_CWORD_CWORD,
3167 /* 226 */ CWORD_CWORD_CWORD_CWORD,
3168 /* 227 */ CWORD_CWORD_CWORD_CWORD,
3169 /* 228 */ CWORD_CWORD_CWORD_CWORD,
3170 /* 229 */ CWORD_CWORD_CWORD_CWORD,
3171 /* 230 */ CWORD_CWORD_CWORD_CWORD,
3172 /* 231 */ CWORD_CWORD_CWORD_CWORD,
3173 /* 232 */ CWORD_CWORD_CWORD_CWORD,
3174 /* 233 */ CWORD_CWORD_CWORD_CWORD,
3175 /* 234 */ CWORD_CWORD_CWORD_CWORD,
3176 /* 235 */ CWORD_CWORD_CWORD_CWORD,
3177 /* 236 */ CWORD_CWORD_CWORD_CWORD,
3178 /* 237 */ CWORD_CWORD_CWORD_CWORD,
3179 /* 238 */ CWORD_CWORD_CWORD_CWORD,
3180 /* 239 */ CWORD_CWORD_CWORD_CWORD,
3181 /* 230 */ CWORD_CWORD_CWORD_CWORD,
3182 /* 241 */ CWORD_CWORD_CWORD_CWORD,
3183 /* 242 */ CWORD_CWORD_CWORD_CWORD,
3184 /* 243 */ CWORD_CWORD_CWORD_CWORD,
3185 /* 244 */ CWORD_CWORD_CWORD_CWORD,
3186 /* 245 */ CWORD_CWORD_CWORD_CWORD,
3187 /* 246 */ CWORD_CWORD_CWORD_CWORD,
3188 /* 247 */ CWORD_CWORD_CWORD_CWORD,
3189 /* 248 */ CWORD_CWORD_CWORD_CWORD,
3190 /* 249 */ CWORD_CWORD_CWORD_CWORD,
3191 /* 250 */ CWORD_CWORD_CWORD_CWORD,
3192 /* 251 */ CWORD_CWORD_CWORD_CWORD,
3193 /* 252 */ CWORD_CWORD_CWORD_CWORD,
3194 /* 253 */ CWORD_CWORD_CWORD_CWORD,
3195 /* 254 */ CWORD_CWORD_CWORD_CWORD,
3196 /* 255 */ CWORD_CWORD_CWORD_CWORD,
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01003197 /* PEOF */ CENDFILE_CENDFILE_CENDFILE_CENDFILE,
Denys Vlasenkocd716832009-11-28 22:14:02 +01003198# if ENABLE_ASH_ALIAS
3199 /* PEOA */ CSPCL_CIGN_CIGN_CIGN,
3200# endif
Eric Andersen2870d962001-07-02 17:27:21 +00003201};
3202
Denys Vlasenko2fe66b12016-12-12 17:39:12 +01003203#if 1
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01003204# define SIT(c, syntax) ((S_I_T[syntax_index_table[c]] >> ((syntax)*4)) & 0xf)
Denys Vlasenko2fe66b12016-12-12 17:39:12 +01003205#else /* debug version, caught one signed char bug */
3206# define SIT(c, syntax) \
3207 ({ \
3208 if ((c) < 0 || (c) > (PEOF + ENABLE_ASH_ALIAS)) \
3209 bb_error_msg_and_die("line:%d c:%d", __LINE__, (c)); \
Denys Vlasenko0b883582016-12-23 16:49:07 +01003210 if ((syntax) < 0 || (syntax) > (2 + ENABLE_FEATURE_SH_MATH)) \
Denys Vlasenko2fe66b12016-12-12 17:39:12 +01003211 bb_error_msg_and_die("line:%d c:%d", __LINE__, (c)); \
3212 ((S_I_T[syntax_index_table[c]] >> ((syntax)*4)) & 0xf); \
3213 })
3214#endif
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00003215
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01003216#endif /* !USE_SIT_FUNCTION */
Eric Andersenc470f442003-07-28 09:56:35 +00003217
Eric Andersen2870d962001-07-02 17:27:21 +00003218
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00003219/* ============ Alias handling */
Denis Vlasenkofc06f292007-02-23 21:09:35 +00003220
Denis Vlasenko131ae172007-02-18 13:00:19 +00003221#if ENABLE_ASH_ALIAS
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00003222
3223#define ALIASINUSE 1
3224#define ALIASDEAD 2
3225
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00003226struct alias {
3227 struct alias *next;
3228 char *name;
3229 char *val;
3230 int flag;
3231};
3232
Denis Vlasenko01631112007-12-16 17:20:38 +00003233
3234static struct alias **atab; // [ATABSIZE];
3235#define INIT_G_alias() do { \
3236 atab = xzalloc(ATABSIZE * sizeof(atab[0])); \
3237} while (0)
3238
Eric Andersen2870d962001-07-02 17:27:21 +00003239
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00003240static struct alias **
Denys Vlasenko37dc08b2016-10-02 04:38:07 +02003241__lookupalias(const char *name)
3242{
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00003243 unsigned int hashval;
3244 struct alias **app;
3245 const char *p;
3246 unsigned int ch;
3247
3248 p = name;
3249
3250 ch = (unsigned char)*p;
3251 hashval = ch << 4;
3252 while (ch) {
3253 hashval += ch;
3254 ch = (unsigned char)*++p;
3255 }
3256 app = &atab[hashval % ATABSIZE];
3257
3258 for (; *app; app = &(*app)->next) {
3259 if (strcmp(name, (*app)->name) == 0) {
3260 break;
3261 }
3262 }
3263
3264 return app;
3265}
3266
3267static struct alias *
3268lookupalias(const char *name, int check)
3269{
3270 struct alias *ap = *__lookupalias(name);
3271
3272 if (check && ap && (ap->flag & ALIASINUSE))
3273 return NULL;
3274 return ap;
3275}
3276
3277static struct alias *
3278freealias(struct alias *ap)
3279{
3280 struct alias *next;
3281
3282 if (ap->flag & ALIASINUSE) {
3283 ap->flag |= ALIASDEAD;
3284 return ap;
3285 }
3286
3287 next = ap->next;
3288 free(ap->name);
3289 free(ap->val);
3290 free(ap);
3291 return next;
3292}
Eric Andersencb57d552001-06-28 07:25:16 +00003293
Eric Andersenc470f442003-07-28 09:56:35 +00003294static void
3295setalias(const char *name, const char *val)
Eric Andersencb57d552001-06-28 07:25:16 +00003296{
3297 struct alias *ap, **app;
3298
3299 app = __lookupalias(name);
3300 ap = *app;
Denis Vlasenkob012b102007-02-19 22:43:01 +00003301 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +00003302 if (ap) {
3303 if (!(ap->flag & ALIASINUSE)) {
Denis Vlasenkob012b102007-02-19 22:43:01 +00003304 free(ap->val);
Eric Andersencb57d552001-06-28 07:25:16 +00003305 }
Denis Vlasenko0c032a42007-02-23 01:03:40 +00003306 ap->val = ckstrdup(val);
Eric Andersencb57d552001-06-28 07:25:16 +00003307 ap->flag &= ~ALIASDEAD;
3308 } else {
3309 /* not found */
Denis Vlasenko597906c2008-02-20 16:38:54 +00003310 ap = ckzalloc(sizeof(struct alias));
Denis Vlasenko0c032a42007-02-23 01:03:40 +00003311 ap->name = ckstrdup(name);
3312 ap->val = ckstrdup(val);
Denis Vlasenko597906c2008-02-20 16:38:54 +00003313 /*ap->flag = 0; - ckzalloc did it */
3314 /*ap->next = NULL;*/
Eric Andersencb57d552001-06-28 07:25:16 +00003315 *app = ap;
3316 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00003317 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +00003318}
3319
Eric Andersenc470f442003-07-28 09:56:35 +00003320static int
3321unalias(const char *name)
Eric Andersen2870d962001-07-02 17:27:21 +00003322{
Eric Andersencb57d552001-06-28 07:25:16 +00003323 struct alias **app;
3324
3325 app = __lookupalias(name);
3326
3327 if (*app) {
Denis Vlasenkob012b102007-02-19 22:43:01 +00003328 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +00003329 *app = freealias(*app);
Denis Vlasenkob012b102007-02-19 22:43:01 +00003330 INT_ON;
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003331 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003332 }
3333
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003334 return 1;
Eric Andersencb57d552001-06-28 07:25:16 +00003335}
3336
Eric Andersenc470f442003-07-28 09:56:35 +00003337static void
3338rmaliases(void)
Eric Andersen2870d962001-07-02 17:27:21 +00003339{
Eric Andersencb57d552001-06-28 07:25:16 +00003340 struct alias *ap, **app;
3341 int i;
3342
Denis Vlasenkob012b102007-02-19 22:43:01 +00003343 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +00003344 for (i = 0; i < ATABSIZE; i++) {
3345 app = &atab[i];
3346 for (ap = *app; ap; ap = *app) {
3347 *app = freealias(*app);
3348 if (ap == *app) {
3349 app = &ap->next;
3350 }
3351 }
3352 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00003353 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +00003354}
3355
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00003356static void
3357printalias(const struct alias *ap)
3358{
3359 out1fmt("%s=%s\n", ap->name, single_quote(ap->val));
3360}
3361
Eric Andersencb57d552001-06-28 07:25:16 +00003362/*
3363 * TODO - sort output
3364 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02003365static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003366aliascmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003367{
3368 char *n, *v;
3369 int ret = 0;
3370 struct alias *ap;
3371
Denis Vlasenko68404f12008-03-17 09:00:54 +00003372 if (!argv[1]) {
Eric Andersencb57d552001-06-28 07:25:16 +00003373 int i;
3374
Denis Vlasenko68404f12008-03-17 09:00:54 +00003375 for (i = 0; i < ATABSIZE; i++) {
Eric Andersencb57d552001-06-28 07:25:16 +00003376 for (ap = atab[i]; ap; ap = ap->next) {
3377 printalias(ap);
3378 }
Denis Vlasenko68404f12008-03-17 09:00:54 +00003379 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003380 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003381 }
3382 while ((n = *++argv) != NULL) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +00003383 v = strchr(n+1, '=');
3384 if (v == NULL) { /* n+1: funny ksh stuff */
3385 ap = *__lookupalias(n);
3386 if (ap == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00003387 fprintf(stderr, "%s: %s not found\n", "alias", n);
Eric Andersencb57d552001-06-28 07:25:16 +00003388 ret = 1;
3389 } else
3390 printalias(ap);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003391 } else {
Eric Andersencb57d552001-06-28 07:25:16 +00003392 *v++ = '\0';
3393 setalias(n, v);
3394 }
3395 }
3396
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003397 return ret;
Eric Andersencb57d552001-06-28 07:25:16 +00003398}
3399
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02003400static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003401unaliascmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +00003402{
3403 int i;
3404
Denys Vlasenko6c149f42017-04-12 21:31:32 +02003405 while (nextopt("a") != '\0') {
3406 rmaliases();
3407 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003408 }
3409 for (i = 0; *argptr; argptr++) {
3410 if (unalias(*argptr)) {
Eric Andersenc470f442003-07-28 09:56:35 +00003411 fprintf(stderr, "%s: %s not found\n", "unalias", *argptr);
Eric Andersencb57d552001-06-28 07:25:16 +00003412 i = 1;
3413 }
3414 }
3415
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003416 return i;
Eric Andersencb57d552001-06-28 07:25:16 +00003417}
Denis Vlasenkofc06f292007-02-23 21:09:35 +00003418
Denis Vlasenko131ae172007-02-18 13:00:19 +00003419#endif /* ASH_ALIAS */
Eric Andersencb57d552001-06-28 07:25:16 +00003420
Eric Andersenc470f442003-07-28 09:56:35 +00003421
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003422/* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */
Denys Vlasenko285ad152009-12-04 23:02:27 +01003423#define FORK_FG 0
3424#define FORK_BG 1
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003425#define FORK_NOJOB 2
3426
3427/* mode flags for showjob(s) */
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02003428#define SHOW_ONLY_PGID 0x01 /* show only pgid (jobs -p) */
3429#define SHOW_PIDS 0x02 /* show individual pids, not just one line per job */
3430#define SHOW_CHANGED 0x04 /* only jobs whose state has changed */
Denys Vlasenko9c541002015-10-07 15:44:36 +02003431#define SHOW_STDERR 0x08 /* print to stderr (else stdout) */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003432
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003433/*
3434 * A job structure contains information about a job. A job is either a
3435 * single process or a set of processes contained in a pipeline. In the
3436 * latter case, pidlist will be non-NULL, and will point to a -1 terminated
3437 * array of pids.
3438 */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003439struct procstat {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003440 pid_t ps_pid; /* process id */
3441 int ps_status; /* last process status from wait() */
3442 char *ps_cmd; /* text of command being run */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003443};
3444
3445struct job {
3446 struct procstat ps0; /* status of process */
3447 struct procstat *ps; /* status or processes when more than one */
3448#if JOBS
3449 int stopstatus; /* status of a stopped job */
3450#endif
Denys Vlasenko4c179372017-01-11 18:44:15 +01003451 unsigned nprocs; /* number of processes */
3452
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003453#define JOBRUNNING 0 /* at least one proc running */
3454#define JOBSTOPPED 1 /* all procs are stopped */
3455#define JOBDONE 2 /* all procs are completed */
Denys Vlasenko4c179372017-01-11 18:44:15 +01003456 unsigned
3457 state: 8,
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003458#if JOBS
3459 sigint: 1, /* job was killed by SIGINT */
3460 jobctl: 1, /* job running under job control */
3461#endif
3462 waited: 1, /* true if this entry has been waited for */
3463 used: 1, /* true if this entry is in used */
3464 changed: 1; /* true if status has changed */
3465 struct job *prev_job; /* previous job */
3466};
3467
Denis Vlasenko68404f12008-03-17 09:00:54 +00003468static struct job *makejob(/*union node *,*/ int);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003469static int forkshell(struct job *, union node *, int);
3470static int waitforjob(struct job *);
3471
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00003472#if !JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +00003473enum { doing_jobctl = 0 };
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00003474#define setjobctl(on) do {} while (0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003475#else
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003476static smallint doing_jobctl; //references:8
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003477static void setjobctl(int);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003478#endif
3479
3480/*
Denis Vlasenko4b875702009-03-19 13:30:04 +00003481 * Ignore a signal.
3482 */
3483static void
3484ignoresig(int signo)
3485{
3486 /* Avoid unnecessary system calls. Is it already SIG_IGNed? */
3487 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
3488 /* No, need to do it */
3489 signal(signo, SIG_IGN);
3490 }
3491 sigmode[signo - 1] = S_HARD_IGN;
3492}
3493
3494/*
Denys Vlasenko238bf182010-05-18 15:49:07 +02003495 * Only one usage site - in setsignal()
Denis Vlasenko4b875702009-03-19 13:30:04 +00003496 */
3497static void
Denys Vlasenko238bf182010-05-18 15:49:07 +02003498signal_handler(int signo)
Denis Vlasenko4b875702009-03-19 13:30:04 +00003499{
Denys Vlasenko458c1f22016-10-27 23:51:19 +02003500 if (signo == SIGCHLD) {
3501 got_sigchld = 1;
3502 if (!trap[SIGCHLD])
3503 return;
3504 }
3505
Denis Vlasenko4b875702009-03-19 13:30:04 +00003506 gotsig[signo - 1] = 1;
Denys Vlasenko458c1f22016-10-27 23:51:19 +02003507 pending_sig = signo;
Denis Vlasenko4b875702009-03-19 13:30:04 +00003508
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02003509 if (signo == SIGINT && !trap[SIGINT]) {
3510 if (!suppress_int) {
3511 pending_sig = 0;
Denis Vlasenko4b875702009-03-19 13:30:04 +00003512 raise_interrupt(); /* does not return */
3513 }
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02003514 pending_int = 1;
Denis Vlasenko4b875702009-03-19 13:30:04 +00003515 }
3516}
3517
3518/*
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003519 * Set the signal handler for the specified signal. The routine figures
3520 * out what it should be set to.
3521 */
3522static void
3523setsignal(int signo)
3524{
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003525 char *t;
3526 char cur_act, new_act;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003527 struct sigaction act;
3528
3529 t = trap[signo];
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003530 new_act = S_DFL;
3531 if (t != NULL) { /* trap for this sig is set */
3532 new_act = S_CATCH;
3533 if (t[0] == '\0') /* trap is "": ignore this sig */
3534 new_act = S_IGN;
3535 }
3536
3537 if (rootshell && new_act == S_DFL) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003538 switch (signo) {
3539 case SIGINT:
3540 if (iflag || minusc || sflag == 0)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003541 new_act = S_CATCH;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003542 break;
3543 case SIGQUIT:
3544#if DEBUG
3545 if (debug)
3546 break;
3547#endif
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003548 /* man bash:
3549 * "In all cases, bash ignores SIGQUIT. Non-builtin
3550 * commands run by bash have signal handlers
3551 * set to the values inherited by the shell
3552 * from its parent". */
3553 new_act = S_IGN;
3554 break;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003555 case SIGTERM:
3556 if (iflag)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003557 new_act = S_IGN;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003558 break;
3559#if JOBS
3560 case SIGTSTP:
3561 case SIGTTOU:
3562 if (mflag)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003563 new_act = S_IGN;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003564 break;
3565#endif
3566 }
3567 }
Denys Vlasenko49e6bf22017-08-04 14:28:16 +02003568 /* if !rootshell, we reset SIGQUIT to DFL,
3569 * whereas we have to restore it to what shell got on entry.
3570 * This is handled by the fact that if signal was IGNored on entry,
3571 * then cur_act is S_HARD_IGN and we never change its sigaction
3572 * (see code below).
3573 */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003574
Denys Vlasenko458c1f22016-10-27 23:51:19 +02003575 if (signo == SIGCHLD)
3576 new_act = S_CATCH;
3577
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003578 t = &sigmode[signo - 1];
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003579 cur_act = *t;
3580 if (cur_act == 0) {
3581 /* current setting is not yet known */
3582 if (sigaction(signo, NULL, &act)) {
3583 /* pretend it worked; maybe we should give a warning,
3584 * but other shells don't. We don't alter sigmode,
3585 * so we retry every time.
3586 * btw, in Linux it never fails. --vda */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003587 return;
3588 }
3589 if (act.sa_handler == SIG_IGN) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003590 cur_act = S_HARD_IGN;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003591 if (mflag
3592 && (signo == SIGTSTP || signo == SIGTTIN || signo == SIGTTOU)
3593 ) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003594 cur_act = S_IGN; /* don't hard ignore these */
Denis Vlasenko991a1da2008-02-10 19:02:53 +00003595 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003596 }
Denys Vlasenko0f14f412017-08-06 20:06:19 +02003597 if (act.sa_handler == SIG_DFL && new_act == S_DFL) {
3598 /* installing SIG_DFL over SIG_DFL is a no-op */
3599 /* saves one sigaction call in each "sh -c SCRIPT" invocation */
3600 *t = S_DFL;
3601 return;
3602 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003603 }
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003604 if (cur_act == S_HARD_IGN || cur_act == new_act)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003605 return;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003606
Denys Vlasenko49e6bf22017-08-04 14:28:16 +02003607 *t = new_act;
3608
Denis Vlasenko991a1da2008-02-10 19:02:53 +00003609 act.sa_handler = SIG_DFL;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003610 switch (new_act) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003611 case S_CATCH:
Denys Vlasenko238bf182010-05-18 15:49:07 +02003612 act.sa_handler = signal_handler;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003613 break;
3614 case S_IGN:
3615 act.sa_handler = SIG_IGN;
3616 break;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003617 }
Ian Wienand89b3cba2011-04-16 20:05:14 +02003618 /* flags and mask matter only if !DFL and !IGN, but we do it
3619 * for all cases for more deterministic behavior:
3620 */
Denys Vlasenko49e6bf22017-08-04 14:28:16 +02003621 act.sa_flags = 0; //TODO: why not SA_RESTART?
Ian Wienand89b3cba2011-04-16 20:05:14 +02003622 sigfillset(&act.sa_mask);
3623
Denis Vlasenko8e2cfec2008-03-12 23:19:35 +00003624 sigaction_set(signo, &act);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003625}
3626
3627/* mode flags for set_curjob */
3628#define CUR_DELETE 2
3629#define CUR_RUNNING 1
3630#define CUR_STOPPED 0
3631
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003632#if JOBS
3633/* pgrp of shell on invocation */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003634static int initialpgrp; //references:2
3635static int ttyfd = -1; //5
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003636#endif
3637/* array of jobs */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003638static struct job *jobtab; //5
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003639/* size of array */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003640static unsigned njobs; //4
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003641/* current job */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003642static struct job *curjob; //lots
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003643/* number of presumed living untracked jobs */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003644static int jobless; //4
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003645
Denys Vlasenko098b7132017-01-11 19:59:03 +01003646#if 0
3647/* Bash has a feature: it restores termios after a successful wait for
3648 * a foreground job which had at least one stopped or sigkilled member.
3649 * The probable rationale is that SIGSTOP and SIGKILL can preclude task from
3650 * properly restoring tty state. Should we do this too?
3651 * A reproducer: ^Z an interactive python:
3652 *
3653 * # python
3654 * Python 2.7.12 (...)
3655 * >>> ^Z
3656 * { python leaves tty in -icanon -echo state. We do survive that... }
3657 * [1]+ Stopped python
3658 * { ...however, next program (python #2) does not survive it well: }
3659 * # python
3660 * Python 2.7.12 (...)
3661 * >>> Traceback (most recent call last):
3662 * { above, I typed "qwerty<CR>", but -echo state is still in effect }
3663 * File "<stdin>", line 1, in <module>
3664 * NameError: name 'qwerty' is not defined
3665 *
3666 * The implementation below is modeled on bash code and seems to work.
3667 * However, I'm not sure we should do this. For one: what if I'd fg
3668 * the stopped python instead? It'll be confused by "restored" tty state.
3669 */
3670static struct termios shell_tty_info;
3671static void
3672get_tty_state(void)
3673{
3674 if (rootshell && ttyfd >= 0)
3675 tcgetattr(ttyfd, &shell_tty_info);
3676}
3677static void
3678set_tty_state(void)
3679{
3680 /* if (rootshell) - caller ensures this */
3681 if (ttyfd >= 0)
3682 tcsetattr(ttyfd, TCSADRAIN, &shell_tty_info);
3683}
3684static int
3685job_signal_status(struct job *jp)
3686{
3687 int status;
3688 unsigned i;
3689 struct procstat *ps = jp->ps;
3690 for (i = 0; i < jp->nprocs; i++) {
3691 status = ps[i].ps_status;
3692 if (WIFSIGNALED(status) || WIFSTOPPED(status))
3693 return status;
3694 }
3695 return 0;
3696}
3697static void
3698restore_tty_if_stopped_or_signaled(struct job *jp)
3699{
3700//TODO: check what happens if we come from waitforjob() in expbackq()
3701 if (rootshell) {
3702 int s = job_signal_status(jp);
3703 if (s) /* WIFSIGNALED(s) || WIFSTOPPED(s) */
3704 set_tty_state();
3705 }
3706}
3707#else
3708# define get_tty_state() ((void)0)
3709# define restore_tty_if_stopped_or_signaled(jp) ((void)0)
3710#endif
3711
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003712static void
3713set_curjob(struct job *jp, unsigned mode)
3714{
3715 struct job *jp1;
3716 struct job **jpp, **curp;
3717
3718 /* first remove from list */
3719 jpp = curp = &curjob;
Denys Vlasenko940c7202011-03-02 04:07:14 +01003720 while (1) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003721 jp1 = *jpp;
3722 if (jp1 == jp)
3723 break;
3724 jpp = &jp1->prev_job;
Denys Vlasenko940c7202011-03-02 04:07:14 +01003725 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003726 *jpp = jp1->prev_job;
3727
3728 /* Then re-insert in correct position */
3729 jpp = curp;
3730 switch (mode) {
3731 default:
3732#if DEBUG
3733 abort();
3734#endif
3735 case CUR_DELETE:
3736 /* job being deleted */
3737 break;
3738 case CUR_RUNNING:
3739 /* newly created job or backgrounded job,
Denys Vlasenko60cb48c2013-01-14 15:57:44 +01003740 * put after all stopped jobs.
3741 */
Denys Vlasenko940c7202011-03-02 04:07:14 +01003742 while (1) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003743 jp1 = *jpp;
3744#if JOBS
3745 if (!jp1 || jp1->state != JOBSTOPPED)
3746#endif
3747 break;
3748 jpp = &jp1->prev_job;
Denys Vlasenko940c7202011-03-02 04:07:14 +01003749 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003750 /* FALLTHROUGH */
3751#if JOBS
3752 case CUR_STOPPED:
3753#endif
3754 /* newly stopped job - becomes curjob */
3755 jp->prev_job = *jpp;
3756 *jpp = jp;
3757 break;
3758 }
3759}
3760
3761#if JOBS || DEBUG
3762static int
3763jobno(const struct job *jp)
3764{
3765 return jp - jobtab + 1;
3766}
3767#endif
3768
3769/*
3770 * Convert a job name to a job structure.
3771 */
Denis Vlasenko85c24712008-03-17 09:04:04 +00003772#if !JOBS
3773#define getjob(name, getctl) getjob(name)
3774#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003775static struct job *
3776getjob(const char *name, int getctl)
3777{
3778 struct job *jp;
3779 struct job *found;
Denys Vlasenkoffc39202009-08-17 02:12:20 +02003780 const char *err_msg = "%s: no such job";
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003781 unsigned num;
3782 int c;
3783 const char *p;
3784 char *(*match)(const char *, const char *);
3785
3786 jp = curjob;
3787 p = name;
3788 if (!p)
3789 goto currentjob;
3790
3791 if (*p != '%')
3792 goto err;
3793
3794 c = *++p;
3795 if (!c)
3796 goto currentjob;
3797
3798 if (!p[1]) {
3799 if (c == '+' || c == '%') {
3800 currentjob:
3801 err_msg = "No current job";
3802 goto check;
3803 }
3804 if (c == '-') {
3805 if (jp)
3806 jp = jp->prev_job;
3807 err_msg = "No previous job";
3808 check:
3809 if (!jp)
3810 goto err;
3811 goto gotit;
3812 }
3813 }
3814
3815 if (is_number(p)) {
3816 num = atoi(p);
Denys Vlasenko46a45ce2016-09-29 01:10:08 +02003817 if (num > 0 && num <= njobs) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003818 jp = jobtab + num - 1;
3819 if (jp->used)
3820 goto gotit;
3821 goto err;
3822 }
3823 }
3824
3825 match = prefix;
3826 if (*p == '?') {
3827 match = strstr;
3828 p++;
3829 }
3830
Denys Vlasenkoffc39202009-08-17 02:12:20 +02003831 found = NULL;
3832 while (jp) {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003833 if (match(jp->ps[0].ps_cmd, p)) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003834 if (found)
3835 goto err;
3836 found = jp;
3837 err_msg = "%s: ambiguous";
3838 }
3839 jp = jp->prev_job;
3840 }
Denys Vlasenkoffc39202009-08-17 02:12:20 +02003841 if (!found)
3842 goto err;
3843 jp = found;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003844
3845 gotit:
3846#if JOBS
3847 err_msg = "job %s not created under job control";
3848 if (getctl && jp->jobctl == 0)
3849 goto err;
3850#endif
3851 return jp;
3852 err:
3853 ash_msg_and_raise_error(err_msg, name);
3854}
3855
3856/*
3857 * Mark a job structure as unused.
3858 */
3859static void
3860freejob(struct job *jp)
3861{
3862 struct procstat *ps;
3863 int i;
3864
3865 INT_OFF;
3866 for (i = jp->nprocs, ps = jp->ps; --i >= 0; ps++) {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003867 if (ps->ps_cmd != nullstr)
3868 free(ps->ps_cmd);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003869 }
3870 if (jp->ps != &jp->ps0)
3871 free(jp->ps);
3872 jp->used = 0;
3873 set_curjob(jp, CUR_DELETE);
3874 INT_ON;
3875}
3876
3877#if JOBS
3878static void
3879xtcsetpgrp(int fd, pid_t pgrp)
3880{
3881 if (tcsetpgrp(fd, pgrp))
Ron Yorstonbe366e52017-07-27 13:53:39 +01003882 ash_msg_and_raise_perror("can't set tty process group");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003883}
3884
3885/*
3886 * Turn job control on and off.
3887 *
3888 * Note: This code assumes that the third arg to ioctl is a character
3889 * pointer, which is true on Berkeley systems but not System V. Since
3890 * System V doesn't have job control yet, this isn't a problem now.
3891 *
3892 * Called with interrupts off.
3893 */
3894static void
3895setjobctl(int on)
3896{
3897 int fd;
3898 int pgrp;
3899
Denis Vlasenkob07a4962008-06-22 13:16:23 +00003900 if (on == doing_jobctl || rootshell == 0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003901 return;
3902 if (on) {
3903 int ofd;
3904 ofd = fd = open(_PATH_TTY, O_RDWR);
3905 if (fd < 0) {
3906 /* BTW, bash will try to open(ttyname(0)) if open("/dev/tty") fails.
3907 * That sometimes helps to acquire controlling tty.
3908 * Obviously, a workaround for bugs when someone
3909 * failed to provide a controlling tty to bash! :) */
Denis Vlasenkoed270a52007-11-26 05:37:07 +00003910 fd = 2;
3911 while (!isatty(fd))
3912 if (--fd < 0)
3913 goto out;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003914 }
Denys Vlasenko64774602016-10-26 15:24:30 +02003915 /* fd is a tty at this point */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003916 fd = fcntl(fd, F_DUPFD, 10);
Denys Vlasenko10ad6222017-04-17 16:13:32 +02003917 if (ofd >= 0) /* if it is "/dev/tty", close. If 0/1/2, don't */
Denis Vlasenkoed270a52007-11-26 05:37:07 +00003918 close(ofd);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003919 if (fd < 0)
Denys Vlasenko64774602016-10-26 15:24:30 +02003920 goto out; /* F_DUPFD failed */
Denis Vlasenko96e1b382007-09-30 23:50:48 +00003921 close_on_exec_on(fd);
Denys Vlasenko940c7202011-03-02 04:07:14 +01003922 while (1) { /* while we are in the background */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003923 pgrp = tcgetpgrp(fd);
3924 if (pgrp < 0) {
3925 out:
3926 ash_msg("can't access tty; job control turned off");
3927 mflag = on = 0;
3928 goto close;
3929 }
3930 if (pgrp == getpgrp())
3931 break;
3932 killpg(0, SIGTTIN);
Denys Vlasenko940c7202011-03-02 04:07:14 +01003933 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003934 initialpgrp = pgrp;
3935
3936 setsignal(SIGTSTP);
3937 setsignal(SIGTTOU);
3938 setsignal(SIGTTIN);
3939 pgrp = rootpid;
3940 setpgid(0, pgrp);
3941 xtcsetpgrp(fd, pgrp);
3942 } else {
3943 /* turning job control off */
3944 fd = ttyfd;
3945 pgrp = initialpgrp;
Denis Vlasenko08c8c1d2007-04-28 22:39:02 +00003946 /* was xtcsetpgrp, but this can make exiting ash
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00003947 * loop forever if pty is already deleted */
Denis Vlasenko08c8c1d2007-04-28 22:39:02 +00003948 tcsetpgrp(fd, pgrp);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003949 setpgid(0, pgrp);
3950 setsignal(SIGTSTP);
3951 setsignal(SIGTTOU);
3952 setsignal(SIGTTIN);
3953 close:
Denis Vlasenkoed270a52007-11-26 05:37:07 +00003954 if (fd >= 0)
3955 close(fd);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003956 fd = -1;
3957 }
3958 ttyfd = fd;
Denis Vlasenkob07a4962008-06-22 13:16:23 +00003959 doing_jobctl = on;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003960}
3961
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02003962static int FAST_FUNC
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003963killcmd(int argc, char **argv)
3964{
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003965 if (argv[1] && strcmp(argv[1], "-l") != 0) {
Denys Vlasenkob12553f2011-02-21 03:22:20 +01003966 int i = 1;
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003967 do {
3968 if (argv[i][0] == '%') {
Denys Vlasenkob12553f2011-02-21 03:22:20 +01003969 /*
3970 * "kill %N" - job kill
3971 * Converting to pgrp / pid kill
3972 */
3973 struct job *jp;
3974 char *dst;
3975 int j, n;
3976
3977 jp = getjob(argv[i], 0);
3978 /*
3979 * In jobs started under job control, we signal
3980 * entire process group by kill -PGRP_ID.
3981 * This happens, f.e., in interactive shell.
3982 *
3983 * Otherwise, we signal each child via
3984 * kill PID1 PID2 PID3.
3985 * Testcases:
3986 * sh -c 'sleep 1|sleep 1 & kill %1'
3987 * sh -c 'true|sleep 2 & sleep 1; kill %1'
3988 * sh -c 'true|sleep 1 & sleep 2; kill %1'
3989 */
3990 n = jp->nprocs; /* can't be 0 (I hope) */
3991 if (jp->jobctl)
3992 n = 1;
3993 dst = alloca(n * sizeof(int)*4);
3994 argv[i] = dst;
3995 for (j = 0; j < n; j++) {
3996 struct procstat *ps = &jp->ps[j];
3997 /* Skip non-running and not-stopped members
3998 * (i.e. dead members) of the job
3999 */
4000 if (ps->ps_status != -1 && !WIFSTOPPED(ps->ps_status))
4001 continue;
4002 /*
4003 * kill_main has matching code to expect
4004 * leading space. Needed to not confuse
4005 * negative pids with "kill -SIGNAL_NO" syntax
4006 */
4007 dst += sprintf(dst, jp->jobctl ? " -%u" : " %u", (int)ps->ps_pid);
4008 }
4009 *dst = '\0';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004010 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00004011 } while (argv[++i]);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004012 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00004013 return kill_main(argc, argv);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004014}
4015
4016static void
Denys Vlasenko285ad152009-12-04 23:02:27 +01004017showpipe(struct job *jp /*, FILE *out*/)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004018{
Denys Vlasenko285ad152009-12-04 23:02:27 +01004019 struct procstat *ps;
4020 struct procstat *psend;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004021
Denys Vlasenko285ad152009-12-04 23:02:27 +01004022 psend = jp->ps + jp->nprocs;
4023 for (ps = jp->ps + 1; ps < psend; ps++)
4024 printf(" | %s", ps->ps_cmd);
Denys Vlasenko9c541002015-10-07 15:44:36 +02004025 newline_and_flush(stdout);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004026 flush_stdout_stderr();
4027}
4028
4029
4030static int
4031restartjob(struct job *jp, int mode)
4032{
4033 struct procstat *ps;
4034 int i;
4035 int status;
4036 pid_t pgid;
4037
4038 INT_OFF;
4039 if (jp->state == JOBDONE)
4040 goto out;
4041 jp->state = JOBRUNNING;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004042 pgid = jp->ps[0].ps_pid;
Denys Vlasenko098b7132017-01-11 19:59:03 +01004043 if (mode == FORK_FG) {
4044 get_tty_state();
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004045 xtcsetpgrp(ttyfd, pgid);
Denys Vlasenko098b7132017-01-11 19:59:03 +01004046 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004047 killpg(pgid, SIGCONT);
4048 ps = jp->ps;
4049 i = jp->nprocs;
4050 do {
Denys Vlasenko285ad152009-12-04 23:02:27 +01004051 if (WIFSTOPPED(ps->ps_status)) {
4052 ps->ps_status = -1;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004053 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00004054 ps++;
4055 } while (--i);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004056 out:
4057 status = (mode == FORK_FG) ? waitforjob(jp) : 0;
4058 INT_ON;
4059 return status;
4060}
4061
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02004062static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00004063fg_bgcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004064{
4065 struct job *jp;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004066 int mode;
4067 int retval;
4068
4069 mode = (**argv == 'f') ? FORK_FG : FORK_BG;
4070 nextopt(nullstr);
4071 argv = argptr;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004072 do {
4073 jp = getjob(*argv, 1);
4074 if (mode == FORK_BG) {
4075 set_curjob(jp, CUR_RUNNING);
Denys Vlasenko285ad152009-12-04 23:02:27 +01004076 printf("[%d] ", jobno(jp));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004077 }
Denys Vlasenko285ad152009-12-04 23:02:27 +01004078 out1str(jp->ps[0].ps_cmd);
4079 showpipe(jp /*, stdout*/);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004080 retval = restartjob(jp, mode);
4081 } while (*argv && *++argv);
4082 return retval;
4083}
4084#endif
4085
4086static int
Denys Vlasenko9c541002015-10-07 15:44:36 +02004087sprint_status48(char *s, int status, int sigonly)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004088{
4089 int col;
4090 int st;
4091
4092 col = 0;
4093 if (!WIFEXITED(status)) {
Johannes Schindelin9d4dc842017-07-14 22:25:58 +02004094#if JOBS
4095 if (WIFSTOPPED(status))
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004096 st = WSTOPSIG(status);
4097 else
Johannes Schindelin9d4dc842017-07-14 22:25:58 +02004098#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004099 st = WTERMSIG(status);
4100 if (sigonly) {
4101 if (st == SIGINT || st == SIGPIPE)
4102 goto out;
Johannes Schindelin9d4dc842017-07-14 22:25:58 +02004103#if JOBS
4104 if (WIFSTOPPED(status))
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004105 goto out;
Johannes Schindelin9d4dc842017-07-14 22:25:58 +02004106#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004107 }
4108 st &= 0x7f;
Denys Vlasenko7c6f2462011-02-14 17:17:10 +01004109//TODO: use bbox's get_signame? strsignal adds ~600 bytes to text+rodata
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004110 col = fmtstr(s, 32, strsignal(st));
4111 if (WCOREDUMP(status)) {
Denys Vlasenko9c541002015-10-07 15:44:36 +02004112 strcpy(s + col, " (core dumped)");
4113 col += sizeof(" (core dumped)")-1;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004114 }
4115 } else if (!sigonly) {
4116 st = WEXITSTATUS(status);
Denys Vlasenko9c541002015-10-07 15:44:36 +02004117 col = fmtstr(s, 16, (st ? "Done(%d)" : "Done"), st);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004118 }
4119 out:
4120 return col;
4121}
4122
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004123static int
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004124wait_block_or_sig(int *status)
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004125{
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004126 int pid;
4127
4128 do {
Denys Vlasenko1ab7c2f2016-11-03 20:17:23 +01004129 sigset_t mask;
4130
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004131 /* Poll all children for changes in their state */
4132 got_sigchld = 0;
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004133 /* if job control is active, accept stopped processes too */
4134 pid = waitpid(-1, status, doing_jobctl ? (WNOHANG|WUNTRACED) : WNOHANG);
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004135 if (pid != 0)
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004136 break; /* Error (e.g. EINTR, ECHILD) or pid */
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004137
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004138 /* Children exist, but none are ready. Sleep until interesting signal */
Denys Vlasenko1ab7c2f2016-11-03 20:17:23 +01004139#if 1
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004140 sigfillset(&mask);
4141 sigprocmask(SIG_SETMASK, &mask, &mask);
4142 while (!got_sigchld && !pending_sig)
4143 sigsuspend(&mask);
4144 sigprocmask(SIG_SETMASK, &mask, NULL);
Denys Vlasenko1ab7c2f2016-11-03 20:17:23 +01004145#else /* unsafe: a signal can set pending_sig after check, but before pause() */
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004146 while (!got_sigchld && !pending_sig)
4147 pause();
4148#endif
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004149
4150 /* If it was SIGCHLD, poll children again */
4151 } while (got_sigchld);
4152
4153 return pid;
4154}
4155
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004156#define DOWAIT_NONBLOCK 0
4157#define DOWAIT_BLOCK 1
4158#define DOWAIT_BLOCK_OR_SIG 2
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004159
4160static int
Denys Vlasenkob543bda2016-10-27 20:08:28 +02004161dowait(int block, struct job *job)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004162{
4163 int pid;
4164 int status;
4165 struct job *jp;
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004166 struct job *thisjob = NULL;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004167
Denys Vlasenkob543bda2016-10-27 20:08:28 +02004168 TRACE(("dowait(0x%x) called\n", block));
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +00004169
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004170 /* It's wrong to call waitpid() outside of INT_OFF region:
4171 * signal can arrive just after syscall return and handler can
4172 * longjmp away, losing stop/exit notification processing.
4173 * Thus, for "jobs" builtin, and for waiting for a fg job,
4174 * we call waitpid() (blocking or non-blocking) inside INT_OFF.
4175 *
4176 * However, for "wait" builtin it is wrong to simply call waitpid()
4177 * in INT_OFF region: "wait" needs to wait for any running job
4178 * to change state, but should exit on any trap too.
4179 * In INT_OFF region, a signal just before syscall entry can set
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004180 * pending_sig variables, but we can't check them, and we would
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004181 * either enter a sleeping waitpid() (BUG), or need to busy-loop.
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004182 *
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004183 * Because of this, we run inside INT_OFF, but use a special routine
Denys Vlasenko1ab7c2f2016-11-03 20:17:23 +01004184 * which combines waitpid() and sigsuspend().
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004185 * This is the reason why we need to have a handler for SIGCHLD:
Denys Vlasenko1ab7c2f2016-11-03 20:17:23 +01004186 * SIG_DFL handler does not wake sigsuspend().
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004187 */
4188 INT_OFF;
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004189 if (block == DOWAIT_BLOCK_OR_SIG) {
4190 pid = wait_block_or_sig(&status);
4191 } else {
4192 int wait_flags = 0;
4193 if (block == DOWAIT_NONBLOCK)
4194 wait_flags = WNOHANG;
4195 /* if job control is active, accept stopped processes too */
4196 if (doing_jobctl)
4197 wait_flags |= WUNTRACED;
4198 /* NB: _not_ safe_waitpid, we need to detect EINTR */
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004199 pid = waitpid(-1, &status, wait_flags);
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004200 }
Denis Vlasenkob21f3792009-03-19 23:09:58 +00004201 TRACE(("wait returns pid=%d, status=0x%x, errno=%d(%s)\n",
4202 pid, status, errno, strerror(errno)));
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004203 if (pid <= 0)
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004204 goto out;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004205
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004206 thisjob = NULL;
4207 for (jp = curjob; jp; jp = jp->prev_job) {
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004208 int jobstate;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004209 struct procstat *ps;
4210 struct procstat *psend;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004211 if (jp->state == JOBDONE)
4212 continue;
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004213 jobstate = JOBDONE;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004214 ps = jp->ps;
4215 psend = ps + jp->nprocs;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004216 do {
Denys Vlasenko285ad152009-12-04 23:02:27 +01004217 if (ps->ps_pid == pid) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004218 TRACE(("Job %d: changing status of proc %d "
4219 "from 0x%x to 0x%x\n",
Denys Vlasenko285ad152009-12-04 23:02:27 +01004220 jobno(jp), pid, ps->ps_status, status));
4221 ps->ps_status = status;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004222 thisjob = jp;
4223 }
Denys Vlasenko285ad152009-12-04 23:02:27 +01004224 if (ps->ps_status == -1)
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004225 jobstate = JOBRUNNING;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004226#if JOBS
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004227 if (jobstate == JOBRUNNING)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004228 continue;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004229 if (WIFSTOPPED(ps->ps_status)) {
4230 jp->stopstatus = ps->ps_status;
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004231 jobstate = JOBSTOPPED;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004232 }
4233#endif
Denys Vlasenko285ad152009-12-04 23:02:27 +01004234 } while (++ps < psend);
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004235 if (!thisjob)
4236 continue;
4237
4238 /* Found the job where one of its processes changed its state.
4239 * Is there at least one live and running process in this job? */
4240 if (jobstate != JOBRUNNING) {
4241 /* No. All live processes in the job are stopped
4242 * (JOBSTOPPED) or there are no live processes (JOBDONE)
4243 */
4244 thisjob->changed = 1;
4245 if (thisjob->state != jobstate) {
4246 TRACE(("Job %d: changing state from %d to %d\n",
4247 jobno(thisjob), thisjob->state, jobstate));
4248 thisjob->state = jobstate;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004249#if JOBS
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004250 if (jobstate == JOBSTOPPED)
4251 set_curjob(thisjob, CUR_STOPPED);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004252#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004253 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004254 }
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004255 goto out;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004256 }
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004257 /* The process wasn't found in job list */
Johannes Schindelin9d4dc842017-07-14 22:25:58 +02004258#if JOBS
4259 if (!WIFSTOPPED(status))
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004260 jobless--;
Johannes Schindelin9d4dc842017-07-14 22:25:58 +02004261#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004262 out:
4263 INT_ON;
4264
4265 if (thisjob && thisjob == job) {
4266 char s[48 + 1];
4267 int len;
4268
Denys Vlasenko9c541002015-10-07 15:44:36 +02004269 len = sprint_status48(s, status, 1);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004270 if (len) {
4271 s[len] = '\n';
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004272 s[len + 1] = '\0';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004273 out2str(s);
4274 }
4275 }
4276 return pid;
4277}
4278
4279#if JOBS
4280static void
Denys Vlasenko9c541002015-10-07 15:44:36 +02004281showjob(struct job *jp, int mode)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004282{
4283 struct procstat *ps;
4284 struct procstat *psend;
4285 int col;
Denis Vlasenko40ba9982007-07-14 00:48:29 +00004286 int indent_col;
Denys Vlasenko9c541002015-10-07 15:44:36 +02004287 char s[16 + 16 + 48];
4288 FILE *out = (mode & SHOW_STDERR ? stderr : stdout);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004289
4290 ps = jp->ps;
4291
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004292 if (mode & SHOW_ONLY_PGID) { /* jobs -p */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004293 /* just output process (group) id of pipeline */
Denys Vlasenko285ad152009-12-04 23:02:27 +01004294 fprintf(out, "%d\n", ps->ps_pid);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004295 return;
4296 }
4297
4298 col = fmtstr(s, 16, "[%d] ", jobno(jp));
Denis Vlasenko40ba9982007-07-14 00:48:29 +00004299 indent_col = col;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004300
4301 if (jp == curjob)
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004302 s[col - 3] = '+';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004303 else if (curjob && jp == curjob->prev_job)
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004304 s[col - 3] = '-';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004305
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004306 if (mode & SHOW_PIDS)
Denys Vlasenko285ad152009-12-04 23:02:27 +01004307 col += fmtstr(s + col, 16, "%d ", ps->ps_pid);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004308
4309 psend = ps + jp->nprocs;
4310
4311 if (jp->state == JOBRUNNING) {
4312 strcpy(s + col, "Running");
4313 col += sizeof("Running") - 1;
4314 } else {
Denys Vlasenko285ad152009-12-04 23:02:27 +01004315 int status = psend[-1].ps_status;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004316 if (jp->state == JOBSTOPPED)
4317 status = jp->stopstatus;
Denys Vlasenko9c541002015-10-07 15:44:36 +02004318 col += sprint_status48(s + col, status, 0);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004319 }
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004320 /* By now, "[JOBID]* [maybe PID] STATUS" is printed */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004321
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004322 /* This loop either prints "<cmd1> | <cmd2> | <cmd3>" line
4323 * or prints several "PID | <cmdN>" lines,
4324 * depending on SHOW_PIDS bit.
4325 * We do not print status of individual processes
4326 * between PID and <cmdN>. bash does it, but not very well:
4327 * first line shows overall job status, not process status,
4328 * making it impossible to know 1st process status.
4329 */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004330 goto start;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004331 do {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004332 /* for each process */
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004333 s[0] = '\0';
4334 col = 33;
4335 if (mode & SHOW_PIDS)
Denys Vlasenko285ad152009-12-04 23:02:27 +01004336 col = fmtstr(s, 48, "\n%*c%d ", indent_col, ' ', ps->ps_pid) - 1;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004337 start:
Denys Vlasenko285ad152009-12-04 23:02:27 +01004338 fprintf(out, "%s%*c%s%s",
4339 s,
4340 33 - col >= 0 ? 33 - col : 0, ' ',
4341 ps == jp->ps ? "" : "| ",
4342 ps->ps_cmd
4343 );
4344 } while (++ps != psend);
Denys Vlasenko9c541002015-10-07 15:44:36 +02004345 newline_and_flush(out);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004346
4347 jp->changed = 0;
4348
4349 if (jp->state == JOBDONE) {
4350 TRACE(("showjob: freeing job %d\n", jobno(jp)));
4351 freejob(jp);
4352 }
4353}
4354
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004355/*
4356 * Print a list of jobs. If "change" is nonzero, only print jobs whose
4357 * statuses have changed since the last call to showjobs.
4358 */
4359static void
Denys Vlasenko9c541002015-10-07 15:44:36 +02004360showjobs(int mode)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004361{
4362 struct job *jp;
4363
Denys Vlasenko883cea42009-07-11 15:31:59 +02004364 TRACE(("showjobs(0x%x) called\n", mode));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004365
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004366 /* Handle all finished jobs */
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004367 while (dowait(DOWAIT_NONBLOCK, NULL) > 0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004368 continue;
4369
4370 for (jp = curjob; jp; jp = jp->prev_job) {
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004371 if (!(mode & SHOW_CHANGED) || jp->changed) {
Denys Vlasenko9c541002015-10-07 15:44:36 +02004372 showjob(jp, mode);
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004373 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004374 }
4375}
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004376
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02004377static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00004378jobscmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004379{
4380 int mode, m;
4381
4382 mode = 0;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02004383 while ((m = nextopt("lp")) != '\0') {
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004384 if (m == 'l')
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004385 mode |= SHOW_PIDS;
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004386 else
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004387 mode |= SHOW_ONLY_PGID;
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004388 }
4389
4390 argv = argptr;
4391 if (*argv) {
4392 do
Denys Vlasenko9c541002015-10-07 15:44:36 +02004393 showjob(getjob(*argv, 0), mode);
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004394 while (*++argv);
Denys Vlasenko285ad152009-12-04 23:02:27 +01004395 } else {
Denys Vlasenko9c541002015-10-07 15:44:36 +02004396 showjobs(mode);
Denys Vlasenko285ad152009-12-04 23:02:27 +01004397 }
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004398
4399 return 0;
4400}
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004401#endif /* JOBS */
4402
Michael Abbott359da5e2009-12-04 23:03:29 +01004403/* Called only on finished or stopped jobs (no members are running) */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004404static int
4405getstatus(struct job *job)
4406{
4407 int status;
4408 int retval;
Michael Abbott359da5e2009-12-04 23:03:29 +01004409 struct procstat *ps;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004410
Michael Abbott359da5e2009-12-04 23:03:29 +01004411 /* Fetch last member's status */
4412 ps = job->ps + job->nprocs - 1;
4413 status = ps->ps_status;
4414 if (pipefail) {
4415 /* "set -o pipefail" mode: use last _nonzero_ status */
4416 while (status == 0 && --ps >= job->ps)
4417 status = ps->ps_status;
4418 }
4419
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004420 retval = WEXITSTATUS(status);
4421 if (!WIFEXITED(status)) {
4422#if JOBS
4423 retval = WSTOPSIG(status);
4424 if (!WIFSTOPPED(status))
4425#endif
4426 {
4427 /* XXX: limits number of signals */
4428 retval = WTERMSIG(status);
4429#if JOBS
4430 if (retval == SIGINT)
4431 job->sigint = 1;
4432#endif
4433 }
4434 retval += 128;
4435 }
Denys Vlasenko883cea42009-07-11 15:31:59 +02004436 TRACE(("getstatus: job %d, nproc %d, status 0x%x, retval 0x%x\n",
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004437 jobno(job), job->nprocs, status, retval));
4438 return retval;
4439}
4440
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02004441static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00004442waitcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004443{
4444 struct job *job;
4445 int retval;
4446 struct job *jp;
4447
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004448 nextopt(nullstr);
4449 retval = 0;
4450
4451 argv = argptr;
4452 if (!*argv) {
4453 /* wait for all jobs */
4454 for (;;) {
4455 jp = curjob;
4456 while (1) {
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004457 if (!jp) /* no running procs */
4458 goto ret;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004459 if (jp->state == JOBRUNNING)
4460 break;
4461 jp->waited = 1;
4462 jp = jp->prev_job;
4463 }
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004464 /* man bash:
4465 * "When bash is waiting for an asynchronous command via
4466 * the wait builtin, the reception of a signal for which a trap
4467 * has been set will cause the wait builtin to return immediately
4468 * with an exit status greater than 128, immediately after which
4469 * the trap is executed."
Denys Vlasenko69188112016-10-27 20:18:18 +02004470 */
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004471 dowait(DOWAIT_BLOCK_OR_SIG, NULL);
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02004472 /* if child sends us a signal *and immediately exits*,
4473 * dowait() returns pid > 0. Check this case,
4474 * not "if (dowait() < 0)"!
4475 */
Denys Vlasenko7c1ed9f2010-05-17 04:42:40 +02004476 if (pending_sig)
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02004477 goto sigout;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004478 }
4479 }
4480
4481 retval = 127;
4482 do {
4483 if (**argv != '%') {
4484 pid_t pid = number(*argv);
4485 job = curjob;
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004486 while (1) {
4487 if (!job)
4488 goto repeat;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004489 if (job->ps[job->nprocs - 1].ps_pid == pid)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004490 break;
4491 job = job->prev_job;
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004492 }
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004493 } else {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004494 job = getjob(*argv, 0);
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004495 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004496 /* loop until process terminated or stopped */
Denys Vlasenko69188112016-10-27 20:18:18 +02004497 while (job->state == JOBRUNNING) {
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004498 dowait(DOWAIT_BLOCK_OR_SIG, NULL);
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02004499 if (pending_sig)
4500 goto sigout;
Denys Vlasenko69188112016-10-27 20:18:18 +02004501 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004502 job->waited = 1;
4503 retval = getstatus(job);
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004504 repeat: ;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004505 } while (*++argv);
4506
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004507 ret:
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004508 return retval;
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02004509 sigout:
4510 retval = 128 + pending_sig;
4511 return retval;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004512}
4513
4514static struct job *
4515growjobtab(void)
4516{
4517 size_t len;
4518 ptrdiff_t offset;
4519 struct job *jp, *jq;
4520
4521 len = njobs * sizeof(*jp);
4522 jq = jobtab;
4523 jp = ckrealloc(jq, len + 4 * sizeof(*jp));
4524
4525 offset = (char *)jp - (char *)jq;
4526 if (offset) {
4527 /* Relocate pointers */
4528 size_t l = len;
4529
4530 jq = (struct job *)((char *)jq + l);
4531 while (l) {
4532 l -= sizeof(*jp);
4533 jq--;
4534#define joff(p) ((struct job *)((char *)(p) + l))
4535#define jmove(p) (p) = (void *)((char *)(p) + offset)
4536 if (joff(jp)->ps == &jq->ps0)
4537 jmove(joff(jp)->ps);
4538 if (joff(jp)->prev_job)
4539 jmove(joff(jp)->prev_job);
4540 }
4541 if (curjob)
4542 jmove(curjob);
4543#undef joff
4544#undef jmove
4545 }
4546
4547 njobs += 4;
4548 jobtab = jp;
4549 jp = (struct job *)((char *)jp + len);
4550 jq = jp + 3;
4551 do {
4552 jq->used = 0;
4553 } while (--jq >= jp);
4554 return jp;
4555}
4556
4557/*
4558 * Return a new job structure.
4559 * Called with interrupts off.
4560 */
4561static struct job *
Denis Vlasenko68404f12008-03-17 09:00:54 +00004562makejob(/*union node *node,*/ int nprocs)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004563{
4564 int i;
4565 struct job *jp;
4566
4567 for (i = njobs, jp = jobtab; ; jp++) {
4568 if (--i < 0) {
4569 jp = growjobtab();
4570 break;
4571 }
4572 if (jp->used == 0)
4573 break;
4574 if (jp->state != JOBDONE || !jp->waited)
4575 continue;
4576#if JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +00004577 if (doing_jobctl)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004578 continue;
4579#endif
4580 freejob(jp);
4581 break;
4582 }
4583 memset(jp, 0, sizeof(*jp));
4584#if JOBS
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004585 /* jp->jobctl is a bitfield.
Denys Vlasenko098b7132017-01-11 19:59:03 +01004586 * "jp->jobctl |= doing_jobctl" likely to give awful code */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00004587 if (doing_jobctl)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004588 jp->jobctl = 1;
4589#endif
4590 jp->prev_job = curjob;
4591 curjob = jp;
4592 jp->used = 1;
4593 jp->ps = &jp->ps0;
4594 if (nprocs > 1) {
4595 jp->ps = ckmalloc(nprocs * sizeof(struct procstat));
4596 }
Denis Vlasenko68404f12008-03-17 09:00:54 +00004597 TRACE(("makejob(%d) returns %%%d\n", nprocs,
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004598 jobno(jp)));
4599 return jp;
4600}
4601
4602#if JOBS
4603/*
4604 * Return a string identifying a command (to be printed by the
4605 * jobs command).
4606 */
4607static char *cmdnextc;
4608
4609static void
4610cmdputs(const char *s)
4611{
Denis Vlasenko92e13c22008-03-25 01:17:40 +00004612 static const char vstype[VSTYPE + 1][3] = {
4613 "", "}", "-", "+", "?", "=",
4614 "%", "%%", "#", "##"
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01004615 IF_BASH_SUBSTR(, ":")
4616 IF_BASH_PATTERN_SUBST(, "/", "//")
Denis Vlasenko92e13c22008-03-25 01:17:40 +00004617 };
4618
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004619 const char *p, *str;
Denys Vlasenko46a14772009-12-10 21:27:13 +01004620 char cc[2];
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004621 char *nextc;
Denys Vlasenkocd716832009-11-28 22:14:02 +01004622 unsigned char c;
4623 unsigned char subtype = 0;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004624 int quoted = 0;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004625
Denys Vlasenko46a14772009-12-10 21:27:13 +01004626 cc[1] = '\0';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004627 nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
4628 p = s;
Denys Vlasenko46a14772009-12-10 21:27:13 +01004629 while ((c = *p++) != '\0') {
Denis Vlasenkoef527f52008-06-23 01:52:30 +00004630 str = NULL;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004631 switch (c) {
4632 case CTLESC:
4633 c = *p++;
4634 break;
4635 case CTLVAR:
4636 subtype = *p++;
4637 if ((subtype & VSTYPE) == VSLENGTH)
4638 str = "${#";
4639 else
4640 str = "${";
Ron Yorston549deab2015-05-18 09:57:51 +02004641 goto dostr;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004642 case CTLENDVAR:
4643 str = "\"}" + !(quoted & 1);
4644 quoted >>= 1;
4645 subtype = 0;
4646 goto dostr;
4647 case CTLBACKQ:
4648 str = "$(...)";
4649 goto dostr;
Denys Vlasenko0b883582016-12-23 16:49:07 +01004650#if ENABLE_FEATURE_SH_MATH
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004651 case CTLARI:
4652 str = "$((";
4653 goto dostr;
4654 case CTLENDARI:
4655 str = "))";
4656 goto dostr;
4657#endif
4658 case CTLQUOTEMARK:
4659 quoted ^= 1;
4660 c = '"';
4661 break;
4662 case '=':
4663 if (subtype == 0)
4664 break;
4665 if ((subtype & VSTYPE) != VSNORMAL)
4666 quoted <<= 1;
4667 str = vstype[subtype & VSTYPE];
4668 if (subtype & VSNUL)
4669 c = ':';
4670 else
4671 goto checkstr;
4672 break;
4673 case '\'':
4674 case '\\':
4675 case '"':
4676 case '$':
4677 /* These can only happen inside quotes */
4678 cc[0] = c;
4679 str = cc;
Denys Vlasenkod0fff912017-07-31 14:32:18 +02004680//FIXME:
4681// $ true $$ &
4682// $ <cr>
4683// [1]+ Done true ${\$} <<=== BUG: ${\$} is not a valid way to write $$ (${$} would be ok)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004684 c = '\\';
4685 break;
4686 default:
4687 break;
4688 }
4689 USTPUTC(c, nextc);
4690 checkstr:
4691 if (!str)
4692 continue;
4693 dostr:
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02004694 while ((c = *str++) != '\0') {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004695 USTPUTC(c, nextc);
4696 }
Denys Vlasenko46a14772009-12-10 21:27:13 +01004697 } /* while *p++ not NUL */
4698
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004699 if (quoted & 1) {
4700 USTPUTC('"', nextc);
4701 }
4702 *nextc = 0;
4703 cmdnextc = nextc;
4704}
4705
4706/* cmdtxt() and cmdlist() call each other */
4707static void cmdtxt(union node *n);
4708
4709static void
4710cmdlist(union node *np, int sep)
4711{
4712 for (; np; np = np->narg.next) {
4713 if (!sep)
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00004714 cmdputs(" ");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004715 cmdtxt(np);
4716 if (sep && np->narg.next)
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00004717 cmdputs(" ");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004718 }
4719}
4720
4721static void
4722cmdtxt(union node *n)
4723{
4724 union node *np;
4725 struct nodelist *lp;
4726 const char *p;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004727
4728 if (!n)
4729 return;
4730 switch (n->type) {
4731 default:
4732#if DEBUG
4733 abort();
4734#endif
4735 case NPIPE:
4736 lp = n->npipe.cmdlist;
4737 for (;;) {
4738 cmdtxt(lp->n);
4739 lp = lp->next;
4740 if (!lp)
4741 break;
4742 cmdputs(" | ");
4743 }
4744 break;
4745 case NSEMI:
4746 p = "; ";
4747 goto binop;
4748 case NAND:
4749 p = " && ";
4750 goto binop;
4751 case NOR:
4752 p = " || ";
4753 binop:
4754 cmdtxt(n->nbinary.ch1);
4755 cmdputs(p);
4756 n = n->nbinary.ch2;
4757 goto donode;
4758 case NREDIR:
4759 case NBACKGND:
4760 n = n->nredir.n;
4761 goto donode;
4762 case NNOT:
4763 cmdputs("!");
4764 n = n->nnot.com;
4765 donode:
4766 cmdtxt(n);
4767 break;
4768 case NIF:
4769 cmdputs("if ");
4770 cmdtxt(n->nif.test);
4771 cmdputs("; then ");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004772 if (n->nif.elsepart) {
Denys Vlasenko7cee00e2009-07-24 01:08:03 +02004773 cmdtxt(n->nif.ifpart);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004774 cmdputs("; else ");
4775 n = n->nif.elsepart;
Denys Vlasenko7cee00e2009-07-24 01:08:03 +02004776 } else {
4777 n = n->nif.ifpart;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004778 }
4779 p = "; fi";
4780 goto dotail;
4781 case NSUBSHELL:
4782 cmdputs("(");
4783 n = n->nredir.n;
4784 p = ")";
4785 goto dotail;
4786 case NWHILE:
4787 p = "while ";
4788 goto until;
4789 case NUNTIL:
4790 p = "until ";
4791 until:
4792 cmdputs(p);
4793 cmdtxt(n->nbinary.ch1);
4794 n = n->nbinary.ch2;
4795 p = "; done";
4796 dodo:
4797 cmdputs("; do ");
4798 dotail:
4799 cmdtxt(n);
4800 goto dotail2;
4801 case NFOR:
4802 cmdputs("for ");
4803 cmdputs(n->nfor.var);
4804 cmdputs(" in ");
4805 cmdlist(n->nfor.args, 1);
4806 n = n->nfor.body;
4807 p = "; done";
4808 goto dodo;
4809 case NDEFUN:
4810 cmdputs(n->narg.text);
4811 p = "() { ... }";
4812 goto dotail2;
4813 case NCMD:
4814 cmdlist(n->ncmd.args, 1);
4815 cmdlist(n->ncmd.redirect, 0);
4816 break;
4817 case NARG:
4818 p = n->narg.text;
4819 dotail2:
4820 cmdputs(p);
4821 break;
4822 case NHERE:
4823 case NXHERE:
4824 p = "<<...";
4825 goto dotail2;
4826 case NCASE:
4827 cmdputs("case ");
4828 cmdputs(n->ncase.expr->narg.text);
4829 cmdputs(" in ");
4830 for (np = n->ncase.cases; np; np = np->nclist.next) {
4831 cmdtxt(np->nclist.pattern);
4832 cmdputs(") ");
4833 cmdtxt(np->nclist.body);
4834 cmdputs(";; ");
4835 }
4836 p = "esac";
4837 goto dotail2;
4838 case NTO:
4839 p = ">";
4840 goto redir;
4841 case NCLOBBER:
4842 p = ">|";
4843 goto redir;
4844 case NAPPEND:
4845 p = ">>";
4846 goto redir;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01004847#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00004848 case NTO2:
4849#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004850 case NTOFD:
4851 p = ">&";
4852 goto redir;
4853 case NFROM:
4854 p = "<";
4855 goto redir;
4856 case NFROMFD:
4857 p = "<&";
4858 goto redir;
4859 case NFROMTO:
4860 p = "<>";
4861 redir:
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00004862 cmdputs(utoa(n->nfile.fd));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004863 cmdputs(p);
4864 if (n->type == NTOFD || n->type == NFROMFD) {
Denys Vlasenkod0fff912017-07-31 14:32:18 +02004865 if (n->ndup.dupfd >= 0)
4866 cmdputs(utoa(n->ndup.dupfd));
4867 else
4868 cmdputs("-");
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00004869 break;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004870 }
4871 n = n->nfile.fname;
4872 goto donode;
4873 }
4874}
4875
4876static char *
4877commandtext(union node *n)
4878{
4879 char *name;
4880
4881 STARTSTACKSTR(cmdnextc);
4882 cmdtxt(n);
4883 name = stackblock();
Denys Vlasenko6a94cee2016-10-25 17:40:25 +02004884 TRACE(("commandtext: name %p, end %p\n", name, cmdnextc));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004885 return ckstrdup(name);
4886}
4887#endif /* JOBS */
4888
4889/*
4890 * Fork off a subshell. If we are doing job control, give the subshell its
4891 * own process group. Jp is a job structure that the job is to be added to.
4892 * N is the command that will be evaluated by the child. Both jp and n may
4893 * be NULL. The mode parameter can be one of the following:
4894 * FORK_FG - Fork off a foreground process.
4895 * FORK_BG - Fork off a background process.
4896 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
4897 * process group even if job control is on.
4898 *
4899 * When job control is turned off, background processes have their standard
4900 * input redirected to /dev/null (except for the second and later processes
4901 * in a pipeline).
4902 *
4903 * Called with interrupts off.
4904 */
4905/*
4906 * Clear traps on a fork.
4907 */
4908static void
4909clear_traps(void)
4910{
4911 char **tp;
4912
Denys Vlasenkob4f51d32016-10-27 12:55:09 +02004913 INT_OFF;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004914 for (tp = trap; tp < &trap[NSIG]; tp++) {
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004915 if (*tp && **tp) { /* trap not NULL or "" (SIG_IGN) */
Denys Vlasenkoe305c282009-09-25 02:12:27 +02004916 if (trap_ptr == trap)
4917 free(*tp);
4918 /* else: it "belongs" to trap_ptr vector, don't free */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004919 *tp = NULL;
Denys Vlasenko0800e3a2009-09-24 03:09:26 +02004920 if ((tp - trap) != 0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004921 setsignal(tp - trap);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004922 }
4923 }
Alexander Shishkinccb97712010-07-25 13:07:39 +02004924 may_have_traps = 0;
Denys Vlasenkob4f51d32016-10-27 12:55:09 +02004925 INT_ON;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004926}
Denis Vlasenkobdc406d2007-07-15 01:13:25 +00004927
4928/* Lives far away from here, needed for forkchild */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004929static void closescript(void);
Denis Vlasenko41770222007-10-07 18:02:52 +00004930
Denis Vlasenkobdc406d2007-07-15 01:13:25 +00004931/* Called after fork(), in child */
Denys Vlasenko70392332016-10-27 02:31:55 +02004932/* jp and n are NULL when called by openhere() for heredoc support */
Denys Vlasenko21d87d42009-09-25 00:06:51 +02004933static NOINLINE void
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02004934forkchild(struct job *jp, union node *n, int mode)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004935{
4936 int oldlvl;
4937
4938 TRACE(("Child shell %d\n", getpid()));
4939 oldlvl = shlvl;
4940 shlvl++;
4941
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004942 /* man bash: "Non-builtin commands run by bash have signal handlers
4943 * set to the values inherited by the shell from its parent".
4944 * Do we do it correctly? */
4945
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004946 closescript();
Denys Vlasenko844f9902009-09-23 03:25:52 +02004947
4948 if (mode == FORK_NOJOB /* is it `xxx` ? */
4949 && n && n->type == NCMD /* is it single cmd? */
4950 /* && n->ncmd.args->type == NARG - always true? */
Denys Vlasenko74269202010-02-21 01:26:42 +01004951 && n->ncmd.args && strcmp(n->ncmd.args->narg.text, "trap") == 0
Denys Vlasenko844f9902009-09-23 03:25:52 +02004952 && n->ncmd.args->narg.next == NULL /* "trap" with no arguments */
4953 /* && n->ncmd.args->narg.backquote == NULL - do we need to check this? */
4954 ) {
4955 TRACE(("Trap hack\n"));
4956 /* Awful hack for `trap` or $(trap).
4957 *
4958 * http://www.opengroup.org/onlinepubs/009695399/utilities/trap.html
4959 * contains an example where "trap" is executed in a subshell:
4960 *
4961 * save_traps=$(trap)
4962 * ...
4963 * eval "$save_traps"
4964 *
4965 * Standard does not say that "trap" in subshell shall print
4966 * parent shell's traps. It only says that its output
4967 * must have suitable form, but then, in the above example
4968 * (which is not supposed to be normative), it implies that.
4969 *
4970 * bash (and probably other shell) does implement it
4971 * (traps are reset to defaults, but "trap" still shows them),
4972 * but as a result, "trap" logic is hopelessly messed up:
4973 *
4974 * # trap
4975 * trap -- 'echo Ho' SIGWINCH <--- we have a handler
4976 * # (trap) <--- trap is in subshell - no output (correct, traps are reset)
4977 * # true | trap <--- trap is in subshell - no output (ditto)
4978 * # echo `true | trap` <--- in subshell - output (but traps are reset!)
4979 * trap -- 'echo Ho' SIGWINCH
4980 * # echo `(trap)` <--- in subshell in subshell - output
4981 * trap -- 'echo Ho' SIGWINCH
4982 * # echo `true | (trap)` <--- in subshell in subshell in subshell - output!
4983 * trap -- 'echo Ho' SIGWINCH
4984 *
4985 * The rules when to forget and when to not forget traps
4986 * get really complex and nonsensical.
4987 *
4988 * Our solution: ONLY bare $(trap) or `trap` is special.
4989 */
Denys Vlasenko8f88d852009-09-25 12:12:53 +02004990 /* Save trap handler strings for trap builtin to print */
Ron Yorstond840c5d2015-07-19 23:05:20 +02004991 trap_ptr = xmemdup(trap, sizeof(trap));
Denys Vlasenko8f88d852009-09-25 12:12:53 +02004992 /* Fall through into clearing traps */
Denys Vlasenko844f9902009-09-23 03:25:52 +02004993 }
Denys Vlasenkoe305c282009-09-25 02:12:27 +02004994 clear_traps();
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004995#if JOBS
4996 /* do job control only in root shell */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00004997 doing_jobctl = 0;
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004998 if (mode != FORK_NOJOB && jp->jobctl && oldlvl == 0) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004999 pid_t pgrp;
5000
5001 if (jp->nprocs == 0)
5002 pgrp = getpid();
5003 else
Denys Vlasenko285ad152009-12-04 23:02:27 +01005004 pgrp = jp->ps[0].ps_pid;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005005 /* this can fail because we are doing it in the parent also */
5006 setpgid(0, pgrp);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005007 if (mode == FORK_FG)
5008 xtcsetpgrp(ttyfd, pgrp);
5009 setsignal(SIGTSTP);
5010 setsignal(SIGTTOU);
5011 } else
5012#endif
5013 if (mode == FORK_BG) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005014 /* man bash: "When job control is not in effect,
5015 * asynchronous commands ignore SIGINT and SIGQUIT" */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005016 ignoresig(SIGINT);
5017 ignoresig(SIGQUIT);
5018 if (jp->nprocs == 0) {
5019 close(0);
5020 if (open(bb_dev_null, O_RDONLY) != 0)
Denys Vlasenko12ffefb2017-08-23 14:52:56 +02005021 ash_msg_and_raise_perror("can't open '%s'", bb_dev_null);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005022 }
5023 }
Denys Vlasenkob12553f2011-02-21 03:22:20 +01005024 if (oldlvl == 0) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005025 if (iflag) { /* why if iflag only? */
5026 setsignal(SIGINT);
5027 setsignal(SIGTERM);
5028 }
5029 /* man bash:
5030 * "In all cases, bash ignores SIGQUIT. Non-builtin
5031 * commands run by bash have signal handlers
5032 * set to the values inherited by the shell
5033 * from its parent".
5034 * Take care of the second rule: */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005035 setsignal(SIGQUIT);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005036 }
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02005037#if JOBS
Denys Vlasenko844f9902009-09-23 03:25:52 +02005038 if (n && n->type == NCMD
Denys Vlasenko74269202010-02-21 01:26:42 +01005039 && n->ncmd.args && strcmp(n->ncmd.args->narg.text, "jobs") == 0
Denys Vlasenko844f9902009-09-23 03:25:52 +02005040 ) {
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02005041 TRACE(("Job hack\n"));
Denys Vlasenko844f9902009-09-23 03:25:52 +02005042 /* "jobs": we do not want to clear job list for it,
5043 * instead we remove only _its_ own_ job from job list.
5044 * This makes "jobs .... | cat" more useful.
5045 */
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02005046 freejob(curjob);
5047 return;
5048 }
5049#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005050 for (jp = curjob; jp; jp = jp->prev_job)
5051 freejob(jp);
5052 jobless = 0;
5053}
5054
Denis Vlasenkobdc406d2007-07-15 01:13:25 +00005055/* Called after fork(), in parent */
Denis Vlasenko85c24712008-03-17 09:04:04 +00005056#if !JOBS
5057#define forkparent(jp, n, mode, pid) forkparent(jp, mode, pid)
5058#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005059static void
5060forkparent(struct job *jp, union node *n, int mode, pid_t pid)
5061{
5062 TRACE(("In parent shell: child = %d\n", pid));
5063 if (!jp) {
Denys Vlasenko70392332016-10-27 02:31:55 +02005064 /* jp is NULL when called by openhere() for heredoc support */
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00005065 while (jobless && dowait(DOWAIT_NONBLOCK, NULL) > 0)
5066 continue;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005067 jobless++;
5068 return;
5069 }
5070#if JOBS
5071 if (mode != FORK_NOJOB && jp->jobctl) {
5072 int pgrp;
5073
5074 if (jp->nprocs == 0)
5075 pgrp = pid;
5076 else
Denys Vlasenko285ad152009-12-04 23:02:27 +01005077 pgrp = jp->ps[0].ps_pid;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005078 /* This can fail because we are doing it in the child also */
5079 setpgid(pid, pgrp);
5080 }
5081#endif
5082 if (mode == FORK_BG) {
5083 backgndpid = pid; /* set $! */
5084 set_curjob(jp, CUR_RUNNING);
5085 }
5086 if (jp) {
5087 struct procstat *ps = &jp->ps[jp->nprocs++];
Denys Vlasenko285ad152009-12-04 23:02:27 +01005088 ps->ps_pid = pid;
5089 ps->ps_status = -1;
5090 ps->ps_cmd = nullstr;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005091#if JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +00005092 if (doing_jobctl && n)
Denys Vlasenko285ad152009-12-04 23:02:27 +01005093 ps->ps_cmd = commandtext(n);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005094#endif
5095 }
5096}
5097
Denys Vlasenko70392332016-10-27 02:31:55 +02005098/* jp and n are NULL when called by openhere() for heredoc support */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005099static int
5100forkshell(struct job *jp, union node *n, int mode)
5101{
5102 int pid;
5103
5104 TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
5105 pid = fork();
5106 if (pid < 0) {
5107 TRACE(("Fork failed, errno=%d", errno));
5108 if (jp)
5109 freejob(jp);
Denys Vlasenko12ffefb2017-08-23 14:52:56 +02005110 ash_msg_and_raise_perror("can't fork");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005111 }
Denys Vlasenko76ace252009-10-12 15:25:01 +02005112 if (pid == 0) {
5113 CLEAR_RANDOM_T(&random_gen); /* or else $RANDOM repeats in child */
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02005114 forkchild(jp, n, mode);
Denys Vlasenko76ace252009-10-12 15:25:01 +02005115 } else {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005116 forkparent(jp, n, mode, pid);
Denys Vlasenko76ace252009-10-12 15:25:01 +02005117 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005118 return pid;
5119}
5120
5121/*
5122 * Wait for job to finish.
5123 *
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005124 * Under job control we have the problem that while a child process
5125 * is running interrupts generated by the user are sent to the child
5126 * but not to the shell. This means that an infinite loop started by
5127 * an interactive user may be hard to kill. With job control turned off,
5128 * an interactive user may place an interactive program inside a loop.
5129 * If the interactive program catches interrupts, the user doesn't want
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005130 * these interrupts to also abort the loop. The approach we take here
5131 * is to have the shell ignore interrupt signals while waiting for a
5132 * foreground process to terminate, and then send itself an interrupt
5133 * signal if the child process was terminated by an interrupt signal.
5134 * Unfortunately, some programs want to do a bit of cleanup and then
5135 * exit on interrupt; unless these processes terminate themselves by
5136 * sending a signal to themselves (instead of calling exit) they will
5137 * confuse this approach.
5138 *
5139 * Called with interrupts off.
5140 */
5141static int
5142waitforjob(struct job *jp)
5143{
5144 int st;
5145
5146 TRACE(("waitforjob(%%%d) called\n", jobno(jp)));
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005147
5148 INT_OFF;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005149 while (jp->state == JOBRUNNING) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005150 /* In non-interactive shells, we _can_ get
5151 * a keyboard signal here and be EINTRed,
5152 * but we just loop back, waiting for command to complete.
5153 *
5154 * man bash:
5155 * "If bash is waiting for a command to complete and receives
5156 * a signal for which a trap has been set, the trap
5157 * will not be executed until the command completes."
5158 *
5159 * Reality is that even if trap is not set, bash
5160 * will not act on the signal until command completes.
5161 * Try this. sleep5intoff.c:
5162 * #include <signal.h>
5163 * #include <unistd.h>
5164 * int main() {
5165 * sigset_t set;
5166 * sigemptyset(&set);
5167 * sigaddset(&set, SIGINT);
5168 * sigaddset(&set, SIGQUIT);
5169 * sigprocmask(SIG_BLOCK, &set, NULL);
5170 * sleep(5);
5171 * return 0;
5172 * }
5173 * $ bash -c './sleep5intoff; echo hi'
5174 * ^C^C^C^C <--- pressing ^C once a second
5175 * $ _
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005176 * $ bash -c './sleep5intoff; echo hi'
5177 * ^\^\^\^\hi <--- pressing ^\ (SIGQUIT)
5178 * $ _
5179 */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005180 dowait(DOWAIT_BLOCK, jp);
5181 }
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005182 INT_ON;
5183
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005184 st = getstatus(jp);
5185#if JOBS
5186 if (jp->jobctl) {
5187 xtcsetpgrp(ttyfd, rootpid);
Denys Vlasenko098b7132017-01-11 19:59:03 +01005188 restore_tty_if_stopped_or_signaled(jp);
5189
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005190 /*
5191 * This is truly gross.
5192 * If we're doing job control, then we did a TIOCSPGRP which
5193 * caused us (the shell) to no longer be in the controlling
5194 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
5195 * intuit from the subprocess exit status whether a SIGINT
5196 * occurred, and if so interrupt ourselves. Yuck. - mycroft
5197 */
Denis Vlasenko991a1da2008-02-10 19:02:53 +00005198 if (jp->sigint) /* TODO: do the same with all signals */
5199 raise(SIGINT); /* ... by raise(jp->sig) instead? */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005200 }
5201 if (jp->state == JOBDONE)
5202#endif
5203 freejob(jp);
5204 return st;
5205}
5206
5207/*
5208 * return 1 if there are stopped jobs, otherwise 0
5209 */
5210static int
5211stoppedjobs(void)
5212{
5213 struct job *jp;
5214 int retval;
5215
5216 retval = 0;
5217 if (job_warning)
5218 goto out;
5219 jp = curjob;
5220 if (jp && jp->state == JOBSTOPPED) {
5221 out2str("You have stopped jobs.\n");
5222 job_warning = 2;
5223 retval++;
5224 }
5225 out:
5226 return retval;
5227}
5228
5229
Denys Vlasenko70392332016-10-27 02:31:55 +02005230/*
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005231 * Code for dealing with input/output redirection.
5232 */
5233
Denys Vlasenko8d0e0cd2011-01-25 23:21:46 +01005234#undef EMPTY
5235#undef CLOSED
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005236#define EMPTY -2 /* marks an unused slot in redirtab */
Denys Vlasenko035486c2017-07-31 04:09:19 +02005237#define CLOSED -1 /* marks a slot of previously-closed fd */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005238
5239/*
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005240 * Handle here documents. Normally we fork off a process to write the
5241 * data to a pipe. If the document is short, we can stuff the data in
5242 * the pipe without forking.
5243 */
5244/* openhere needs this forward reference */
5245static void expandhere(union node *arg, int fd);
5246static int
5247openhere(union node *redir)
5248{
5249 int pip[2];
5250 size_t len = 0;
5251
5252 if (pipe(pip) < 0)
Denys Vlasenko12ffefb2017-08-23 14:52:56 +02005253 ash_msg_and_raise_perror("can't create pipe");
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005254 if (redir->type == NHERE) {
5255 len = strlen(redir->nhere.doc->narg.text);
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005256 if (len <= PIPE_BUF) {
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005257 full_write(pip[1], redir->nhere.doc->narg.text, len);
5258 goto out;
5259 }
5260 }
5261 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
Denis Vlasenko0b769642008-07-24 07:54:57 +00005262 /* child */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005263 close(pip[0]);
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005264 ignoresig(SIGINT); //signal(SIGINT, SIG_IGN);
5265 ignoresig(SIGQUIT); //signal(SIGQUIT, SIG_IGN);
5266 ignoresig(SIGHUP); //signal(SIGHUP, SIG_IGN);
5267 ignoresig(SIGTSTP); //signal(SIGTSTP, SIG_IGN);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005268 signal(SIGPIPE, SIG_DFL);
5269 if (redir->type == NHERE)
5270 full_write(pip[1], redir->nhere.doc->narg.text, len);
Denis Vlasenko0b769642008-07-24 07:54:57 +00005271 else /* NXHERE */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005272 expandhere(redir->nhere.doc, pip[1]);
Bernhard Reutner-Fischer636a1f82008-05-19 09:29:47 +00005273 _exit(EXIT_SUCCESS);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005274 }
5275 out:
5276 close(pip[1]);
5277 return pip[0];
5278}
5279
5280static int
5281openredirect(union node *redir)
5282{
Denys Vlasenkof1a5cb02017-07-25 17:47:48 +02005283 struct stat sb;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005284 char *fname;
5285 int f;
5286
5287 switch (redir->nfile.type) {
Denys Vlasenko557482c2016-09-25 21:24:04 +02005288/* Can't happen, our single caller does this itself */
5289// case NTOFD:
5290// case NFROMFD:
5291// return -1;
5292 case NHERE:
5293 case NXHERE:
5294 return openhere(redir);
5295 }
5296
5297 /* For N[X]HERE, reading redir->nfile.expfname would touch beyond
5298 * allocated space. Do it only when we know it is safe.
5299 */
5300 fname = redir->nfile.expfname;
5301
5302 switch (redir->nfile.type) {
5303 default:
5304#if DEBUG
5305 abort();
5306#endif
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005307 case NFROM:
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005308 f = open(fname, O_RDONLY);
5309 if (f < 0)
5310 goto eopen;
5311 break;
5312 case NFROMTO:
Andreas Bühmannda75f442010-06-24 04:32:37 +02005313 f = open(fname, O_RDWR|O_CREAT, 0666);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005314 if (f < 0)
5315 goto ecreate;
5316 break;
5317 case NTO:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01005318#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00005319 case NTO2:
5320#endif
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005321 /* Take care of noclobber mode. */
5322 if (Cflag) {
Denys Vlasenkof1a5cb02017-07-25 17:47:48 +02005323 if (stat(fname, &sb) < 0) {
5324 f = open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
5325 if (f < 0)
5326 goto ecreate;
5327 } else if (!S_ISREG(sb.st_mode)) {
5328 f = open(fname, O_WRONLY, 0666);
5329 if (f < 0)
5330 goto ecreate;
5331 if (fstat(f, &sb) < 0 && S_ISREG(sb.st_mode)) {
5332 close(f);
5333 errno = EEXIST;
5334 goto ecreate;
5335 }
5336 } else {
5337 errno = EEXIST;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005338 goto ecreate;
Denys Vlasenkof1a5cb02017-07-25 17:47:48 +02005339 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005340 break;
5341 }
5342 /* FALLTHROUGH */
5343 case NCLOBBER:
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005344 f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666);
5345 if (f < 0)
5346 goto ecreate;
5347 break;
5348 case NAPPEND:
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005349 f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666);
5350 if (f < 0)
5351 goto ecreate;
5352 break;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005353 }
5354
5355 return f;
5356 ecreate:
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +00005357 ash_msg_and_raise_error("can't create %s: %s", fname, errmsg(errno, "nonexistent directory"));
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005358 eopen:
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +00005359 ash_msg_and_raise_error("can't open %s: %s", fname, errmsg(errno, "no such file"));
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005360}
5361
5362/*
Denys Vlasenko64774602016-10-26 15:24:30 +02005363 * Copy a file descriptor to be >= 10. Throws exception on error.
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005364 */
5365static int
Denys Vlasenko64774602016-10-26 15:24:30 +02005366savefd(int from)
5367{
5368 int newfd;
5369 int err;
5370
5371 newfd = fcntl(from, F_DUPFD, 10);
5372 err = newfd < 0 ? errno : 0;
5373 if (err != EBADF) {
5374 if (err)
Ron Yorstonbe366e52017-07-27 13:53:39 +01005375 ash_msg_and_raise_perror("%d", from);
Denys Vlasenko64774602016-10-26 15:24:30 +02005376 close(from);
5377 fcntl(newfd, F_SETFD, FD_CLOEXEC);
5378 }
5379
5380 return newfd;
5381}
5382static int
5383dup2_or_raise(int from, int to)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005384{
5385 int newfd;
5386
Denys Vlasenko64774602016-10-26 15:24:30 +02005387 newfd = (from != to) ? dup2(from, to) : to;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005388 if (newfd < 0) {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005389 /* Happens when source fd is not open: try "echo >&99" */
Ron Yorstonbe366e52017-07-27 13:53:39 +01005390 ash_msg_and_raise_perror("%d", from);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005391 }
5392 return newfd;
5393}
Denys Vlasenko035486c2017-07-31 04:09:19 +02005394static int
5395fcntl_F_DUPFD(int fd, int avoid_fd)
5396{
5397 int newfd;
5398 repeat:
5399 newfd = fcntl(fd, F_DUPFD, avoid_fd + 1);
5400 if (newfd < 0) {
5401 if (errno == EBUSY)
5402 goto repeat;
5403 if (errno == EINTR)
5404 goto repeat;
5405 }
5406 return newfd;
5407}
5408static int
5409xdup_CLOEXEC_and_close(int fd, int avoid_fd)
5410{
5411 int newfd;
5412 repeat:
5413 newfd = fcntl(fd, F_DUPFD, avoid_fd + 1);
5414 if (newfd < 0) {
5415 if (errno == EBUSY)
5416 goto repeat;
5417 if (errno == EINTR)
5418 goto repeat;
5419 /* fd was not open? */
5420 if (errno == EBADF)
5421 return fd;
5422 ash_msg_and_raise_perror("%d", newfd);
5423 }
5424 fcntl(newfd, F_SETFD, FD_CLOEXEC);
5425 close(fd);
5426 return newfd;
5427}
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005428
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005429/* Struct def and variable are moved down to the first usage site */
Denys Vlasenko035486c2017-07-31 04:09:19 +02005430struct squirrel {
5431 int orig_fd;
5432 int moved_to;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005433};
Denis Vlasenko0b769642008-07-24 07:54:57 +00005434struct redirtab {
5435 struct redirtab *next;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005436 int pair_count;
Denys Vlasenko035486c2017-07-31 04:09:19 +02005437 struct squirrel two_fd[];
Denis Vlasenko0b769642008-07-24 07:54:57 +00005438};
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005439#define redirlist (G_var.redirlist)
Denis Vlasenko0b769642008-07-24 07:54:57 +00005440
Denys Vlasenko035486c2017-07-31 04:09:19 +02005441static void
5442add_squirrel_closed(struct redirtab *sq, int fd)
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005443{
5444 int i;
5445
Denys Vlasenko035486c2017-07-31 04:09:19 +02005446 if (!sq)
5447 return;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005448
Denys Vlasenko035486c2017-07-31 04:09:19 +02005449 for (i = 0; sq->two_fd[i].orig_fd != EMPTY; i++) {
5450 /* If we collide with an already moved fd... */
5451 if (fd == sq->two_fd[i].orig_fd) {
5452 /* Examples:
5453 * "echo 3>FILE 3>&- 3>FILE"
5454 * "echo 3>&- 3>FILE"
5455 * No need for last redirect to insert
5456 * another "need to close 3" indicator.
5457 */
5458 TRACE(("redirect_fd %d: already moved or closed\n", fd));
5459 return;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005460 }
5461 }
Denys Vlasenko035486c2017-07-31 04:09:19 +02005462 TRACE(("redirect_fd %d: previous fd was closed\n", fd));
5463 sq->two_fd[i].orig_fd = fd;
5464 sq->two_fd[i].moved_to = CLOSED;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005465}
5466
Denys Vlasenko37dc08b2016-10-02 04:38:07 +02005467static int
Denys Vlasenko035486c2017-07-31 04:09:19 +02005468save_fd_on_redirect(int fd, int avoid_fd, struct redirtab *sq)
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005469{
Denys Vlasenko035486c2017-07-31 04:09:19 +02005470 int i, new_fd;
Denis Vlasenko34c73c42008-08-16 11:48:02 +00005471
Denys Vlasenko035486c2017-07-31 04:09:19 +02005472 if (avoid_fd < 9) /* the important case here is that it can be -1 */
5473 avoid_fd = 9;
5474
5475#if JOBS
5476 if (fd == ttyfd) {
5477 /* Testcase: "ls -l /proc/$$/fd 10>&-" should work */
5478 ttyfd = xdup_CLOEXEC_and_close(ttyfd, avoid_fd);
5479 TRACE(("redirect_fd %d: matches ttyfd, moving it to %d\n", fd, ttyfd));
5480 return 1; /* "we closed fd" */
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005481 }
Denys Vlasenko035486c2017-07-31 04:09:19 +02005482#endif
5483 /* Are we called from redirect(0)? E.g. redirect
5484 * in a forked child. No need to save fds,
5485 * we aren't going to use them anymore, ok to trash.
5486 */
5487 if (!sq)
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005488 return 0;
Denys Vlasenko035486c2017-07-31 04:09:19 +02005489
5490 /* If this one of script's fds? */
5491 if (fd != 0) {
5492 struct parsefile *pf = g_parsefile;
5493 while (pf) {
5494 /* We skip fd == 0 case because of the following:
5495 * $ ash # running ash interactively
5496 * $ . ./script.sh
5497 * and in script.sh: "exec 9>&0".
5498 * Even though top-level pf_fd _is_ 0,
5499 * it's still ok to use it: "read" builtin uses it,
5500 * why should we cripple "exec" builtin?
5501 */
5502 if (fd == pf->pf_fd) {
5503 pf->pf_fd = xdup_CLOEXEC_and_close(fd, avoid_fd);
5504 return 1; /* "we closed fd" */
5505 }
5506 pf = pf->prev;
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005507 }
5508 }
Denys Vlasenko035486c2017-07-31 04:09:19 +02005509
5510 /* Check whether it collides with any open fds (e.g. stdio), save fds as needed */
5511
5512 /* First: do we collide with some already moved fds? */
5513 for (i = 0; sq->two_fd[i].orig_fd != EMPTY; i++) {
5514 /* If we collide with an already moved fd... */
5515 if (fd == sq->two_fd[i].moved_to) {
5516 new_fd = fcntl_F_DUPFD(fd, avoid_fd);
5517 sq->two_fd[i].moved_to = new_fd;
5518 TRACE(("redirect_fd %d: already busy, moving to %d\n", fd, new_fd));
5519 if (new_fd < 0) /* what? */
5520 xfunc_die();
5521 return 0; /* "we did not close fd" */
5522 }
5523 if (fd == sq->two_fd[i].orig_fd) {
5524 /* Example: echo Hello >/dev/null 1>&2 */
5525 TRACE(("redirect_fd %d: already moved\n", fd));
5526 return 0; /* "we did not close fd" */
5527 }
5528 }
5529
5530 /* If this fd is open, we move and remember it; if it's closed, new_fd = CLOSED (-1) */
5531 new_fd = fcntl_F_DUPFD(fd, avoid_fd);
5532 TRACE(("redirect_fd %d: previous fd is moved to %d (-1 if it was closed)\n", fd, new_fd));
5533 if (new_fd < 0) {
5534 if (errno != EBADF)
5535 xfunc_die();
5536 /* new_fd = CLOSED; - already is -1 */
5537 }
5538 sq->two_fd[i].moved_to = new_fd;
5539 sq->two_fd[i].orig_fd = fd;
5540
5541 /* if we move stderr, let "set -x" code know */
5542 if (fd == preverrout_fd)
5543 preverrout_fd = new_fd;
5544
5545 return 0; /* "we did not close fd" */
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005546}
5547
Denys Vlasenko32fdf2f2017-07-31 04:32:06 +02005548static int
5549internally_opened_fd(int fd, struct redirtab *sq)
5550{
5551 int i;
5552#if JOBS
5553 if (fd == ttyfd)
5554 return 1;
5555#endif
5556 /* If this one of script's fds? */
5557 if (fd != 0) {
5558 struct parsefile *pf = g_parsefile;
5559 while (pf) {
5560 if (fd == pf->pf_fd)
5561 return 1;
5562 pf = pf->prev;
5563 }
5564 }
5565
5566 if (sq) for (i = 0; i < sq->pair_count && sq->two_fd[i].orig_fd != EMPTY; i++) {
5567 if (fd == sq->two_fd[i].moved_to)
5568 return 1;
5569 }
5570 return 0;
5571}
5572
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005573/*
5574 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
5575 * old file descriptors are stashed away so that the redirection can be
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005576 * undone by calling popredir.
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005577 */
5578/* flags passed to redirect */
5579#define REDIR_PUSH 01 /* save previous values of file descriptors */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005580static void
5581redirect(union node *redir, int flags)
5582{
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005583 struct redirtab *sv;
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005584
Denys Vlasenko1c79aeb2017-07-29 22:51:52 +02005585 if (!redir)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005586 return;
Denys Vlasenko035486c2017-07-31 04:09:19 +02005587
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005588 sv = NULL;
5589 INT_OFF;
Denys Vlasenko1c79aeb2017-07-29 22:51:52 +02005590 if (flags & REDIR_PUSH)
5591 sv = redirlist;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005592 do {
Denys Vlasenko035486c2017-07-31 04:09:19 +02005593 int fd;
5594 int newfd;
5595 int close_fd;
5596 int closed;
5597
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00005598 fd = redir->nfile.fd;
Denis Vlasenko0b769642008-07-24 07:54:57 +00005599 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
Denys Vlasenko035486c2017-07-31 04:09:19 +02005600 //bb_error_msg("doing %d > %d", fd, newfd);
5601 newfd = redir->ndup.dupfd;
5602 close_fd = -1;
Denis Vlasenko0b769642008-07-24 07:54:57 +00005603 } else {
5604 newfd = openredirect(redir); /* always >= 0 */
5605 if (fd == newfd) {
Denys Vlasenko035486c2017-07-31 04:09:19 +02005606 /* open() gave us precisely the fd we wanted.
5607 * This means that this fd was not busy
5608 * (not opened to anywhere).
5609 * Remember to close it on restore:
5610 */
5611 add_squirrel_closed(sv, fd);
Denis Vlasenko0b769642008-07-24 07:54:57 +00005612 continue;
5613 }
Denys Vlasenko035486c2017-07-31 04:09:19 +02005614 close_fd = newfd;
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005615 }
Denys Vlasenko035486c2017-07-31 04:09:19 +02005616
5617 if (fd == newfd)
5618 continue;
5619
5620 /* if "N>FILE": move newfd to fd */
5621 /* if "N>&M": dup newfd to fd */
5622 /* if "N>&-": close fd (newfd is -1) */
5623
5624 IF_BASH_REDIR_OUTPUT(redirect_more:)
5625
5626 closed = save_fd_on_redirect(fd, /*avoid:*/ newfd, sv);
5627 if (newfd == -1) {
5628 /* "N>&-" means "close me" */
5629 if (!closed) {
5630 /* ^^^ optimization: saving may already
5631 * have closed it. If not... */
5632 close(fd);
Denis Vlasenko22f74142008-07-24 22:34:43 +00005633 }
Denys Vlasenko035486c2017-07-31 04:09:19 +02005634 } else {
Denys Vlasenko32fdf2f2017-07-31 04:32:06 +02005635 /* if newfd is a script fd or saved fd, simulate EBADF */
5636 if (internally_opened_fd(newfd, sv)) {
5637 errno = EBADF;
5638 ash_msg_and_raise_perror("%d", newfd);
5639 }
Denys Vlasenko64774602016-10-26 15:24:30 +02005640 dup2_or_raise(newfd, fd);
Denys Vlasenko035486c2017-07-31 04:09:19 +02005641 if (close_fd >= 0) /* "N>FILE" or ">&FILE" or heredoc? */
5642 close(close_fd);
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01005643#if BASH_REDIR_OUTPUT
Denys Vlasenko035486c2017-07-31 04:09:19 +02005644 if (redir->nfile.type == NTO2 && fd == 1) {
5645 /* ">&FILE". we already redirected to 1, now copy 1 to 2 */
5646 fd = 2;
5647 newfd = 1;
5648 close_fd = -1;
5649 goto redirect_more;
5650 }
Denis Vlasenko559691a2008-10-05 18:39:31 +00005651#endif
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005652 }
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00005653 } while ((redir = redir->nfile.next) != NULL);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005654 INT_ON;
Denys Vlasenkod07a15b2017-07-30 16:51:05 +02005655
5656//dash:#define REDIR_SAVEFD2 03 /* set preverrout */
5657#define REDIR_SAVEFD2 0
5658 // dash has a bug: since REDIR_SAVEFD2=3 and REDIR_PUSH=1, this test
5659 // triggers for pure REDIR_PUSH too. Thus, this is done almost always,
5660 // not only for calls with flags containing REDIR_SAVEFD2.
Denys Vlasenko035486c2017-07-31 04:09:19 +02005661 // We do this unconditionally (see save_fd_on_redirect()).
Denys Vlasenkod07a15b2017-07-30 16:51:05 +02005662 //if ((flags & REDIR_SAVEFD2) && copied_fd2 >= 0)
5663 // preverrout_fd = copied_fd2;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005664}
5665
Denys Vlasenko170f93e2017-07-29 18:54:53 +02005666static int
5667redirectsafe(union node *redir, int flags)
5668{
5669 int err;
5670 volatile int saveint;
5671 struct jmploc *volatile savehandler = exception_handler;
5672 struct jmploc jmploc;
5673
5674 SAVE_INT(saveint);
5675 /* "echo 9>/dev/null; echo >&9; echo result: $?" - result should be 1, not 2! */
Denys Vlasenko035486c2017-07-31 04:09:19 +02005676 err = setjmp(jmploc.loc); /* was = setjmp(jmploc.loc) * 2; */
Denys Vlasenko170f93e2017-07-29 18:54:53 +02005677 if (!err) {
5678 exception_handler = &jmploc;
5679 redirect(redir, flags);
5680 }
5681 exception_handler = savehandler;
5682 if (err && exception_type != EXERROR)
5683 longjmp(exception_handler->loc, 1);
5684 RESTORE_INT(saveint);
5685 return err;
5686}
5687
Denys Vlasenko1c79aeb2017-07-29 22:51:52 +02005688static struct redirtab*
5689pushredir(union node *redir)
5690{
5691 struct redirtab *sv;
5692 int i;
5693
5694 if (!redir)
5695 return redirlist;
5696
5697 i = 0;
5698 do {
5699 i++;
5700#if BASH_REDIR_OUTPUT
5701 if (redir->nfile.type == NTO2)
5702 i++;
5703#endif
5704 redir = redir->nfile.next;
5705 } while (redir);
5706
5707 sv = ckzalloc(sizeof(*sv) + i * sizeof(sv->two_fd[0]));
5708 sv->pair_count = i;
5709 while (--i >= 0)
Denys Vlasenko035486c2017-07-31 04:09:19 +02005710 sv->two_fd[i].orig_fd = sv->two_fd[i].moved_to = EMPTY;
Denys Vlasenko1c79aeb2017-07-29 22:51:52 +02005711 sv->next = redirlist;
5712 redirlist = sv;
5713 return sv->next;
5714}
5715
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005716/*
5717 * Undo the effects of the last redirection.
5718 */
5719static void
Denys Vlasenko035486c2017-07-31 04:09:19 +02005720popredir(int drop)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005721{
5722 struct redirtab *rp;
5723 int i;
5724
Denys Vlasenkoeaf94362016-10-25 21:46:03 +02005725 if (redirlist == NULL)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005726 return;
5727 INT_OFF;
5728 rp = redirlist;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005729 for (i = 0; i < rp->pair_count; i++) {
Denys Vlasenko035486c2017-07-31 04:09:19 +02005730 int fd = rp->two_fd[i].orig_fd;
5731 int copy = rp->two_fd[i].moved_to;
Denis Vlasenko22f74142008-07-24 22:34:43 +00005732 if (copy == CLOSED) {
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005733 if (!drop)
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005734 close(fd);
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005735 continue;
5736 }
Denis Vlasenko22f74142008-07-24 22:34:43 +00005737 if (copy != EMPTY) {
Denys Vlasenko035486c2017-07-31 04:09:19 +02005738 if (!drop) {
Denis Vlasenko5a867312008-07-24 19:46:38 +00005739 /*close(fd);*/
Denys Vlasenko64774602016-10-26 15:24:30 +02005740 dup2_or_raise(copy, fd);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005741 }
Denys Vlasenko035486c2017-07-31 04:09:19 +02005742 close(copy);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005743 }
5744 }
5745 redirlist = rp->next;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005746 free(rp);
5747 INT_ON;
5748}
5749
Denys Vlasenko1c79aeb2017-07-29 22:51:52 +02005750static void
5751unwindredir(struct redirtab *stop)
5752{
5753 while (redirlist != stop)
Denys Vlasenko035486c2017-07-31 04:09:19 +02005754 popredir(/*drop:*/ 0);
Denys Vlasenko1c79aeb2017-07-29 22:51:52 +02005755}
5756
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005757
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005758/* ============ Routines to expand arguments to commands
5759 *
5760 * We have to deal with backquotes, shell variables, and file metacharacters.
5761 */
5762
Denys Vlasenko0b883582016-12-23 16:49:07 +01005763#if ENABLE_FEATURE_SH_MATH
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005764static arith_t
5765ash_arith(const char *s)
5766{
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005767 arith_state_t math_state;
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005768 arith_t result;
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005769
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005770 math_state.lookupvar = lookupvar;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02005771 math_state.setvar = setvar0;
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005772 //math_state.endofname = endofname;
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005773
5774 INT_OFF;
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005775 result = arith(&math_state, s);
Denys Vlasenko063847d2010-09-15 13:33:02 +02005776 if (math_state.errmsg)
5777 ash_msg_and_raise_error(math_state.errmsg);
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005778 INT_ON;
5779
5780 return result;
5781}
Denis Vlasenko448d30e2008-06-27 00:24:11 +00005782#endif
Denys Vlasenkobaa41c72018-01-10 13:22:25 +01005783#if BASH_SUBSTR
5784# if ENABLE_FEATURE_SH_MATH
5785static int substr_atoi(const char *s)
5786{
5787 arith_t t = ash_arith(s);
5788 if (sizeof(t) > sizeof(int)) {
5789 /* clamp very large or very large negative nums for ${v:N:M}:
5790 * else "${v:0:0x100000001}" would work as "${v:0:1}"
5791 */
5792 if (t > INT_MAX)
5793 t = INT_MAX;
5794 if (t < INT_MIN)
5795 t = INT_MIN;
5796 }
5797 return t;
5798}
5799# else
5800# define substr_atoi(s) number(s)
5801# endif
5802#endif
Denis Vlasenko448d30e2008-06-27 00:24:11 +00005803
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005804/*
5805 * expandarg flags
5806 */
5807#define EXP_FULL 0x1 /* perform word splitting & file globbing */
5808#define EXP_TILDE 0x2 /* do normal tilde expansion */
5809#define EXP_VARTILDE 0x4 /* expand tildes in an assignment */
5810#define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */
Denys Vlasenkodb74c6c2016-10-24 21:12:33 +02005811/* ^^^^^^^^^^^^^^ this is meant to support constructs such as "cmd >file*.txt"
5812 * POSIX says for this case:
5813 * Pathname expansion shall not be performed on the word by a
5814 * non-interactive shell; an interactive shell may perform it, but shall
5815 * do so only when the expansion would result in one word.
5816 * Currently, our code complies to the above rule by never globbing
5817 * redirection filenames.
5818 * Bash performs globbing, unless it is non-interactive and in POSIX mode.
5819 * (this means that on a typical Linux distro, bash almost always
5820 * performs globbing, and thus diverges from what we do).
5821 */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005822#define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */
Ron Yorston549deab2015-05-18 09:57:51 +02005823#define EXP_QPAT 0x20 /* pattern in quoted parameter expansion */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005824#define EXP_VARTILDE2 0x40 /* expand tildes after colons only */
5825#define EXP_WORD 0x80 /* expand word in parameter expansion */
Ron Yorston3df47f92015-05-18 09:53:26 +02005826#define EXP_QUOTED 0x100 /* expand word in double quotes */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005827/*
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005828 * rmescape() flags
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005829 */
5830#define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
5831#define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005832#define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */
5833#define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */
5834
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005835/* Add CTLESC when necessary. */
Denys Vlasenko2990aa42017-07-25 17:37:57 +02005836#define QUOTES_ESC (EXP_FULL | EXP_CASE | EXP_QPAT)
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005837/* Do not skip NUL characters. */
5838#define QUOTES_KEEPNUL EXP_TILDE
5839
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005840/*
5841 * Structure specifying which parts of the string should be searched
5842 * for IFS characters.
5843 */
5844struct ifsregion {
5845 struct ifsregion *next; /* next region in list */
5846 int begoff; /* offset of start of region */
5847 int endoff; /* offset of end of region */
5848 int nulonly; /* search for nul bytes only */
5849};
5850
5851struct arglist {
5852 struct strlist *list;
5853 struct strlist **lastp;
5854};
5855
5856/* output of current string */
5857static char *expdest;
5858/* list of back quote expressions */
5859static struct nodelist *argbackq;
5860/* first struct in list of ifs regions */
5861static struct ifsregion ifsfirst;
5862/* last struct in list */
5863static struct ifsregion *ifslastp;
5864/* holds expanded arg list */
5865static struct arglist exparg;
5866
5867/*
5868 * Our own itoa().
Denys Vlasenkocf3a7962017-07-26 14:38:19 +02005869 * cvtnum() is used even if math support is off (to prepare $? values and such).
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005870 */
5871static int
5872cvtnum(arith_t num)
5873{
5874 int len;
5875
Denys Vlasenkocf3a7962017-07-26 14:38:19 +02005876 /* 32-bit and wider ints require buffer size of bytes*3 (or less) */
5877 len = sizeof(arith_t) * 3;
5878 /* If narrower: worst case, 1-byte ints: need 5 bytes: "-127<NUL>" */
5879 if (sizeof(arith_t) < 4) len += 2;
5880
5881 expdest = makestrspace(len, expdest);
5882 len = fmtstr(expdest, len, ARITH_FMT, num);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005883 STADJUST(len, expdest);
5884 return len;
5885}
5886
Denys Vlasenko455e4222016-10-27 14:45:13 +02005887/*
5888 * Break the argument string into pieces based upon IFS and add the
5889 * strings to the argument list. The regions of the string to be
5890 * searched for IFS characters have been stored by recordregion.
5891 */
5892static void
5893ifsbreakup(char *string, struct arglist *arglist)
5894{
5895 struct ifsregion *ifsp;
5896 struct strlist *sp;
5897 char *start;
5898 char *p;
5899 char *q;
5900 const char *ifs, *realifs;
5901 int ifsspc;
5902 int nulonly;
5903
5904 start = string;
5905 if (ifslastp != NULL) {
5906 ifsspc = 0;
5907 nulonly = 0;
5908 realifs = ifsset() ? ifsval() : defifs;
5909 ifsp = &ifsfirst;
5910 do {
5911 p = string + ifsp->begoff;
5912 nulonly = ifsp->nulonly;
5913 ifs = nulonly ? nullstr : realifs;
5914 ifsspc = 0;
5915 while (p < string + ifsp->endoff) {
5916 q = p;
5917 if ((unsigned char)*p == CTLESC)
5918 p++;
5919 if (!strchr(ifs, *p)) {
5920 p++;
5921 continue;
5922 }
5923 if (!nulonly)
5924 ifsspc = (strchr(defifs, *p) != NULL);
5925 /* Ignore IFS whitespace at start */
5926 if (q == start && ifsspc) {
5927 p++;
5928 start = p;
5929 continue;
5930 }
5931 *q = '\0';
5932 sp = stzalloc(sizeof(*sp));
5933 sp->text = start;
5934 *arglist->lastp = sp;
5935 arglist->lastp = &sp->next;
5936 p++;
5937 if (!nulonly) {
5938 for (;;) {
5939 if (p >= string + ifsp->endoff) {
5940 break;
5941 }
5942 q = p;
5943 if ((unsigned char)*p == CTLESC)
5944 p++;
5945 if (strchr(ifs, *p) == NULL) {
5946 p = q;
5947 break;
5948 }
5949 if (strchr(defifs, *p) == NULL) {
5950 if (ifsspc) {
5951 p++;
5952 ifsspc = 0;
5953 } else {
5954 p = q;
5955 break;
5956 }
5957 } else
5958 p++;
5959 }
5960 }
5961 start = p;
5962 } /* while */
5963 ifsp = ifsp->next;
5964 } while (ifsp != NULL);
5965 if (nulonly)
5966 goto add;
5967 }
5968
5969 if (!*start)
5970 return;
5971
5972 add:
5973 sp = stzalloc(sizeof(*sp));
5974 sp->text = start;
5975 *arglist->lastp = sp;
5976 arglist->lastp = &sp->next;
5977}
5978
5979static void
5980ifsfree(void)
5981{
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02005982 struct ifsregion *p = ifsfirst.next;
5983
5984 if (!p)
5985 goto out;
Denys Vlasenko455e4222016-10-27 14:45:13 +02005986
5987 INT_OFF;
Denys Vlasenko455e4222016-10-27 14:45:13 +02005988 do {
5989 struct ifsregion *ifsp;
5990 ifsp = p->next;
5991 free(p);
5992 p = ifsp;
5993 } while (p);
Denys Vlasenko455e4222016-10-27 14:45:13 +02005994 ifsfirst.next = NULL;
5995 INT_ON;
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02005996 out:
5997 ifslastp = NULL;
Denys Vlasenko455e4222016-10-27 14:45:13 +02005998}
5999
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006000static size_t
6001esclen(const char *start, const char *p)
6002{
6003 size_t esc = 0;
6004
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006005 while (p > start && (unsigned char)*--p == CTLESC) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006006 esc++;
6007 }
6008 return esc;
6009}
6010
6011/*
6012 * Remove any CTLESC characters from a string.
6013 */
Denys Vlasenko740058b2018-01-09 17:01:00 +01006014#if !BASH_PATTERN_SUBST
6015#define rmescapes(str, flag, slash_position) \
6016 rmescapes(str, flag)
6017#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006018static char *
Denys Vlasenko740058b2018-01-09 17:01:00 +01006019rmescapes(char *str, int flag, int *slash_position)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006020{
Ron Yorston417622c2015-05-18 09:59:14 +02006021 static const char qchars[] ALIGN1 = {
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006022 IF_BASH_PATTERN_SUBST('/',) CTLESC, CTLQUOTEMARK, '\0' };
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00006023
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006024 char *p, *q, *r;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006025 unsigned inquotes;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006026 unsigned protect_against_glob;
6027 unsigned globbing;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006028
Denys Vlasenko740058b2018-01-09 17:01:00 +01006029 p = strpbrk(str, qchars IF_BASH_PATTERN_SUBST(+ !slash_position));
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006030 if (!p)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006031 return str;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006032
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006033 q = p;
6034 r = str;
6035 if (flag & RMESCAPE_ALLOC) {
6036 size_t len = p - str;
6037 size_t fulllen = len + strlen(p) + 1;
6038
6039 if (flag & RMESCAPE_GROW) {
Colin Watson3963d942010-04-26 14:21:27 +02006040 int strloc = str - (char *)stackblock();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006041 r = makestrspace(fulllen, expdest);
Colin Watson3963d942010-04-26 14:21:27 +02006042 /* p and str may be invalidated by makestrspace */
6043 str = (char *)stackblock() + strloc;
6044 p = str + len;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006045 } else if (flag & RMESCAPE_HEAP) {
6046 r = ckmalloc(fulllen);
6047 } else {
6048 r = stalloc(fulllen);
6049 }
6050 q = r;
6051 if (len > 0) {
Denys Vlasenko5ace96a2017-07-23 21:46:02 +02006052 q = (char *)mempcpy(q, str, len);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006053 }
6054 }
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006055
Ron Yorston549deab2015-05-18 09:57:51 +02006056 inquotes = 0;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006057 globbing = flag & RMESCAPE_GLOB;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006058 protect_against_glob = globbing;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006059 while (*p) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006060 if ((unsigned char)*p == CTLQUOTEMARK) {
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006061// Note: both inquotes and protect_against_glob only affect whether
Denys Vlasenkofda9faf2017-07-05 19:10:21 +02006062// CTLESC,<ch> gets converted to <ch> or to \<ch>
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006063 inquotes = ~inquotes;
6064 p++;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006065 protect_against_glob = globbing;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006066 continue;
6067 }
Ron Yorston549deab2015-05-18 09:57:51 +02006068 if ((unsigned char)*p == CTLESC) {
6069 p++;
Denys Vlasenko13f20912016-09-25 20:54:25 +02006070#if DEBUG
6071 if (*p == '\0')
6072 ash_msg_and_raise_error("CTLESC at EOL (shouldn't happen)");
6073#endif
Ron Yorston549deab2015-05-18 09:57:51 +02006074 if (protect_against_glob) {
Denys Vlasenkofda9faf2017-07-05 19:10:21 +02006075 /*
6076 * We used to trust glob() and fnmatch() to eat
6077 * superfluous escapes (\z where z has no
6078 * special meaning anyway). But this causes
6079 * bugs such as string of one greek letter rho
Denys Vlasenkoed79a632017-07-05 19:20:43 +02006080 * (unicode-encoded as two bytes "cf,81")
Denys Vlasenkofda9faf2017-07-05 19:10:21 +02006081 * getting encoded as "cf,CTLESC,81"
6082 * and here, converted to "cf,\,81" -
6083 * which does not go well with some flavors
Denys Vlasenko92b8d9c2017-07-05 19:13:44 +02006084 * of fnmatch() in unicode locales
6085 * (for example, glibc <= 2.22).
Denys Vlasenkofda9faf2017-07-05 19:10:21 +02006086 *
6087 * Lets add "\" only on the chars which need it.
Denys Vlasenko4142f012017-07-05 22:19:28 +02006088 * Testcases for less obvious chars are shown.
Denys Vlasenkofda9faf2017-07-05 19:10:21 +02006089 */
6090 if (*p == '*'
6091 || *p == '?'
6092 || *p == '['
Denys Vlasenko4142f012017-07-05 22:19:28 +02006093 || *p == '\\' /* case '\' in \\ ) echo ok;; *) echo WRONG;; esac */
6094 || *p == ']' /* case ']' in [a\]] ) echo ok;; *) echo WRONG;; esac */
6095 || *p == '-' /* case '-' in [a\-c]) echo ok;; *) echo WRONG;; esac */
6096 || *p == '!' /* case '!' in [\!] ) echo ok;; *) echo WRONG;; esac */
6097 /* Some libc support [^negate], that's why "^" also needs love */
6098 || *p == '^' /* case '^' in [\^] ) echo ok;; *) echo WRONG;; esac */
Denys Vlasenkofda9faf2017-07-05 19:10:21 +02006099 ) {
6100 *q++ = '\\';
6101 }
Ron Yorston549deab2015-05-18 09:57:51 +02006102 }
6103 } else if (*p == '\\' && !inquotes) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006104 /* naked back slash */
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006105 protect_against_glob = 0;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006106 goto copy;
6107 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006108#if BASH_PATTERN_SUBST
Denys Vlasenko740058b2018-01-09 17:01:00 +01006109 else if (slash_position && p == str + *slash_position) {
6110 /* stop handling globbing */
6111 globbing = 0;
6112 *slash_position = q - r;
6113 slash_position = NULL;
Ron Yorston417622c2015-05-18 09:59:14 +02006114 }
6115#endif
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006116 protect_against_glob = globbing;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006117 copy:
6118 *q++ = *p++;
6119 }
6120 *q = '\0';
6121 if (flag & RMESCAPE_GROW) {
6122 expdest = r;
6123 STADJUST(q - r + 1, expdest);
6124 }
6125 return r;
6126}
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006127#define pmatch(a, b) !fnmatch((a), (b), 0)
6128
6129/*
6130 * Prepare a pattern for a expmeta (internal glob(3)) call.
6131 *
6132 * Returns an stalloced string.
6133 */
6134static char *
Ron Yorston549deab2015-05-18 09:57:51 +02006135preglob(const char *pattern, int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006136{
Denys Vlasenko740058b2018-01-09 17:01:00 +01006137 return rmescapes((char *)pattern, flag | RMESCAPE_GLOB, NULL);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006138}
6139
6140/*
6141 * Put a string on the stack.
6142 */
6143static void
6144memtodest(const char *p, size_t len, int syntax, int quotes)
6145{
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006146 char *q;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006147
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006148 if (!len)
6149 return;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006150
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006151 q = makestrspace((quotes & QUOTES_ESC) ? len * 2 : len, expdest);
6152
6153 do {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006154 unsigned char c = *p++;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006155 if (c) {
Denys Vlasenko2fe66b12016-12-12 17:39:12 +01006156 if (quotes & QUOTES_ESC) {
6157 int n = SIT(c, syntax);
6158 if (n == CCTL
6159 || (((quotes & EXP_FULL) || syntax != BASESYNTAX)
6160 && n == CBACK
6161 )
6162 ) {
6163 USTPUTC(CTLESC, q);
6164 }
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02006165 }
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006166 } else if (!(quotes & QUOTES_KEEPNUL))
6167 continue;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006168 USTPUTC(c, q);
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006169 } while (--len);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006170
6171 expdest = q;
6172}
6173
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006174static size_t
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006175strtodest(const char *p, int syntax, int quotes)
6176{
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006177 size_t len = strlen(p);
6178 memtodest(p, len, syntax, quotes);
6179 return len;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006180}
6181
6182/*
6183 * Record the fact that we have to scan this region of the
6184 * string for IFS characters.
6185 */
6186static void
6187recordregion(int start, int end, int nulonly)
6188{
6189 struct ifsregion *ifsp;
6190
6191 if (ifslastp == NULL) {
6192 ifsp = &ifsfirst;
6193 } else {
6194 INT_OFF;
Denis Vlasenko597906c2008-02-20 16:38:54 +00006195 ifsp = ckzalloc(sizeof(*ifsp));
6196 /*ifsp->next = NULL; - ckzalloc did it */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006197 ifslastp->next = ifsp;
6198 INT_ON;
6199 }
6200 ifslastp = ifsp;
6201 ifslastp->begoff = start;
6202 ifslastp->endoff = end;
6203 ifslastp->nulonly = nulonly;
6204}
6205
6206static void
6207removerecordregions(int endoff)
6208{
6209 if (ifslastp == NULL)
6210 return;
6211
6212 if (ifsfirst.endoff > endoff) {
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006213 while (ifsfirst.next) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006214 struct ifsregion *ifsp;
6215 INT_OFF;
6216 ifsp = ifsfirst.next->next;
6217 free(ifsfirst.next);
6218 ifsfirst.next = ifsp;
6219 INT_ON;
6220 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006221 if (ifsfirst.begoff > endoff) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006222 ifslastp = NULL;
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006223 } else {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006224 ifslastp = &ifsfirst;
6225 ifsfirst.endoff = endoff;
6226 }
6227 return;
6228 }
6229
6230 ifslastp = &ifsfirst;
6231 while (ifslastp->next && ifslastp->next->begoff < endoff)
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006232 ifslastp = ifslastp->next;
6233 while (ifslastp->next) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006234 struct ifsregion *ifsp;
6235 INT_OFF;
6236 ifsp = ifslastp->next->next;
6237 free(ifslastp->next);
6238 ifslastp->next = ifsp;
6239 INT_ON;
6240 }
6241 if (ifslastp->endoff > endoff)
6242 ifslastp->endoff = endoff;
6243}
6244
6245static char *
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006246exptilde(char *startp, char *p, int flags)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006247{
Denys Vlasenkocd716832009-11-28 22:14:02 +01006248 unsigned char c;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006249 char *name;
6250 struct passwd *pw;
6251 const char *home;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006252 int quotes = flags & QUOTES_ESC;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006253
6254 name = p + 1;
6255
6256 while ((c = *++p) != '\0') {
6257 switch (c) {
6258 case CTLESC:
6259 return startp;
6260 case CTLQUOTEMARK:
6261 return startp;
6262 case ':':
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006263 if (flags & EXP_VARTILDE)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006264 goto done;
6265 break;
6266 case '/':
6267 case CTLENDVAR:
6268 goto done;
6269 }
6270 }
6271 done:
6272 *p = '\0';
6273 if (*name == '\0') {
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02006274 home = lookupvar("HOME");
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006275 } else {
6276 pw = getpwnam(name);
6277 if (pw == NULL)
6278 goto lose;
6279 home = pw->pw_dir;
6280 }
6281 if (!home || !*home)
6282 goto lose;
6283 *p = c;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006284 strtodest(home, SQSYNTAX, quotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006285 return p;
6286 lose:
6287 *p = c;
6288 return startp;
6289}
6290
6291/*
6292 * Execute a command inside back quotes. If it's a builtin command, we
6293 * want to save its output in a block obtained from malloc. Otherwise
6294 * we fork off a subprocess and get the output of the command via a pipe.
6295 * Should be called with interrupts off.
6296 */
6297struct backcmd { /* result of evalbackcmd */
6298 int fd; /* file descriptor to read from */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006299 int nleft; /* number of chars in buffer */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00006300 char *buf; /* buffer */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006301 struct job *jp; /* job structure for command */
6302};
6303
6304/* These forward decls are needed to use "eval" code for backticks handling: */
Denys Vlasenko1e3e2cc2017-07-25 20:31:14 +02006305/* flags in argument to evaltree */
6306#define EV_EXIT 01 /* exit after evaluating tree */
6307#define EV_TESTED 02 /* exit status is checked; ignore -e flag */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02006308static int evaltree(union node *, int);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006309
Denys Vlasenko619d9b52017-07-28 15:28:33 +02006310/* An evaltree() which is known to never return.
6311 * Used to use an alias:
6312 * static int evaltreenr(union node *, int) __attribute__((alias("evaltree"),__noreturn__));
6313 * but clang was reported to "transfer" noreturn-ness to evaltree() as well.
6314 */
6315static ALWAYS_INLINE NORETURN void
6316evaltreenr(union node *n, int flags)
6317{
6318 evaltree(n, flags);
6319 bb_unreachable(abort());
6320 /* NOTREACHED */
6321}
6322
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02006323static void FAST_FUNC
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006324evalbackcmd(union node *n, struct backcmd *result)
6325{
Denys Vlasenko579ad102016-10-25 21:10:20 +02006326 int pip[2];
6327 struct job *jp;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006328
6329 result->fd = -1;
6330 result->buf = NULL;
6331 result->nleft = 0;
6332 result->jp = NULL;
Denys Vlasenko579ad102016-10-25 21:10:20 +02006333 if (n == NULL) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006334 goto out;
Denys Vlasenko579ad102016-10-25 21:10:20 +02006335 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006336
Denys Vlasenko579ad102016-10-25 21:10:20 +02006337 if (pipe(pip) < 0)
Denys Vlasenko12ffefb2017-08-23 14:52:56 +02006338 ash_msg_and_raise_perror("can't create pipe");
Denys Vlasenko579ad102016-10-25 21:10:20 +02006339 jp = makejob(/*n,*/ 1);
6340 if (forkshell(jp, n, FORK_NOJOB) == 0) {
Denys Vlasenko70392332016-10-27 02:31:55 +02006341 /* child */
Denys Vlasenko579ad102016-10-25 21:10:20 +02006342 FORCE_INT_ON;
6343 close(pip[0]);
6344 if (pip[1] != 1) {
6345 /*close(1);*/
Denys Vlasenko64774602016-10-26 15:24:30 +02006346 dup2_or_raise(pip[1], 1);
Denys Vlasenko579ad102016-10-25 21:10:20 +02006347 close(pip[1]);
6348 }
Denys Vlasenko960ca382016-10-25 18:12:15 +02006349/* TODO: eflag clearing makes the following not abort:
6350 * ash -c 'set -e; z=$(false;echo foo); echo $z'
6351 * which is what bash does (unless it is in POSIX mode).
6352 * dash deleted "eflag = 0" line in the commit
6353 * Date: Mon, 28 Jun 2010 17:11:58 +1000
6354 * [EVAL] Don't clear eflag in evalbackcmd
6355 * For now, preserve bash-like behavior, it seems to be somewhat more useful:
6356 */
Denys Vlasenko579ad102016-10-25 21:10:20 +02006357 eflag = 0;
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02006358 ifsfree();
Denys Vlasenko619d9b52017-07-28 15:28:33 +02006359 evaltreenr(n, EV_EXIT);
Denys Vlasenko579ad102016-10-25 21:10:20 +02006360 /* NOTREACHED */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006361 }
Denys Vlasenko70392332016-10-27 02:31:55 +02006362 /* parent */
Denys Vlasenko579ad102016-10-25 21:10:20 +02006363 close(pip[1]);
6364 result->fd = pip[0];
6365 result->jp = jp;
6366
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006367 out:
6368 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
6369 result->fd, result->buf, result->nleft, result->jp));
6370}
6371
6372/*
6373 * Expand stuff in backwards quotes.
6374 */
6375static void
Ron Yorston549deab2015-05-18 09:57:51 +02006376expbackq(union node *cmd, int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006377{
6378 struct backcmd in;
6379 int i;
6380 char buf[128];
6381 char *p;
6382 char *dest;
6383 int startloc;
Ron Yorston549deab2015-05-18 09:57:51 +02006384 int syntax = flag & EXP_QUOTED ? DQSYNTAX : BASESYNTAX;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006385 struct stackmark smark;
6386
6387 INT_OFF;
Denys Vlasenko60ca8342016-09-30 11:21:21 +02006388 startloc = expdest - (char *)stackblock();
6389 pushstackmark(&smark, startloc);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006390 evalbackcmd(cmd, &in);
6391 popstackmark(&smark);
6392
6393 p = in.buf;
6394 i = in.nleft;
6395 if (i == 0)
6396 goto read;
6397 for (;;) {
Ron Yorston549deab2015-05-18 09:57:51 +02006398 memtodest(p, i, syntax, flag & QUOTES_ESC);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006399 read:
6400 if (in.fd < 0)
6401 break;
Ron Yorston61d6ae22015-04-19 10:50:25 +01006402 i = nonblock_immune_read(in.fd, buf, sizeof(buf));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006403 TRACE(("expbackq: read returns %d\n", i));
6404 if (i <= 0)
6405 break;
6406 p = buf;
6407 }
6408
Denis Vlasenko60818682007-09-28 22:07:23 +00006409 free(in.buf);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006410 if (in.fd >= 0) {
6411 close(in.fd);
6412 back_exitstatus = waitforjob(in.jp);
6413 }
6414 INT_ON;
6415
6416 /* Eat all trailing newlines */
6417 dest = expdest;
6418 for (; dest > (char *)stackblock() && dest[-1] == '\n';)
6419 STUNPUTC(dest);
6420 expdest = dest;
6421
Ron Yorston549deab2015-05-18 09:57:51 +02006422 if (!(flag & EXP_QUOTED))
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006423 recordregion(startloc, dest - (char *)stackblock(), 0);
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006424 TRACE(("evalbackq: size:%d:'%.*s'\n",
6425 (int)((dest - (char *)stackblock()) - startloc),
6426 (int)((dest - (char *)stackblock()) - startloc),
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006427 stackblock() + startloc));
6428}
6429
Denys Vlasenko0b883582016-12-23 16:49:07 +01006430#if ENABLE_FEATURE_SH_MATH
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006431/*
6432 * Expand arithmetic expression. Backup to start of expression,
6433 * evaluate, place result in (backed up) result, adjust string position.
6434 */
6435static void
Ron Yorston549deab2015-05-18 09:57:51 +02006436expari(int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006437{
6438 char *p, *start;
6439 int begoff;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006440 int len;
6441
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006442 /* ifsfree(); */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006443
6444 /*
6445 * This routine is slightly over-complicated for
6446 * efficiency. Next we scan backwards looking for the
6447 * start of arithmetic.
6448 */
6449 start = stackblock();
6450 p = expdest - 1;
6451 *p = '\0';
6452 p--;
Denys Vlasenko940c7202011-03-02 04:07:14 +01006453 while (1) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006454 int esc;
6455
Denys Vlasenkocd716832009-11-28 22:14:02 +01006456 while ((unsigned char)*p != CTLARI) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006457 p--;
6458#if DEBUG
6459 if (p < start) {
6460 ash_msg_and_raise_error("missing CTLARI (shouldn't happen)");
6461 }
6462#endif
6463 }
6464
6465 esc = esclen(start, p);
6466 if (!(esc % 2)) {
6467 break;
6468 }
6469
6470 p -= esc + 1;
Denys Vlasenko940c7202011-03-02 04:07:14 +01006471 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006472
6473 begoff = p - start;
6474
6475 removerecordregions(begoff);
6476
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006477 expdest = p;
6478
Ron Yorston549deab2015-05-18 09:57:51 +02006479 if (flag & QUOTES_ESC)
Denys Vlasenko740058b2018-01-09 17:01:00 +01006480 rmescapes(p + 1, 0, NULL);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006481
Ron Yorston549deab2015-05-18 09:57:51 +02006482 len = cvtnum(ash_arith(p + 1));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006483
Ron Yorston549deab2015-05-18 09:57:51 +02006484 if (!(flag & EXP_QUOTED))
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006485 recordregion(begoff, begoff + len, 0);
6486}
6487#endif
6488
6489/* argstr needs it */
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02006490static char *evalvar(char *p, int flags);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006491
6492/*
6493 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
6494 * characters to allow for further processing. Otherwise treat
6495 * $@ like $* since no splitting will be performed.
6496 */
6497static void
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02006498argstr(char *p, int flags)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006499{
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00006500 static const char spclchars[] ALIGN1 = {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006501 '=',
6502 ':',
6503 CTLQUOTEMARK,
6504 CTLENDVAR,
6505 CTLESC,
6506 CTLVAR,
6507 CTLBACKQ,
Denys Vlasenko0b883582016-12-23 16:49:07 +01006508#if ENABLE_FEATURE_SH_MATH
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006509 CTLENDARI,
6510#endif
Denys Vlasenkocd716832009-11-28 22:14:02 +01006511 '\0'
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006512 };
6513 const char *reject = spclchars;
Ron Yorston3df47f92015-05-18 09:53:26 +02006514 int breakall = (flags & (EXP_WORD | EXP_QUOTED)) == EXP_WORD;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006515 int inquotes;
6516 size_t length;
6517 int startloc;
6518
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006519 if (!(flags & EXP_VARTILDE)) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006520 reject += 2;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006521 } else if (flags & EXP_VARTILDE2) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006522 reject++;
6523 }
6524 inquotes = 0;
6525 length = 0;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006526 if (flags & EXP_TILDE) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006527 char *q;
6528
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006529 flags &= ~EXP_TILDE;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006530 tilde:
6531 q = p;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006532 if (*q == '~')
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006533 p = exptilde(p, q, flags);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006534 }
6535 start:
6536 startloc = expdest - (char *)stackblock();
6537 for (;;) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006538 unsigned char c;
6539
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006540 length += strcspn(p + length, reject);
Denys Vlasenkocd716832009-11-28 22:14:02 +01006541 c = p[length];
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006542 if (c) {
6543 if (!(c & 0x80)
Denys Vlasenko0b883582016-12-23 16:49:07 +01006544 IF_FEATURE_SH_MATH(|| c == CTLENDARI)
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006545 ) {
6546 /* c == '=' || c == ':' || c == CTLENDARI */
6547 length++;
6548 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006549 }
6550 if (length > 0) {
6551 int newloc;
6552 expdest = stack_nputstr(p, length, expdest);
6553 newloc = expdest - (char *)stackblock();
6554 if (breakall && !inquotes && newloc > startloc) {
6555 recordregion(startloc, newloc, 0);
6556 }
6557 startloc = newloc;
6558 }
6559 p += length + 1;
6560 length = 0;
6561
6562 switch (c) {
6563 case '\0':
6564 goto breakloop;
6565 case '=':
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006566 if (flags & EXP_VARTILDE2) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006567 p--;
6568 continue;
6569 }
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006570 flags |= EXP_VARTILDE2;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006571 reject++;
6572 /* fall through */
6573 case ':':
6574 /*
6575 * sort of a hack - expand tildes in variable
6576 * assignments (after the first '=' and after ':'s).
6577 */
6578 if (*--p == '~') {
6579 goto tilde;
6580 }
6581 continue;
6582 }
6583
6584 switch (c) {
6585 case CTLENDVAR: /* ??? */
6586 goto breakloop;
6587 case CTLQUOTEMARK:
Ron Yorston549deab2015-05-18 09:57:51 +02006588 inquotes ^= EXP_QUOTED;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006589 /* "$@" syntax adherence hack */
Ron Yorston549deab2015-05-18 09:57:51 +02006590 if (inquotes && !memcmp(p, dolatstr + 1, DOLATSTRLEN - 1)) {
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02006591 p = evalvar(p + 1, flags | inquotes) + 1;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006592 goto start;
6593 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006594 addquote:
Ron Yorston549deab2015-05-18 09:57:51 +02006595 if (flags & QUOTES_ESC) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006596 p--;
6597 length++;
6598 startloc++;
6599 }
6600 break;
6601 case CTLESC:
6602 startloc++;
6603 length++;
Ron Yorston549deab2015-05-18 09:57:51 +02006604
6605 /*
6606 * Quoted parameter expansion pattern: remove quote
6607 * unless inside inner quotes or we have a literal
6608 * backslash.
6609 */
6610 if (((flags | inquotes) & (EXP_QPAT | EXP_QUOTED)) ==
6611 EXP_QPAT && *p != '\\')
6612 break;
6613
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006614 goto addquote;
6615 case CTLVAR:
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02006616 TRACE(("argstr: evalvar('%s')\n", p));
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02006617 p = evalvar(p, flags | inquotes);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02006618 TRACE(("argstr: evalvar:'%s'\n", (char *)stackblock()));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006619 goto start;
6620 case CTLBACKQ:
Ron Yorston549deab2015-05-18 09:57:51 +02006621 expbackq(argbackq->n, flags | inquotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006622 argbackq = argbackq->next;
6623 goto start;
Denys Vlasenko0b883582016-12-23 16:49:07 +01006624#if ENABLE_FEATURE_SH_MATH
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006625 case CTLENDARI:
6626 p--;
Ron Yorston549deab2015-05-18 09:57:51 +02006627 expari(flags | inquotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006628 goto start;
6629#endif
6630 }
6631 }
Denys Vlasenko958581a2010-09-12 15:04:27 +02006632 breakloop: ;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006633}
6634
6635static char *
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006636scanleft(char *startp, char *rmesc, char *rmescend UNUSED_PARAM,
6637 char *pattern, int quotes, int zero)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006638{
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006639 char *loc, *loc2;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006640 char c;
6641
6642 loc = startp;
6643 loc2 = rmesc;
6644 do {
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006645 int match;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006646 const char *s = loc2;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006647
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006648 c = *loc2;
6649 if (zero) {
6650 *loc2 = '\0';
6651 s = rmesc;
6652 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006653 match = pmatch(pattern, s);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006654
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006655 *loc2 = c;
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006656 if (match)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006657 return loc;
Denys Vlasenkocd716832009-11-28 22:14:02 +01006658 if (quotes && (unsigned char)*loc == CTLESC)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006659 loc++;
6660 loc++;
6661 loc2++;
6662 } while (c);
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006663 return NULL;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006664}
6665
6666static char *
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006667scanright(char *startp, char *rmesc, char *rmescend,
6668 char *pattern, int quotes, int match_at_start)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006669{
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006670#if !ENABLE_ASH_OPTIMIZE_FOR_SIZE
6671 int try2optimize = match_at_start;
6672#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006673 int esc = 0;
6674 char *loc;
6675 char *loc2;
6676
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006677 /* If we called by "${v/pattern/repl}" or "${v//pattern/repl}":
6678 * startp="escaped_value_of_v" rmesc="raw_value_of_v"
6679 * rmescend=""(ptr to NUL in rmesc) pattern="pattern" quotes=match_at_start=1
6680 * Logic:
6681 * loc starts at NUL at the end of startp, loc2 starts at the end of rmesc,
6682 * and on each iteration they go back two/one char until they reach the beginning.
6683 * We try to find a match in "raw_value_of_v", "raw_value_of_", "raw_value_of" etc.
6684 */
6685 /* TODO: document in what other circumstances we are called. */
6686
6687 for (loc = pattern - 1, loc2 = rmescend; loc >= startp; loc2--) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006688 int match;
6689 char c = *loc2;
6690 const char *s = loc2;
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006691 if (match_at_start) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006692 *loc2 = '\0';
6693 s = rmesc;
6694 }
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006695 match = pmatch(pattern, s);
6696 //bb_error_msg("pmatch(pattern:'%s',s:'%s'):%d", pattern, s, match);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006697 *loc2 = c;
6698 if (match)
6699 return loc;
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006700#if !ENABLE_ASH_OPTIMIZE_FOR_SIZE
6701 if (try2optimize) {
6702 /* Maybe we can optimize this:
6703 * if pattern ends with unescaped *, we can avoid checking
Denys Vlasenko10ad6222017-04-17 16:13:32 +02006704 * shorter strings: if "foo*" doesn't match "raw_value_of_v",
6705 * it won't match truncated "raw_value_of_" strings too.
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006706 */
6707 unsigned plen = strlen(pattern);
6708 /* Does it end with "*"? */
6709 if (plen != 0 && pattern[--plen] == '*') {
6710 /* "xxxx*" is not escaped */
6711 /* "xxx\*" is escaped */
6712 /* "xx\\*" is not escaped */
6713 /* "x\\\*" is escaped */
6714 int slashes = 0;
6715 while (plen != 0 && pattern[--plen] == '\\')
6716 slashes++;
6717 if (!(slashes & 1))
6718 break; /* ends with unescaped "*" */
6719 }
6720 try2optimize = 0;
6721 }
6722#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006723 loc--;
6724 if (quotes) {
6725 if (--esc < 0) {
6726 esc = esclen(startp, loc);
6727 }
6728 if (esc % 2) {
6729 esc--;
6730 loc--;
6731 }
6732 }
6733 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006734 return NULL;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006735}
6736
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00006737static void varunset(const char *, const char *, const char *, int) NORETURN;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006738static void
6739varunset(const char *end, const char *var, const char *umsg, int varflags)
6740{
6741 const char *msg;
6742 const char *tail;
6743
6744 tail = nullstr;
6745 msg = "parameter not set";
6746 if (umsg) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006747 if ((unsigned char)*end == CTLENDVAR) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006748 if (varflags & VSNUL)
6749 tail = " or null";
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006750 } else {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006751 msg = umsg;
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006752 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006753 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006754 ash_msg_and_raise_error("%.*s: %s%s", (int)(end - var - 1), var, msg, tail);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006755}
6756
6757static const char *
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006758subevalvar(char *p, char *varname, int strloc, int subtype,
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02006759 int startloc, int varflags, int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006760{
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006761 struct nodelist *saveargbackq = argbackq;
Ron Yorston549deab2015-05-18 09:57:51 +02006762 int quotes = flag & QUOTES_ESC;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006763 char *startp;
6764 char *loc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006765 char *rmesc, *rmescend;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006766 char *str;
Denys Vlasenko0b4980c2012-09-25 12:49:29 +02006767 int amount, resetloc;
Denys Vlasenko740058b2018-01-09 17:01:00 +01006768 int argstr_flags;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006769 IF_BASH_PATTERN_SUBST(int workloc;)
Denys Vlasenko740058b2018-01-09 17:01:00 +01006770 IF_BASH_PATTERN_SUBST(int slash_pos;)
6771 IF_BASH_PATTERN_SUBST(char *repl;)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006772 int zero;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006773 char *(*scan)(char*, char*, char*, char*, int, int);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006774
Denys Vlasenko6040fe82010-09-12 15:03:16 +02006775 //bb_error_msg("subevalvar(p:'%s',varname:'%s',strloc:%d,subtype:%d,startloc:%d,varflags:%x,quotes:%d)",
6776 // p, varname, strloc, subtype, startloc, varflags, quotes);
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006777
Denys Vlasenko740058b2018-01-09 17:01:00 +01006778#if BASH_PATTERN_SUBST
Denys Vlasenkod1df1a72018-01-09 17:25:58 +01006779 /* For "${v/pattern/repl}", we must find the delimiter _before_
6780 * argstr() call expands possible variable references in pattern:
6781 * think about "v=a; a=a/; echo ${v/$a/r}" case.
6782 */
Denys Vlasenko740058b2018-01-09 17:01:00 +01006783 repl = NULL;
6784 if (subtype == VSREPLACE || subtype == VSREPLACEALL) {
6785 /* Find '/' and replace with NUL */
6786 repl = p;
6787 for (;;) {
6788 /* Handle escaped slashes, e.g. "${v/\//_}" (they are CTLESC'ed by this point) */
6789 if (*repl == '\0') {
6790 repl = NULL;
6791 break;
6792 }
6793 if (*repl == '/') {
6794 *repl = '\0';
6795 break;
6796 }
Denys Vlasenkod1df1a72018-01-09 17:25:58 +01006797 if ((unsigned char)*repl == CTLESC && repl[1])
Denys Vlasenko740058b2018-01-09 17:01:00 +01006798 repl++;
Denys Vlasenko740058b2018-01-09 17:01:00 +01006799 repl++;
6800 }
6801 }
6802#endif
6803 argstr_flags = EXP_TILDE;
6804 if (subtype != VSASSIGN && subtype != VSQUESTION)
6805 argstr_flags |= (flag & (EXP_QUOTED | EXP_QPAT) ? EXP_QPAT : EXP_CASE);
6806 argstr(p, argstr_flags);
6807#if BASH_PATTERN_SUBST
6808 slash_pos = -1;
6809 if (repl) {
6810 slash_pos = expdest - ((char *)stackblock() + strloc);
6811 STPUTC('/', expdest);
6812 argstr(repl + 1, argstr_flags);
6813 *repl = '/';
6814 }
6815#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006816 STPUTC('\0', expdest);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006817 argbackq = saveargbackq;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006818 startp = (char *)stackblock() + startloc;
Denys Vlasenko740058b2018-01-09 17:01:00 +01006819 //bb_error_msg("str1:'%s'", (char *)stackblock() + strloc);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006820
6821 switch (subtype) {
6822 case VSASSIGN:
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02006823 setvar0(varname, startp);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006824 amount = startp - expdest;
6825 STADJUST(amount, expdest);
6826 return startp;
6827
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006828 case VSQUESTION:
6829 varunset(p, varname, startp, varflags);
6830 /* NOTREACHED */
6831
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006832#if BASH_SUBSTR
Denys Vlasenko826360f2017-07-17 17:49:11 +02006833 case VSSUBSTR: {
6834 int pos, len, orig_len;
6835 char *colon;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006836
Denys Vlasenko826360f2017-07-17 17:49:11 +02006837 loc = str = stackblock() + strloc;
6838
Denys Vlasenko826360f2017-07-17 17:49:11 +02006839 /* Read POS in ${var:POS:LEN} */
6840 colon = strchr(loc, ':');
6841 if (colon) *colon = '\0';
Denys Vlasenkobaa41c72018-01-10 13:22:25 +01006842 pos = substr_atoi(loc);
Denys Vlasenko826360f2017-07-17 17:49:11 +02006843 if (colon) *colon = ':';
6844
6845 /* Read LEN in ${var:POS:LEN} */
6846 len = str - startp - 1;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006847 /* *loc != '\0', guaranteed by parser */
6848 if (quotes) {
6849 char *ptr;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006850 /* Adjust the length by the number of escapes */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006851 for (ptr = startp; ptr < (str - 1); ptr++) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006852 if ((unsigned char)*ptr == CTLESC) {
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006853 len--;
6854 ptr++;
6855 }
6856 }
6857 }
6858 orig_len = len;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006859 if (*loc++ == ':') {
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006860 /* ${var::LEN} */
Denys Vlasenkobaa41c72018-01-10 13:22:25 +01006861 len = substr_atoi(loc);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006862 } else {
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006863 /* Skip POS in ${var:POS:LEN} */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006864 len = orig_len;
Denys Vlasenkobaa41c72018-01-10 13:22:25 +01006865 while (*loc && *loc != ':')
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006866 loc++;
Denys Vlasenkobaa41c72018-01-10 13:22:25 +01006867 if (*loc++ == ':')
6868 len = substr_atoi(loc);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006869 }
Denys Vlasenko08a5dab2014-11-17 20:27:18 +01006870 if (pos < 0) {
6871 /* ${VAR:$((-n)):l} starts n chars from the end */
6872 pos = orig_len + pos;
6873 }
6874 if ((unsigned)pos >= orig_len) {
6875 /* apart from obvious ${VAR:999999:l},
6876 * covers ${VAR:$((-9999999)):l} - result is ""
Denys Vlasenko826360f2017-07-17 17:49:11 +02006877 * (bash compat)
Denys Vlasenko08a5dab2014-11-17 20:27:18 +01006878 */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006879 pos = 0;
6880 len = 0;
6881 }
Denys Vlasenko826360f2017-07-17 17:49:11 +02006882 if (len < 0) {
6883 /* ${VAR:N:-M} sets LEN to strlen()-M */
6884 len = (orig_len - pos) + len;
6885 }
6886 if ((unsigned)len > (orig_len - pos))
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006887 len = orig_len - pos;
6888
6889 for (str = startp; pos; str++, pos--) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006890 if (quotes && (unsigned char)*str == CTLESC)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006891 str++;
6892 }
6893 for (loc = startp; len; len--) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006894 if (quotes && (unsigned char)*str == CTLESC)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006895 *loc++ = *str++;
6896 *loc++ = *str++;
6897 }
6898 *loc = '\0';
6899 amount = loc - expdest;
6900 STADJUST(amount, expdest);
6901 return loc;
Denys Vlasenko826360f2017-07-17 17:49:11 +02006902 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006903#endif /* BASH_SUBSTR */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006904 }
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006905
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006906 resetloc = expdest - (char *)stackblock();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006907
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006908#if BASH_PATTERN_SUBST
Denys Vlasenko740058b2018-01-09 17:01:00 +01006909 repl = NULL;
6910
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006911 /* We'll comeback here if we grow the stack while handling
6912 * a VSREPLACE or VSREPLACEALL, since our pointers into the
6913 * stack will need rebasing, and we'll need to remove our work
6914 * areas each time
6915 */
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006916 restart:
6917#endif
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006918
6919 amount = expdest - ((char *)stackblock() + resetloc);
6920 STADJUST(-amount, expdest);
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006921 startp = (char *)stackblock() + startloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006922
6923 rmesc = startp;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006924 rmescend = (char *)stackblock() + strloc;
Denys Vlasenko740058b2018-01-09 17:01:00 +01006925 //bb_error_msg("str7:'%s'", rmescend);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006926 if (quotes) {
Denys Vlasenko740058b2018-01-09 17:01:00 +01006927//TODO: how to handle slash_pos here if string changes (shortens?)
6928 rmesc = rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW, NULL);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006929 if (rmesc != startp) {
6930 rmescend = expdest;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006931 startp = (char *)stackblock() + startloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006932 }
6933 }
6934 rmescend--;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006935 str = (char *)stackblock() + strloc;
Ron Yorston417622c2015-05-18 09:59:14 +02006936 /*
6937 * Example: v='a\bc'; echo ${v/\\b/_\\_\z_}
6938 * The result is a_\_z_c (not a\_\_z_c)!
6939 *
6940 * The search pattern and replace string treat backslashes differently!
Denys Vlasenko740058b2018-01-09 17:01:00 +01006941 * "&slash_pos" causes rmescapes() to work differently on the pattern
Ron Yorston417622c2015-05-18 09:59:14 +02006942 * and string. It's only used on the first call.
6943 */
Denys Vlasenko740058b2018-01-09 17:01:00 +01006944 //bb_error_msg("str8:'%s' slash_pos:%d", str, slash_pos);
6945 rmescapes(str, RMESCAPE_GLOB,
6946 repl ? NULL : (slash_pos < 0 ? NULL : &slash_pos)
6947 );
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006948
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006949#if BASH_PATTERN_SUBST
Denys Vlasenko0b4980c2012-09-25 12:49:29 +02006950 workloc = expdest - (char *)stackblock();
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006951 if (subtype == VSREPLACE || subtype == VSREPLACEALL) {
Denys Vlasenko826360f2017-07-17 17:49:11 +02006952 int len;
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006953 char *idx, *end;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006954
Denis Vlasenkod6855d12008-09-27 14:03:25 +00006955 if (!repl) {
Denys Vlasenko740058b2018-01-09 17:01:00 +01006956 //bb_error_msg("str9:'%s' slash_pos:%d", str, slash_pos);
Denys Vlasenkod1df1a72018-01-09 17:25:58 +01006957 repl = nullstr;
Denys Vlasenko740058b2018-01-09 17:01:00 +01006958 if (slash_pos >= 0) {
6959 repl = str + slash_pos;
Ron Yorston417622c2015-05-18 09:59:14 +02006960 *repl++ = '\0';
Denys Vlasenko740058b2018-01-09 17:01:00 +01006961 }
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006962 }
Ron Yorston417622c2015-05-18 09:59:14 +02006963 //bb_error_msg("str:'%s' repl:'%s'", str, repl);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006964
6965 /* If there's no pattern to match, return the expansion unmolested */
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006966 if (str[0] == '\0')
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006967 return NULL;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006968
6969 len = 0;
6970 idx = startp;
6971 end = str - 1;
6972 while (idx < end) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006973 try_to_match:
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006974 loc = scanright(idx, rmesc, rmescend, str, quotes, 1);
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006975 //bb_error_msg("scanright('%s'):'%s'", str, loc);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006976 if (!loc) {
6977 /* No match, advance */
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006978 char *restart_detect = stackblock();
6979 skip_matching:
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006980 STPUTC(*idx, expdest);
Denys Vlasenkocd716832009-11-28 22:14:02 +01006981 if (quotes && (unsigned char)*idx == CTLESC) {
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006982 idx++;
6983 len++;
6984 STPUTC(*idx, expdest);
6985 }
6986 if (stackblock() != restart_detect)
6987 goto restart;
6988 idx++;
6989 len++;
6990 rmesc++;
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006991 /* continue; - prone to quadratic behavior, smarter code: */
6992 if (idx >= end)
6993 break;
6994 if (str[0] == '*') {
6995 /* Pattern is "*foo". If "*foo" does not match "long_string",
6996 * it would never match "ong_string" etc, no point in trying.
6997 */
6998 goto skip_matching;
6999 }
7000 goto try_to_match;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007001 }
7002
7003 if (subtype == VSREPLACEALL) {
7004 while (idx < loc) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01007005 if (quotes && (unsigned char)*idx == CTLESC)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007006 idx++;
7007 idx++;
7008 rmesc++;
7009 }
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00007010 } else {
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007011 idx = loc;
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00007012 }
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007013
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02007014 //bb_error_msg("repl:'%s'", repl);
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007015 for (loc = (char*)repl; *loc; loc++) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01007016 char *restart_detect = stackblock();
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007017 if (quotes && *loc == '\\') {
7018 STPUTC(CTLESC, expdest);
7019 len++;
7020 }
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007021 STPUTC(*loc, expdest);
7022 if (stackblock() != restart_detect)
7023 goto restart;
7024 len++;
7025 }
7026
7027 if (subtype == VSREPLACE) {
Denys Vlasenkof02c82f2010-08-06 19:14:47 +02007028 //bb_error_msg("tail:'%s', quotes:%x", idx, quotes);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007029 while (*idx) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01007030 char *restart_detect = stackblock();
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007031 STPUTC(*idx, expdest);
7032 if (stackblock() != restart_detect)
7033 goto restart;
7034 len++;
7035 idx++;
7036 }
7037 break;
7038 }
7039 }
7040
7041 /* We've put the replaced text into a buffer at workloc, now
7042 * move it to the right place and adjust the stack.
7043 */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007044 STPUTC('\0', expdest);
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007045 startp = (char *)stackblock() + startloc;
7046 memmove(startp, (char *)stackblock() + workloc, len + 1);
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02007047 //bb_error_msg("startp:'%s'", startp);
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007048 amount = expdest - (startp + len);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007049 STADJUST(-amount, expdest);
7050 return startp;
7051 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01007052#endif /* BASH_PATTERN_SUBST */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007053
7054 subtype -= VSTRIMRIGHT;
7055#if DEBUG
7056 if (subtype < 0 || subtype > 7)
7057 abort();
7058#endif
Denys Vlasenkob76356b2010-03-13 16:19:04 +01007059 /* zero = (subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX) */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007060 zero = subtype >> 1;
7061 /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */
7062 scan = (subtype & 1) ^ zero ? scanleft : scanright;
7063
7064 loc = scan(startp, rmesc, rmescend, str, quotes, zero);
7065 if (loc) {
7066 if (zero) {
7067 memmove(startp, loc, str - loc);
7068 loc = startp + (str - loc) - 1;
7069 }
7070 *loc = '\0';
7071 amount = loc - expdest;
7072 STADJUST(amount, expdest);
7073 }
7074 return loc;
7075}
7076
7077/*
7078 * Add the value of a specialized variable to the stack string.
Denys Vlasenko4d8873f2009-10-04 03:14:41 +02007079 * name parameter (examples):
7080 * ash -c 'echo $1' name:'1='
7081 * ash -c 'echo $qwe' name:'qwe='
7082 * ash -c 'echo $$' name:'$='
7083 * ash -c 'echo ${$}' name:'$='
7084 * ash -c 'echo ${$##q}' name:'$=q'
7085 * ash -c 'echo ${#$}' name:'$='
7086 * note: examples with bad shell syntax:
7087 * ash -c 'echo ${#$1}' name:'$=1'
7088 * ash -c 'echo ${#1#}' name:'1=#'
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007089 */
Denys Vlasenkoadf922e2009-10-08 14:35:37 +02007090static NOINLINE ssize_t
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02007091varvalue(char *name, int varflags, int flags, int *quotedp)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007092{
Mike Frysinger98c52642009-04-02 10:02:37 +00007093 const char *p;
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01007094 int num;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007095 int i;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007096 ssize_t len = 0;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007097 int sep;
Denys Vlasenko0dd8e452016-10-01 21:02:06 +02007098 int quoted = *quotedp;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007099 int subtype = varflags & VSTYPE;
7100 int discard = subtype == VSPLUS || subtype == VSLENGTH;
7101 int quotes = (discard ? 0 : (flags & QUOTES_ESC)) | QUOTES_KEEPNUL;
Denys Vlasenko0aaaa502016-10-02 02:46:56 +02007102 int syntax;
7103
7104 sep = (flags & EXP_FULL) << CHAR_BIT;
7105 syntax = quoted ? DQSYNTAX : BASESYNTAX;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007106
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007107 switch (*name) {
7108 case '$':
7109 num = rootpid;
7110 goto numvar;
7111 case '?':
7112 num = exitstatus;
7113 goto numvar;
7114 case '#':
7115 num = shellparam.nparam;
7116 goto numvar;
7117 case '!':
7118 num = backgndpid;
7119 if (num == 0)
7120 return -1;
7121 numvar:
7122 len = cvtnum(num);
Denys Vlasenko4d8873f2009-10-04 03:14:41 +02007123 goto check_1char_name;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007124 case '-':
Mike Frysinger98c52642009-04-02 10:02:37 +00007125 expdest = makestrspace(NOPTS, expdest);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007126 for (i = NOPTS - 1; i >= 0; i--) {
7127 if (optlist[i]) {
Mike Frysinger98c52642009-04-02 10:02:37 +00007128 USTPUTC(optletters(i), expdest);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007129 len++;
7130 }
7131 }
Denys Vlasenko4d8873f2009-10-04 03:14:41 +02007132 check_1char_name:
7133#if 0
7134 /* handles cases similar to ${#$1} */
7135 if (name[2] != '\0')
7136 raise_error_syntax("bad substitution");
7137#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007138 break;
Denys Vlasenko0aaaa502016-10-02 02:46:56 +02007139 case '@':
7140 if (quoted && sep)
7141 goto param;
7142 /* fall through */
7143 case '*': {
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01007144 char **ap;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007145 char sepc;
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01007146
Denys Vlasenko0aaaa502016-10-02 02:46:56 +02007147 if (quoted)
7148 sep = 0;
7149 sep |= ifsset() ? ifsval()[0] : ' ';
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007150 param:
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007151 sepc = sep;
Denys Vlasenko0dd8e452016-10-01 21:02:06 +02007152 *quotedp = !sepc;
7153 ap = shellparam.p;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007154 if (!ap)
7155 return -1;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02007156 while ((p = *ap++) != NULL) {
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007157 len += strtodest(p, syntax, quotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007158
7159 if (*ap && sep) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007160 len++;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007161 memtodest(&sepc, 1, syntax, quotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007162 }
7163 }
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007164 break;
Denys Vlasenko0aaaa502016-10-02 02:46:56 +02007165 } /* case '*' */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007166 case '0':
7167 case '1':
7168 case '2':
7169 case '3':
7170 case '4':
7171 case '5':
7172 case '6':
7173 case '7':
7174 case '8':
7175 case '9':
Denys Vlasenkoa00329c2009-08-30 20:05:10 +02007176 num = atoi(name); /* number(name) fails on ${N#str} etc */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007177 if (num < 0 || num > shellparam.nparam)
7178 return -1;
7179 p = num ? shellparam.p[num - 1] : arg0;
7180 goto value;
7181 default:
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00007182 /* NB: name has form "VAR=..." */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007183 p = lookupvar(name);
7184 value:
7185 if (!p)
7186 return -1;
7187
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007188 len = strtodest(p, syntax, quotes);
Denys Vlasenkoc76236f2014-12-29 00:04:18 +01007189#if ENABLE_UNICODE_SUPPORT
7190 if (subtype == VSLENGTH && len > 0) {
7191 reinit_unicode_for_ash();
7192 if (unicode_status == UNICODE_ON) {
Ron Yorston3e3bfb82016-03-18 11:29:19 +00007193 STADJUST(-len, expdest);
7194 discard = 0;
Denys Vlasenkoc76236f2014-12-29 00:04:18 +01007195 len = unicode_strlen(p);
7196 }
7197 }
7198#endif
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007199 break;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007200 }
7201
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007202 if (discard)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007203 STADJUST(-len, expdest);
7204 return len;
7205}
7206
7207/*
7208 * Expand a variable, and return a pointer to the next character in the
7209 * input string.
7210 */
7211static char *
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02007212evalvar(char *p, int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007213{
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00007214 char varflags;
7215 char subtype;
Ron Yorston549deab2015-05-18 09:57:51 +02007216 int quoted;
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00007217 char easy;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007218 char *var;
7219 int patloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007220 int startloc;
7221 ssize_t varlen;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007222
Denys Vlasenkob0d63382009-09-16 16:18:32 +02007223 varflags = (unsigned char) *p++;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007224 subtype = varflags & VSTYPE;
Denys Vlasenko88e15702016-10-26 01:55:56 +02007225
7226 if (!subtype)
7227 raise_error_syntax("bad substitution");
7228
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007229 quoted = flag & EXP_QUOTED;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007230 var = p;
7231 easy = (!quoted || (*var == '@' && shellparam.nparam));
7232 startloc = expdest - (char *)stackblock();
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02007233 p = strchr(p, '=') + 1; //TODO: use var_end(p)?
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007234
7235 again:
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02007236 varlen = varvalue(var, varflags, flag, &quoted);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007237 if (varflags & VSNUL)
7238 varlen--;
7239
7240 if (subtype == VSPLUS) {
7241 varlen = -1 - varlen;
7242 goto vsplus;
7243 }
7244
7245 if (subtype == VSMINUS) {
7246 vsplus:
7247 if (varlen < 0) {
7248 argstr(
Denys Vlasenko6040fe82010-09-12 15:03:16 +02007249 p,
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02007250 flag | EXP_TILDE | EXP_WORD
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007251 );
7252 goto end;
7253 }
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007254 goto record;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007255 }
7256
7257 if (subtype == VSASSIGN || subtype == VSQUESTION) {
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007258 if (varlen >= 0)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007259 goto record;
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007260
7261 subevalvar(p, var, 0, subtype, startloc, varflags,
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02007262 flag & ~QUOTES_ESC);
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007263 varflags &= ~VSNUL;
7264 /*
7265 * Remove any recorded regions beyond
7266 * start of variable
7267 */
7268 removerecordregions(startloc);
7269 goto again;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007270 }
7271
7272 if (varlen < 0 && uflag)
7273 varunset(p, var, 0, 0);
7274
7275 if (subtype == VSLENGTH) {
Denys Vlasenkoc76236f2014-12-29 00:04:18 +01007276 cvtnum(varlen > 0 ? varlen : 0);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007277 goto record;
7278 }
7279
7280 if (subtype == VSNORMAL) {
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007281 record:
7282 if (!easy)
7283 goto end;
Denys Vlasenko0dd8e452016-10-01 21:02:06 +02007284 recordregion(startloc, expdest - (char *)stackblock(), quoted);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007285 goto end;
7286 }
7287
7288#if DEBUG
7289 switch (subtype) {
7290 case VSTRIMLEFT:
7291 case VSTRIMLEFTMAX:
7292 case VSTRIMRIGHT:
7293 case VSTRIMRIGHTMAX:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01007294#if BASH_SUBSTR
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007295 case VSSUBSTR:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01007296#endif
7297#if BASH_PATTERN_SUBST
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007298 case VSREPLACE:
7299 case VSREPLACEALL:
7300#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007301 break;
7302 default:
7303 abort();
7304 }
7305#endif
7306
7307 if (varlen >= 0) {
7308 /*
7309 * Terminate the string and start recording the pattern
7310 * right after it
7311 */
7312 STPUTC('\0', expdest);
7313 patloc = expdest - (char *)stackblock();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02007314 if (NULL == subevalvar(p, /* varname: */ NULL, patloc, subtype,
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02007315 startloc, varflags, flag)) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007316 int amount = expdest - (
7317 (char *)stackblock() + patloc - 1
7318 );
7319 STADJUST(-amount, expdest);
7320 }
7321 /* Remove any recorded regions beyond start of variable */
7322 removerecordregions(startloc);
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007323 goto record;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007324 }
7325
7326 end:
7327 if (subtype != VSNORMAL) { /* skip to end of alternative */
7328 int nesting = 1;
7329 for (;;) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01007330 unsigned char c = *p++;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007331 if (c == CTLESC)
7332 p++;
Ron Yorston549deab2015-05-18 09:57:51 +02007333 else if (c == CTLBACKQ) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007334 if (varlen >= 0)
7335 argbackq = argbackq->next;
7336 } else if (c == CTLVAR) {
7337 if ((*p++ & VSTYPE) != VSNORMAL)
7338 nesting++;
7339 } else if (c == CTLENDVAR) {
7340 if (--nesting == 0)
7341 break;
7342 }
7343 }
7344 }
7345 return p;
7346}
7347
7348/*
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007349 * Add a file name to the list.
7350 */
7351static void
7352addfname(const char *name)
7353{
7354 struct strlist *sp;
7355
Denis Vlasenko597906c2008-02-20 16:38:54 +00007356 sp = stzalloc(sizeof(*sp));
Denys Vlasenko8e2bc472016-09-28 23:02:57 +02007357 sp->text = sstrdup(name);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007358 *exparg.lastp = sp;
7359 exparg.lastp = &sp->next;
7360}
7361
Felix Fietkaub5b21122017-01-31 21:58:55 +01007362/* Avoid glob() (and thus, stat() et al) for words like "echo" */
7363static int
7364hasmeta(const char *p)
7365{
7366 static const char chars[] ALIGN1 = {
7367 '*', '?', '[', '\\', CTLQUOTEMARK, CTLESC, 0
7368 };
7369
7370 for (;;) {
7371 p = strpbrk(p, chars);
7372 if (!p)
7373 break;
7374 switch ((unsigned char) *p) {
7375 case CTLQUOTEMARK:
7376 for (;;) {
7377 p++;
7378 if (*p == CTLQUOTEMARK)
7379 break;
7380 if (*p == CTLESC)
7381 p++;
7382 if (*p == '\0') /* huh? */
7383 return 0;
7384 }
7385 break;
7386 case '\\':
7387 case CTLESC:
7388 p++;
7389 if (*p == '\0')
7390 return 0;
7391 break;
7392 case '[':
7393 if (!strchr(p + 1, ']')) {
7394 /* It's not a properly closed [] pattern,
7395 * but other metas may follow. Continue checking.
7396 * my[file* _is_ globbed by bash
7397 * and matches filenames like "my[file1".
7398 */
7399 break;
7400 }
7401 /* fallthrough */
7402 default:
7403 /* case '*': */
7404 /* case '?': */
7405 return 1;
7406 }
7407 p++;
7408 }
7409
7410 return 0;
7411}
7412
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007413/* If we want to use glob() from libc... */
Denys Vlasenko514b51d2016-10-01 14:33:08 +02007414#if !ENABLE_ASH_INTERNAL_GLOB
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007415
7416/* Add the result of glob() to the list */
7417static void
7418addglob(const glob_t *pglob)
7419{
7420 char **p = pglob->gl_pathv;
7421
7422 do {
7423 addfname(*p);
7424 } while (*++p);
7425}
7426static void
7427expandmeta(struct strlist *str /*, int flag*/)
7428{
7429 /* TODO - EXP_REDIR */
7430
7431 while (str) {
7432 char *p;
7433 glob_t pglob;
7434 int i;
7435
7436 if (fflag)
7437 goto nometa;
Denys Vlasenkod4f3db92016-10-30 18:41:01 +01007438
Felix Fietkaub5b21122017-01-31 21:58:55 +01007439 if (!hasmeta(str->text))
7440 goto nometa;
Denys Vlasenkod4f3db92016-10-30 18:41:01 +01007441
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007442 INT_OFF;
7443 p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP);
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007444// GLOB_NOMAGIC (GNU): if no *?[ chars in pattern, return it even if no match
7445// GLOB_NOCHECK: if no match, return unchanged pattern (sans \* escapes?)
7446//
7447// glibc 2.24.90 glob(GLOB_NOMAGIC) does not remove backslashes used for escaping:
7448// if you pass it "file\?", it returns "file\?", not "file?", if no match.
7449// Which means you need to unescape the string, right? Not so fast:
7450// if there _is_ a file named "file\?" (with backslash), it is returned
7451// as "file\?" too (whichever pattern you used to find it, say, "file*").
Denys Vlasenko10ad6222017-04-17 16:13:32 +02007452// You DON'T KNOW by looking at the result whether you need to unescape it.
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007453//
7454// Worse, globbing of "file\?" in a directory with two files, "file?" and "file\?",
7455// returns "file\?" - which is WRONG: "file\?" pattern matches "file?" file.
7456// Without GLOB_NOMAGIC, this works correctly ("file?" is returned as a match).
7457// With GLOB_NOMAGIC | GLOB_NOCHECK, this also works correctly.
7458// i = glob(p, GLOB_NOMAGIC | GLOB_NOCHECK, NULL, &pglob);
7459// i = glob(p, GLOB_NOMAGIC, NULL, &pglob);
7460 i = glob(p, 0, NULL, &pglob);
7461 //bb_error_msg("glob('%s'):%d '%s'...", p, i, pglob.gl_pathv ? pglob.gl_pathv[0] : "-");
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007462 if (p != str->text)
7463 free(p);
7464 switch (i) {
7465 case 0:
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007466#if 0 // glibc 2.24.90 bug? Patterns like "*/file", when match, don't set GLOB_MAGCHAR
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007467 /* GLOB_MAGCHAR is set if *?[ chars were seen (GNU) */
7468 if (!(pglob.gl_flags & GLOB_MAGCHAR))
7469 goto nometa2;
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007470#endif
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007471 addglob(&pglob);
7472 globfree(&pglob);
7473 INT_ON;
7474 break;
7475 case GLOB_NOMATCH:
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007476 //nometa2:
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007477 globfree(&pglob);
7478 INT_ON;
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007479 nometa:
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007480 *exparg.lastp = str;
Denys Vlasenko740058b2018-01-09 17:01:00 +01007481 rmescapes(str->text, 0, NULL);
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007482 exparg.lastp = &str->next;
7483 break;
7484 default: /* GLOB_NOSPACE */
7485 globfree(&pglob);
7486 INT_ON;
7487 ash_msg_and_raise_error(bb_msg_memory_exhausted);
7488 }
7489 str = str->next;
7490 }
7491}
7492
7493#else
Denys Vlasenko514b51d2016-10-01 14:33:08 +02007494/* ENABLE_ASH_INTERNAL_GLOB: Homegrown globbing code. (dash also has both, uses homegrown one.) */
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007495
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007496/*
7497 * Do metacharacter (i.e. *, ?, [...]) expansion.
7498 */
7499static void
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007500expmeta(char *expdir, char *enddir, char *name)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007501{
7502 char *p;
7503 const char *cp;
7504 char *start;
7505 char *endname;
7506 int metaflag;
7507 struct stat statb;
7508 DIR *dirp;
7509 struct dirent *dp;
7510 int atend;
7511 int matchdot;
Ron Yorstonca25af92015-09-04 10:32:41 +01007512 int esc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007513
7514 metaflag = 0;
7515 start = name;
Ron Yorstonca25af92015-09-04 10:32:41 +01007516 for (p = name; esc = 0, *p; p += esc + 1) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007517 if (*p == '*' || *p == '?')
7518 metaflag = 1;
7519 else if (*p == '[') {
7520 char *q = p + 1;
7521 if (*q == '!')
7522 q++;
7523 for (;;) {
7524 if (*q == '\\')
7525 q++;
7526 if (*q == '/' || *q == '\0')
7527 break;
7528 if (*++q == ']') {
7529 metaflag = 1;
7530 break;
7531 }
7532 }
Ron Yorstonca25af92015-09-04 10:32:41 +01007533 } else {
7534 if (*p == '\\')
7535 esc++;
7536 if (p[esc] == '/') {
7537 if (metaflag)
7538 break;
7539 start = p + esc + 1;
7540 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007541 }
7542 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007543 if (metaflag == 0) { /* we've reached the end of the file name */
7544 if (enddir != expdir)
7545 metaflag++;
7546 p = name;
7547 do {
7548 if (*p == '\\')
7549 p++;
7550 *enddir++ = *p;
7551 } while (*p++);
7552 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
7553 addfname(expdir);
7554 return;
7555 }
7556 endname = p;
7557 if (name < start) {
7558 p = name;
7559 do {
7560 if (*p == '\\')
7561 p++;
7562 *enddir++ = *p++;
7563 } while (p < start);
7564 }
7565 if (enddir == expdir) {
7566 cp = ".";
7567 } else if (enddir == expdir + 1 && *expdir == '/') {
7568 cp = "/";
7569 } else {
7570 cp = expdir;
7571 enddir[-1] = '\0';
7572 }
7573 dirp = opendir(cp);
7574 if (dirp == NULL)
7575 return;
7576 if (enddir != expdir)
7577 enddir[-1] = '/';
7578 if (*endname == 0) {
7579 atend = 1;
7580 } else {
7581 atend = 0;
Ron Yorstonca25af92015-09-04 10:32:41 +01007582 *endname = '\0';
7583 endname += esc + 1;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007584 }
7585 matchdot = 0;
7586 p = start;
7587 if (*p == '\\')
7588 p++;
7589 if (*p == '.')
7590 matchdot++;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02007591 while (!pending_int && (dp = readdir(dirp)) != NULL) {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00007592 if (dp->d_name[0] == '.' && !matchdot)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007593 continue;
7594 if (pmatch(start, dp->d_name)) {
7595 if (atend) {
7596 strcpy(enddir, dp->d_name);
7597 addfname(expdir);
7598 } else {
7599 for (p = enddir, cp = dp->d_name; (*p++ = *cp++) != '\0';)
7600 continue;
7601 p[-1] = '/';
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007602 expmeta(expdir, p, endname);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007603 }
7604 }
7605 }
7606 closedir(dirp);
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00007607 if (!atend)
Ron Yorstonca25af92015-09-04 10:32:41 +01007608 endname[-esc - 1] = esc ? '\\' : '/';
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007609}
7610
7611static struct strlist *
7612msort(struct strlist *list, int len)
7613{
7614 struct strlist *p, *q = NULL;
7615 struct strlist **lpp;
7616 int half;
7617 int n;
7618
7619 if (len <= 1)
7620 return list;
7621 half = len >> 1;
7622 p = list;
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +00007623 for (n = half; --n >= 0;) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007624 q = p;
7625 p = p->next;
7626 }
7627 q->next = NULL; /* terminate first half of list */
7628 q = msort(list, half); /* sort first half of list */
7629 p = msort(p, len - half); /* sort second half */
7630 lpp = &list;
7631 for (;;) {
7632#if ENABLE_LOCALE_SUPPORT
7633 if (strcoll(p->text, q->text) < 0)
7634#else
7635 if (strcmp(p->text, q->text) < 0)
7636#endif
7637 {
7638 *lpp = p;
7639 lpp = &p->next;
7640 p = *lpp;
7641 if (p == NULL) {
7642 *lpp = q;
7643 break;
7644 }
7645 } else {
7646 *lpp = q;
7647 lpp = &q->next;
7648 q = *lpp;
7649 if (q == NULL) {
7650 *lpp = p;
7651 break;
7652 }
7653 }
7654 }
7655 return list;
7656}
7657
7658/*
7659 * Sort the results of file name expansion. It calculates the number of
7660 * strings to sort and then calls msort (short for merge sort) to do the
7661 * work.
7662 */
7663static struct strlist *
7664expsort(struct strlist *str)
7665{
7666 int len;
7667 struct strlist *sp;
7668
7669 len = 0;
7670 for (sp = str; sp; sp = sp->next)
7671 len++;
7672 return msort(str, len);
7673}
7674
7675static void
Denis Vlasenko68404f12008-03-17 09:00:54 +00007676expandmeta(struct strlist *str /*, int flag*/)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007677{
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007678 /* TODO - EXP_REDIR */
7679
7680 while (str) {
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007681 char *expdir;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007682 struct strlist **savelastp;
7683 struct strlist *sp;
7684 char *p;
7685
7686 if (fflag)
7687 goto nometa;
Felix Fietkaub5b21122017-01-31 21:58:55 +01007688 if (!hasmeta(str->text))
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007689 goto nometa;
7690 savelastp = exparg.lastp;
7691
7692 INT_OFF;
Ron Yorston549deab2015-05-18 09:57:51 +02007693 p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007694 {
7695 int i = strlen(str->text);
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007696//BUGGY estimation of how long expanded name can be
7697 expdir = ckmalloc(i < 2048 ? 2048 : i+1);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007698 }
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007699 expmeta(expdir, expdir, p);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007700 free(expdir);
7701 if (p != str->text)
7702 free(p);
7703 INT_ON;
7704 if (exparg.lastp == savelastp) {
7705 /*
7706 * no matches
7707 */
7708 nometa:
7709 *exparg.lastp = str;
Denys Vlasenko740058b2018-01-09 17:01:00 +01007710 rmescapes(str->text, 0, NULL);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007711 exparg.lastp = &str->next;
7712 } else {
7713 *exparg.lastp = NULL;
7714 *savelastp = sp = expsort(*savelastp);
7715 while (sp->next != NULL)
7716 sp = sp->next;
7717 exparg.lastp = &sp->next;
7718 }
7719 str = str->next;
7720 }
7721}
Denys Vlasenko514b51d2016-10-01 14:33:08 +02007722#endif /* ENABLE_ASH_INTERNAL_GLOB */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007723
7724/*
7725 * Perform variable substitution and command substitution on an argument,
7726 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
7727 * perform splitting and file name expansion. When arglist is NULL, perform
7728 * here document expansion.
7729 */
7730static void
7731expandarg(union node *arg, struct arglist *arglist, int flag)
7732{
7733 struct strlist *sp;
7734 char *p;
7735
7736 argbackq = arg->narg.backquote;
7737 STARTSTACKSTR(expdest);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02007738 TRACE(("expandarg: argstr('%s',flags:%x)\n", arg->narg.text, flag));
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02007739 argstr(arg->narg.text, flag);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007740 p = _STPUTC('\0', expdest);
7741 expdest = p - 1;
7742 if (arglist == NULL) {
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02007743 /* here document expanded */
7744 goto out;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007745 }
7746 p = grabstackstr(p);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02007747 TRACE(("expandarg: p:'%s'\n", p));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007748 exparg.lastp = &exparg.list;
7749 /*
7750 * TODO - EXP_REDIR
7751 */
7752 if (flag & EXP_FULL) {
7753 ifsbreakup(p, &exparg);
7754 *exparg.lastp = NULL;
7755 exparg.lastp = &exparg.list;
Denis Vlasenko68404f12008-03-17 09:00:54 +00007756 expandmeta(exparg.list /*, flag*/);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007757 } else {
Denis Vlasenko597906c2008-02-20 16:38:54 +00007758 sp = stzalloc(sizeof(*sp));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007759 sp->text = p;
7760 *exparg.lastp = sp;
7761 exparg.lastp = &sp->next;
7762 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007763 *exparg.lastp = NULL;
7764 if (exparg.list) {
7765 *arglist->lastp = exparg.list;
7766 arglist->lastp = exparg.lastp;
7767 }
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02007768
7769 out:
7770 ifsfree();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007771}
7772
7773/*
7774 * Expand shell variables and backquotes inside a here document.
7775 */
7776static void
7777expandhere(union node *arg, int fd)
7778{
Ron Yorston549deab2015-05-18 09:57:51 +02007779 expandarg(arg, (struct arglist *)NULL, EXP_QUOTED);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007780 full_write(fd, stackblock(), expdest - (char *)stackblock());
7781}
7782
7783/*
7784 * Returns true if the pattern matches the string.
7785 */
7786static int
7787patmatch(char *pattern, const char *string)
7788{
Denys Vlasenkobd43c672017-07-05 23:12:15 +02007789 char *p = preglob(pattern, 0);
Denys Vlasenko4476c702017-08-15 15:27:41 +02007790 int r = pmatch(p, string);
7791 //bb_error_msg("!fnmatch(pattern:'%s',str:'%s',0):%d", p, string, r);
7792 return r;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007793}
7794
7795/*
7796 * See if a pattern matches in a case statement.
7797 */
7798static int
7799casematch(union node *pattern, char *val)
7800{
7801 struct stackmark smark;
7802 int result;
7803
7804 setstackmark(&smark);
7805 argbackq = pattern->narg.backquote;
7806 STARTSTACKSTR(expdest);
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02007807 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007808 STACKSTRNUL(expdest);
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02007809 ifsfree();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007810 result = patmatch(stackblock(), val);
7811 popstackmark(&smark);
7812 return result;
7813}
7814
7815
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007816/* ============ find_command */
7817
7818struct builtincmd {
7819 const char *name;
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02007820 int (*builtin)(int, char **) FAST_FUNC;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007821 /* unsigned flags; */
7822};
7823#define IS_BUILTIN_SPECIAL(b) ((b)->name[0] & 1)
Denis Vlasenkoe26b2782008-02-12 07:40:29 +00007824/* "regular" builtins always take precedence over commands,
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007825 * regardless of PATH=....%builtin... position */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007826#define IS_BUILTIN_REGULAR(b) ((b)->name[0] & 2)
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007827#define IS_BUILTIN_ASSIGN(b) ((b)->name[0] & 4)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007828
7829struct cmdentry {
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00007830 smallint cmdtype; /* CMDxxx */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007831 union param {
7832 int index;
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00007833 /* index >= 0 for commands without path (slashes) */
7834 /* (TODO: what exactly does the value mean? PATH position?) */
7835 /* index == -1 for commands with slashes */
7836 /* index == (-2 - applet_no) for NOFORK applets */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007837 const struct builtincmd *cmd;
7838 struct funcnode *func;
7839 } u;
7840};
7841/* values of cmdtype */
7842#define CMDUNKNOWN -1 /* no entry in table for command */
7843#define CMDNORMAL 0 /* command is an executable program */
7844#define CMDFUNCTION 1 /* command is a shell function */
7845#define CMDBUILTIN 2 /* command is a shell builtin */
7846
7847/* action to find_command() */
7848#define DO_ERR 0x01 /* prints errors */
7849#define DO_ABS 0x02 /* checks absolute paths */
7850#define DO_NOFUNC 0x04 /* don't return shell functions, for command */
7851#define DO_ALTPATH 0x08 /* using alternate path */
7852#define DO_ALTBLTIN 0x20 /* %builtin in alt. path */
7853
7854static void find_command(char *, struct cmdentry *, int, const char *);
7855
7856
7857/* ============ Hashing commands */
7858
7859/*
7860 * When commands are first encountered, they are entered in a hash table.
7861 * This ensures that a full path search will not have to be done for them
7862 * on each invocation.
7863 *
7864 * We should investigate converting to a linear search, even though that
7865 * would make the command name "hash" a misnomer.
7866 */
7867
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007868struct tblentry {
7869 struct tblentry *next; /* next entry in hash chain */
7870 union param param; /* definition of builtin function */
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00007871 smallint cmdtype; /* CMDxxx */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007872 char rehash; /* if set, cd done since entry created */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00007873 char cmdname[1]; /* name of command */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007874};
7875
Denis Vlasenko01631112007-12-16 17:20:38 +00007876static struct tblentry **cmdtable;
7877#define INIT_G_cmdtable() do { \
7878 cmdtable = xzalloc(CMDTABLESIZE * sizeof(cmdtable[0])); \
7879} while (0)
7880
7881static int builtinloc = -1; /* index in path of %builtin, or -1 */
7882
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007883
7884static void
Denys Vlasenko00a1dbd2017-07-29 01:20:53 +02007885tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) const char *cmd, char **argv, char **envp)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007886{
Denis Vlasenko80d14be2007-04-10 23:03:30 +00007887#if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007888 if (applet_no >= 0) {
Denis Vlasenkob7304742008-10-20 08:15:51 +00007889 if (APPLET_IS_NOEXEC(applet_no)) {
Denys Vlasenko7df28bb2010-06-18 14:23:47 +02007890 clearenv();
Denis Vlasenkob7304742008-10-20 08:15:51 +00007891 while (*envp)
7892 putenv(*envp++);
Denys Vlasenko035486c2017-07-31 04:09:19 +02007893 popredir(/*drop:*/ 1);
Denys Vlasenko80e8e3c2017-08-07 19:24:57 +02007894 run_noexec_applet_and_exit(applet_no, cmd, argv);
Denis Vlasenkob7304742008-10-20 08:15:51 +00007895 }
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007896 /* re-exec ourselves with the new arguments */
7897 execve(bb_busybox_exec_path, argv, envp);
7898 /* If they called chroot or otherwise made the binary no longer
7899 * executable, fall through */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007900 }
7901#endif
7902
7903 repeat:
7904#ifdef SYSV
7905 do {
7906 execve(cmd, argv, envp);
7907 } while (errno == EINTR);
7908#else
7909 execve(cmd, argv, envp);
7910#endif
Denys Vlasenko00a1dbd2017-07-29 01:20:53 +02007911 if (cmd != bb_busybox_exec_path && errno == ENOEXEC) {
Denys Vlasenkoaefe1c22011-03-07 12:02:40 +01007912 /* Run "cmd" as a shell script:
7913 * http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html
7914 * "If the execve() function fails with ENOEXEC, the shell
7915 * shall execute a command equivalent to having a shell invoked
7916 * with the command name as its first operand,
7917 * with any remaining arguments passed to the new shell"
7918 *
7919 * That is, do not use $SHELL, user's shell, or /bin/sh;
7920 * just call ourselves.
Denys Vlasenko2bef5262011-12-16 00:25:17 +01007921 *
7922 * Note that bash reads ~80 chars of the file, and if it sees
7923 * a zero byte before it sees newline, it doesn't try to
7924 * interpret it, but fails with "cannot execute binary file"
Denys Vlasenkocda6ea92011-12-16 00:44:36 +01007925 * message and exit code 126. For one, this prevents attempts
7926 * to interpret foreign ELF binaries as shell scripts.
Denys Vlasenkoaefe1c22011-03-07 12:02:40 +01007927 */
Denys Vlasenko00a1dbd2017-07-29 01:20:53 +02007928 argv[0] = (char*) cmd;
7929 cmd = bb_busybox_exec_path;
Denys Vlasenko65a8b852016-10-26 22:29:11 +02007930 /* NB: this is only possible because all callers of shellexec()
7931 * ensure that the argv[-1] slot exists!
7932 */
7933 argv--;
7934 argv[0] = (char*) "ash";
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007935 goto repeat;
7936 }
7937}
7938
7939/*
7940 * Exec a program. Never returns. If you change this routine, you may
7941 * have to change the find_command routine as well.
Denys Vlasenko65a8b852016-10-26 22:29:11 +02007942 * argv[-1] must exist and be writable! See tryexec() for why.
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007943 */
Denys Vlasenkoe139ae32017-04-12 21:02:33 +02007944static void shellexec(char *prog, char **argv, const char *path, int idx) NORETURN;
7945static void shellexec(char *prog, char **argv, const char *path, int idx)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007946{
7947 char *cmdname;
7948 int e;
7949 char **envp;
7950 int exerrno;
Denys Vlasenko83f103b2011-12-20 06:10:35 +01007951 int applet_no = -1; /* used only by FEATURE_SH_STANDALONE */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007952
Denys Vlasenkoa5060b82017-11-03 14:16:25 +01007953 envp = listvars(VEXPORT, VUNSET, /*strlist:*/ NULL, /*end:*/ NULL);
Denys Vlasenkoe139ae32017-04-12 21:02:33 +02007954 if (strchr(prog, '/') != NULL
Denis Vlasenko80d14be2007-04-10 23:03:30 +00007955#if ENABLE_FEATURE_SH_STANDALONE
Denys Vlasenkoe139ae32017-04-12 21:02:33 +02007956 || (applet_no = find_applet_by_name(prog)) >= 0
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007957#endif
7958 ) {
Denys Vlasenkoe139ae32017-04-12 21:02:33 +02007959 tryexec(IF_FEATURE_SH_STANDALONE(applet_no,) prog, argv, envp);
Denys Vlasenko83f103b2011-12-20 06:10:35 +01007960 if (applet_no >= 0) {
7961 /* We tried execing ourself, but it didn't work.
7962 * Maybe /proc/self/exe doesn't exist?
7963 * Try $PATH search.
7964 */
7965 goto try_PATH;
7966 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007967 e = errno;
7968 } else {
Denys Vlasenko83f103b2011-12-20 06:10:35 +01007969 try_PATH:
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007970 e = ENOENT;
Denys Vlasenkoe139ae32017-04-12 21:02:33 +02007971 while ((cmdname = path_advance(&path, prog)) != NULL) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007972 if (--idx < 0 && pathopt == NULL) {
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00007973 tryexec(IF_FEATURE_SH_STANDALONE(-1,) cmdname, argv, envp);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007974 if (errno != ENOENT && errno != ENOTDIR)
7975 e = errno;
7976 }
7977 stunalloc(cmdname);
7978 }
7979 }
7980
7981 /* Map to POSIX errors */
7982 switch (e) {
7983 case EACCES:
7984 exerrno = 126;
7985 break;
7986 case ENOENT:
7987 exerrno = 127;
7988 break;
7989 default:
7990 exerrno = 2;
7991 break;
7992 }
7993 exitstatus = exerrno;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02007994 TRACE(("shellexec failed for %s, errno %d, suppress_int %d\n",
Denys Vlasenkoe139ae32017-04-12 21:02:33 +02007995 prog, e, suppress_int));
7996 ash_msg_and_raise(EXEXIT, "%s: %s", prog, errmsg(e, "not found"));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007997 /* NOTREACHED */
7998}
7999
8000static void
8001printentry(struct tblentry *cmdp)
8002{
8003 int idx;
8004 const char *path;
8005 char *name;
8006
8007 idx = cmdp->param.index;
8008 path = pathval();
8009 do {
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02008010 name = path_advance(&path, cmdp->cmdname);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008011 stunalloc(name);
8012 } while (--idx >= 0);
8013 out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr));
8014}
8015
8016/*
8017 * Clear out command entries. The argument specifies the first entry in
8018 * PATH which has changed.
8019 */
8020static void
8021clearcmdentry(int firstchange)
8022{
8023 struct tblentry **tblp;
8024 struct tblentry **pp;
8025 struct tblentry *cmdp;
8026
8027 INT_OFF;
8028 for (tblp = cmdtable; tblp < &cmdtable[CMDTABLESIZE]; tblp++) {
8029 pp = tblp;
8030 while ((cmdp = *pp) != NULL) {
8031 if ((cmdp->cmdtype == CMDNORMAL &&
8032 cmdp->param.index >= firstchange)
8033 || (cmdp->cmdtype == CMDBUILTIN &&
8034 builtinloc >= firstchange)
8035 ) {
8036 *pp = cmdp->next;
8037 free(cmdp);
8038 } else {
8039 pp = &cmdp->next;
8040 }
8041 }
8042 }
8043 INT_ON;
8044}
8045
8046/*
8047 * Locate a command in the command hash table. If "add" is nonzero,
8048 * add the command to the table if it is not already present. The
8049 * variable "lastcmdentry" is set to point to the address of the link
8050 * pointing to the entry, so that delete_cmd_entry can delete the
8051 * entry.
8052 *
8053 * Interrupts must be off if called with add != 0.
8054 */
8055static struct tblentry **lastcmdentry;
8056
8057static struct tblentry *
8058cmdlookup(const char *name, int add)
8059{
8060 unsigned int hashval;
8061 const char *p;
8062 struct tblentry *cmdp;
8063 struct tblentry **pp;
8064
8065 p = name;
8066 hashval = (unsigned char)*p << 4;
8067 while (*p)
8068 hashval += (unsigned char)*p++;
8069 hashval &= 0x7FFF;
8070 pp = &cmdtable[hashval % CMDTABLESIZE];
8071 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
8072 if (strcmp(cmdp->cmdname, name) == 0)
8073 break;
8074 pp = &cmdp->next;
8075 }
8076 if (add && cmdp == NULL) {
Denis Vlasenkob07a4962008-06-22 13:16:23 +00008077 cmdp = *pp = ckzalloc(sizeof(struct tblentry)
8078 + strlen(name)
8079 /* + 1 - already done because
8080 * tblentry::cmdname is char[1] */);
Denis Vlasenko597906c2008-02-20 16:38:54 +00008081 /*cmdp->next = NULL; - ckzalloc did it */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008082 cmdp->cmdtype = CMDUNKNOWN;
8083 strcpy(cmdp->cmdname, name);
8084 }
8085 lastcmdentry = pp;
8086 return cmdp;
8087}
8088
8089/*
8090 * Delete the command entry returned on the last lookup.
8091 */
8092static void
8093delete_cmd_entry(void)
8094{
8095 struct tblentry *cmdp;
8096
8097 INT_OFF;
8098 cmdp = *lastcmdentry;
8099 *lastcmdentry = cmdp->next;
8100 if (cmdp->cmdtype == CMDFUNCTION)
8101 freefunc(cmdp->param.func);
8102 free(cmdp);
8103 INT_ON;
8104}
8105
8106/*
8107 * Add a new command entry, replacing any existing command entry for
8108 * the same name - except special builtins.
8109 */
8110static void
8111addcmdentry(char *name, struct cmdentry *entry)
8112{
8113 struct tblentry *cmdp;
8114
8115 cmdp = cmdlookup(name, 1);
8116 if (cmdp->cmdtype == CMDFUNCTION) {
8117 freefunc(cmdp->param.func);
8118 }
8119 cmdp->cmdtype = entry->cmdtype;
8120 cmdp->param = entry->u;
8121 cmdp->rehash = 0;
8122}
8123
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02008124static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00008125hashcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008126{
8127 struct tblentry **pp;
8128 struct tblentry *cmdp;
8129 int c;
8130 struct cmdentry entry;
8131 char *name;
8132
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008133 if (nextopt("r") != '\0') {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008134 clearcmdentry(0);
8135 return 0;
8136 }
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008137
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008138 if (*argptr == NULL) {
8139 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
8140 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
8141 if (cmdp->cmdtype == CMDNORMAL)
8142 printentry(cmdp);
8143 }
8144 }
8145 return 0;
8146 }
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008147
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008148 c = 0;
8149 while ((name = *argptr) != NULL) {
8150 cmdp = cmdlookup(name, 0);
8151 if (cmdp != NULL
8152 && (cmdp->cmdtype == CMDNORMAL
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008153 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))
8154 ) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008155 delete_cmd_entry();
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008156 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008157 find_command(name, &entry, DO_ERR, pathval());
8158 if (entry.cmdtype == CMDUNKNOWN)
8159 c = 1;
8160 argptr++;
8161 }
8162 return c;
8163}
8164
8165/*
8166 * Called when a cd is done. Marks all commands so the next time they
8167 * are executed they will be rehashed.
8168 */
8169static void
8170hashcd(void)
8171{
8172 struct tblentry **pp;
8173 struct tblentry *cmdp;
8174
8175 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
8176 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008177 if (cmdp->cmdtype == CMDNORMAL
8178 || (cmdp->cmdtype == CMDBUILTIN
Denys Vlasenkoe4dcba12010-10-28 18:57:19 +02008179 && !IS_BUILTIN_REGULAR(cmdp->param.cmd)
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008180 && builtinloc > 0)
8181 ) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008182 cmdp->rehash = 1;
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008183 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008184 }
8185 }
8186}
8187
8188/*
8189 * Fix command hash table when PATH changed.
8190 * Called before PATH is changed. The argument is the new value of PATH;
8191 * pathval() still returns the old value at this point.
8192 * Called with interrupts off.
8193 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02008194static void FAST_FUNC
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008195changepath(const char *new)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008196{
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008197 const char *old;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008198 int firstchange;
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008199 int idx;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008200 int idx_bltin;
8201
8202 old = pathval();
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008203 firstchange = 9999; /* assume no change */
8204 idx = 0;
8205 idx_bltin = -1;
8206 for (;;) {
8207 if (*old != *new) {
8208 firstchange = idx;
8209 if ((*old == '\0' && *new == ':')
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +02008210 || (*old == ':' && *new == '\0')
8211 ) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008212 firstchange++;
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +02008213 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008214 old = new; /* ignore subsequent differences */
8215 }
8216 if (*new == '\0')
8217 break;
8218 if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin"))
8219 idx_bltin = idx;
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008220 if (*new == ':')
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008221 idx++;
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +02008222 new++;
8223 old++;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008224 }
8225 if (builtinloc < 0 && idx_bltin >= 0)
8226 builtinloc = idx_bltin; /* zap builtins */
8227 if (builtinloc >= 0 && idx_bltin < 0)
8228 firstchange = 0;
8229 clearcmdentry(firstchange);
8230 builtinloc = idx_bltin;
8231}
Ron Yorston95ebcf72015-11-03 09:42:23 +00008232enum {
8233 TEOF,
8234 TNL,
8235 TREDIR,
8236 TWORD,
8237 TSEMI,
8238 TBACKGND,
8239 TAND,
8240 TOR,
8241 TPIPE,
8242 TLP,
8243 TRP,
8244 TENDCASE,
8245 TENDBQUOTE,
8246 TNOT,
8247 TCASE,
8248 TDO,
8249 TDONE,
8250 TELIF,
8251 TELSE,
8252 TESAC,
8253 TFI,
8254 TFOR,
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01008255#if BASH_FUNCTION
Ron Yorston95ebcf72015-11-03 09:42:23 +00008256 TFUNCTION,
8257#endif
8258 TIF,
8259 TIN,
8260 TTHEN,
8261 TUNTIL,
8262 TWHILE,
8263 TBEGIN,
8264 TEND
8265};
Denis Vlasenkob07a4962008-06-22 13:16:23 +00008266typedef smallint token_id_t;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008267
Denys Vlasenko888527c2016-10-02 16:54:17 +02008268/* Nth bit indicates if token marks the end of a list */
8269enum {
8270 tokendlist = 0
8271 /* 0 */ | (1u << TEOF)
8272 /* 1 */ | (0u << TNL)
8273 /* 2 */ | (0u << TREDIR)
8274 /* 3 */ | (0u << TWORD)
8275 /* 4 */ | (0u << TSEMI)
8276 /* 5 */ | (0u << TBACKGND)
8277 /* 6 */ | (0u << TAND)
8278 /* 7 */ | (0u << TOR)
8279 /* 8 */ | (0u << TPIPE)
8280 /* 9 */ | (0u << TLP)
8281 /* 10 */ | (1u << TRP)
8282 /* 11 */ | (1u << TENDCASE)
8283 /* 12 */ | (1u << TENDBQUOTE)
8284 /* 13 */ | (0u << TNOT)
8285 /* 14 */ | (0u << TCASE)
8286 /* 15 */ | (1u << TDO)
8287 /* 16 */ | (1u << TDONE)
8288 /* 17 */ | (1u << TELIF)
8289 /* 18 */ | (1u << TELSE)
8290 /* 19 */ | (1u << TESAC)
8291 /* 20 */ | (1u << TFI)
8292 /* 21 */ | (0u << TFOR)
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01008293#if BASH_FUNCTION
Denys Vlasenko888527c2016-10-02 16:54:17 +02008294 /* 22 */ | (0u << TFUNCTION)
Denys Vlasenko80729a42016-10-02 22:33:15 +02008295#endif
Denys Vlasenko888527c2016-10-02 16:54:17 +02008296 /* 23 */ | (0u << TIF)
8297 /* 24 */ | (0u << TIN)
8298 /* 25 */ | (1u << TTHEN)
8299 /* 26 */ | (0u << TUNTIL)
8300 /* 27 */ | (0u << TWHILE)
8301 /* 28 */ | (0u << TBEGIN)
8302 /* 29 */ | (1u << TEND)
8303 , /* thus far 29 bits used */
8304};
8305
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008306static const char *const tokname_array[] = {
Denys Vlasenko888527c2016-10-02 16:54:17 +02008307 "end of file",
8308 "newline",
8309 "redirection",
8310 "word",
8311 ";",
8312 "&",
8313 "&&",
8314 "||",
8315 "|",
8316 "(",
8317 ")",
8318 ";;",
8319 "`",
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008320#define KWDOFFSET 13
8321 /* the following are keywords */
Denys Vlasenko888527c2016-10-02 16:54:17 +02008322 "!",
8323 "case",
8324 "do",
8325 "done",
8326 "elif",
8327 "else",
8328 "esac",
8329 "fi",
8330 "for",
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01008331#if BASH_FUNCTION
Denys Vlasenko888527c2016-10-02 16:54:17 +02008332 "function",
Ron Yorston95ebcf72015-11-03 09:42:23 +00008333#endif
Denys Vlasenko888527c2016-10-02 16:54:17 +02008334 "if",
8335 "in",
8336 "then",
8337 "until",
8338 "while",
8339 "{",
8340 "}",
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008341};
8342
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008343/* Wrapper around strcmp for qsort/bsearch/... */
8344static int
8345pstrcmp(const void *a, const void *b)
8346{
Denys Vlasenko888527c2016-10-02 16:54:17 +02008347 return strcmp((char*)a, *(char**)b);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008348}
8349
8350static const char *const *
8351findkwd(const char *s)
8352{
8353 return bsearch(s, tokname_array + KWDOFFSET,
Denis Vlasenko80b8b392007-06-25 10:55:35 +00008354 ARRAY_SIZE(tokname_array) - KWDOFFSET,
8355 sizeof(tokname_array[0]), pstrcmp);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008356}
8357
8358/*
8359 * Locate and print what a word is...
8360 */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008361static int
Ron Yorston3f221112015-08-03 13:47:33 +01008362describe_command(char *command, const char *path, int describe_command_verbose)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008363{
8364 struct cmdentry entry;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008365#if ENABLE_ASH_ALIAS
8366 const struct alias *ap;
8367#endif
Ron Yorston3f221112015-08-03 13:47:33 +01008368
8369 path = path ? path : pathval();
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008370
8371 if (describe_command_verbose) {
8372 out1str(command);
8373 }
8374
8375 /* First look at the keywords */
8376 if (findkwd(command)) {
8377 out1str(describe_command_verbose ? " is a shell keyword" : command);
8378 goto out;
8379 }
8380
8381#if ENABLE_ASH_ALIAS
8382 /* Then look at the aliases */
8383 ap = lookupalias(command, 0);
8384 if (ap != NULL) {
Denis Vlasenko46846e22007-05-20 13:08:31 +00008385 if (!describe_command_verbose) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008386 out1str("alias ");
8387 printalias(ap);
8388 return 0;
8389 }
Denis Vlasenko46846e22007-05-20 13:08:31 +00008390 out1fmt(" is an alias for %s", ap->val);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008391 goto out;
8392 }
8393#endif
Youfu Zhang6683d1c2017-05-26 15:31:29 +08008394 /* Brute force */
8395 find_command(command, &entry, DO_ABS, path);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008396
8397 switch (entry.cmdtype) {
8398 case CMDNORMAL: {
8399 int j = entry.u.index;
8400 char *p;
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00008401 if (j < 0) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008402 p = command;
8403 } else {
8404 do {
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02008405 p = path_advance(&path, command);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008406 stunalloc(p);
8407 } while (--j >= 0);
8408 }
8409 if (describe_command_verbose) {
Youfu Zhang6683d1c2017-05-26 15:31:29 +08008410 out1fmt(" is %s", p);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008411 } else {
8412 out1str(p);
8413 }
8414 break;
8415 }
8416
8417 case CMDFUNCTION:
8418 if (describe_command_verbose) {
8419 out1str(" is a shell function");
8420 } else {
8421 out1str(command);
8422 }
8423 break;
8424
8425 case CMDBUILTIN:
8426 if (describe_command_verbose) {
8427 out1fmt(" is a %sshell builtin",
8428 IS_BUILTIN_SPECIAL(entry.u.cmd) ?
8429 "special " : nullstr
8430 );
8431 } else {
8432 out1str(command);
8433 }
8434 break;
8435
8436 default:
8437 if (describe_command_verbose) {
8438 out1str(": not found\n");
8439 }
8440 return 127;
8441 }
8442 out:
Denys Vlasenko285ad152009-12-04 23:02:27 +01008443 out1str("\n");
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008444 return 0;
8445}
8446
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02008447static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00008448typecmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008449{
Denis Vlasenko46846e22007-05-20 13:08:31 +00008450 int i = 1;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008451 int err = 0;
Denis Vlasenko46846e22007-05-20 13:08:31 +00008452 int verbose = 1;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008453
Denis Vlasenko46846e22007-05-20 13:08:31 +00008454 /* type -p ... ? (we don't bother checking for 'p') */
Denis Vlasenko1fc62382007-06-25 22:55:34 +00008455 if (argv[1] && argv[1][0] == '-') {
Denis Vlasenko46846e22007-05-20 13:08:31 +00008456 i++;
8457 verbose = 0;
8458 }
Denis Vlasenko68404f12008-03-17 09:00:54 +00008459 while (argv[i]) {
Ron Yorston3f221112015-08-03 13:47:33 +01008460 err |= describe_command(argv[i++], NULL, verbose);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008461 }
8462 return err;
8463}
8464
8465#if ENABLE_ASH_CMDCMD
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008466/* Is it "command [-p] PROG ARGS" bltin, no other opts? Return ptr to "PROG" if yes */
8467static char **
8468parse_command_args(char **argv, const char **path)
8469{
8470 char *cp, c;
8471
8472 for (;;) {
8473 cp = *++argv;
8474 if (!cp)
8475 return NULL;
8476 if (*cp++ != '-')
8477 break;
8478 c = *cp++;
8479 if (!c)
8480 break;
8481 if (c == '-' && !*cp) {
8482 if (!*++argv)
8483 return NULL;
8484 break;
8485 }
8486 do {
8487 switch (c) {
8488 case 'p':
8489 *path = bb_default_path;
8490 break;
8491 default:
8492 /* run 'typecmd' for other options */
8493 return NULL;
8494 }
8495 c = *cp++;
8496 } while (c);
8497 }
8498 return argv;
8499}
8500
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02008501static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00008502commandcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008503{
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008504 char *cmd;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008505 int c;
8506 enum {
8507 VERIFY_BRIEF = 1,
8508 VERIFY_VERBOSE = 2,
8509 } verify = 0;
Ron Yorston3f221112015-08-03 13:47:33 +01008510 const char *path = NULL;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008511
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008512 /* "command [-p] PROG ARGS" (that is, without -V or -v)
8513 * never reaches this function.
8514 */
8515
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008516 while ((c = nextopt("pvV")) != '\0')
8517 if (c == 'V')
8518 verify |= VERIFY_VERBOSE;
8519 else if (c == 'v')
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008520 /*verify |= VERIFY_BRIEF*/;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008521#if DEBUG
8522 else if (c != 'p')
8523 abort();
8524#endif
Ron Yorston3f221112015-08-03 13:47:33 +01008525 else
8526 path = bb_default_path;
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008527
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00008528 /* Mimic bash: just "command -v" doesn't complain, it's a nop */
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008529 cmd = *argptr;
8530 if (/*verify && */ cmd)
8531 return describe_command(cmd, path, verify /* - VERIFY_BRIEF*/);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008532
8533 return 0;
8534}
8535#endif
8536
8537
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008538/*static int funcblocksize; // size of structures in function */
8539/*static int funcstringsize; // size of strings in node */
Denis Vlasenko340299a2008-11-21 10:36:36 +00008540static void *funcblock; /* block to allocate function from */
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008541static char *funcstring_end; /* end of block to allocate strings from */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008542
Denys Vlasenko3e134eb2016-04-22 18:09:21 +02008543static const uint8_t nodesize[N_NUMBER] ALIGN1 = {
Denis Vlasenko340299a2008-11-21 10:36:36 +00008544 [NCMD ] = SHELL_ALIGN(sizeof(struct ncmd)),
8545 [NPIPE ] = SHELL_ALIGN(sizeof(struct npipe)),
8546 [NREDIR ] = SHELL_ALIGN(sizeof(struct nredir)),
8547 [NBACKGND ] = SHELL_ALIGN(sizeof(struct nredir)),
8548 [NSUBSHELL] = SHELL_ALIGN(sizeof(struct nredir)),
8549 [NAND ] = SHELL_ALIGN(sizeof(struct nbinary)),
8550 [NOR ] = SHELL_ALIGN(sizeof(struct nbinary)),
8551 [NSEMI ] = SHELL_ALIGN(sizeof(struct nbinary)),
8552 [NIF ] = SHELL_ALIGN(sizeof(struct nif)),
8553 [NWHILE ] = SHELL_ALIGN(sizeof(struct nbinary)),
8554 [NUNTIL ] = SHELL_ALIGN(sizeof(struct nbinary)),
8555 [NFOR ] = SHELL_ALIGN(sizeof(struct nfor)),
8556 [NCASE ] = SHELL_ALIGN(sizeof(struct ncase)),
8557 [NCLIST ] = SHELL_ALIGN(sizeof(struct nclist)),
8558 [NDEFUN ] = SHELL_ALIGN(sizeof(struct narg)),
8559 [NARG ] = SHELL_ALIGN(sizeof(struct narg)),
8560 [NTO ] = SHELL_ALIGN(sizeof(struct nfile)),
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01008561#if BASH_REDIR_OUTPUT
Denis Vlasenko340299a2008-11-21 10:36:36 +00008562 [NTO2 ] = SHELL_ALIGN(sizeof(struct nfile)),
Denis Vlasenkocc5feab2008-11-22 01:32:40 +00008563#endif
Denis Vlasenko340299a2008-11-21 10:36:36 +00008564 [NCLOBBER ] = SHELL_ALIGN(sizeof(struct nfile)),
8565 [NFROM ] = SHELL_ALIGN(sizeof(struct nfile)),
8566 [NFROMTO ] = SHELL_ALIGN(sizeof(struct nfile)),
8567 [NAPPEND ] = SHELL_ALIGN(sizeof(struct nfile)),
8568 [NTOFD ] = SHELL_ALIGN(sizeof(struct ndup)),
8569 [NFROMFD ] = SHELL_ALIGN(sizeof(struct ndup)),
8570 [NHERE ] = SHELL_ALIGN(sizeof(struct nhere)),
8571 [NXHERE ] = SHELL_ALIGN(sizeof(struct nhere)),
8572 [NNOT ] = SHELL_ALIGN(sizeof(struct nnot)),
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008573};
8574
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008575static int calcsize(int funcblocksize, union node *n);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008576
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008577static int
8578sizenodelist(int funcblocksize, struct nodelist *lp)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008579{
8580 while (lp) {
8581 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008582 funcblocksize = calcsize(funcblocksize, lp->n);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008583 lp = lp->next;
8584 }
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008585 return funcblocksize;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008586}
8587
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008588static int
8589calcsize(int funcblocksize, union node *n)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008590{
8591 if (n == NULL)
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008592 return funcblocksize;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008593 funcblocksize += nodesize[n->type];
8594 switch (n->type) {
8595 case NCMD:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008596 funcblocksize = calcsize(funcblocksize, n->ncmd.redirect);
8597 funcblocksize = calcsize(funcblocksize, n->ncmd.args);
8598 funcblocksize = calcsize(funcblocksize, n->ncmd.assign);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008599 break;
8600 case NPIPE:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008601 funcblocksize = sizenodelist(funcblocksize, n->npipe.cmdlist);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008602 break;
8603 case NREDIR:
8604 case NBACKGND:
8605 case NSUBSHELL:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008606 funcblocksize = calcsize(funcblocksize, n->nredir.redirect);
8607 funcblocksize = calcsize(funcblocksize, n->nredir.n);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008608 break;
8609 case NAND:
8610 case NOR:
8611 case NSEMI:
8612 case NWHILE:
8613 case NUNTIL:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008614 funcblocksize = calcsize(funcblocksize, n->nbinary.ch2);
8615 funcblocksize = calcsize(funcblocksize, n->nbinary.ch1);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008616 break;
8617 case NIF:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008618 funcblocksize = calcsize(funcblocksize, n->nif.elsepart);
8619 funcblocksize = calcsize(funcblocksize, n->nif.ifpart);
8620 funcblocksize = calcsize(funcblocksize, n->nif.test);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008621 break;
8622 case NFOR:
Denys Vlasenko561639a2016-10-07 04:28:33 +02008623 funcblocksize += SHELL_ALIGN(strlen(n->nfor.var) + 1); /* was funcstringsize += ... */
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008624 funcblocksize = calcsize(funcblocksize, n->nfor.body);
8625 funcblocksize = calcsize(funcblocksize, n->nfor.args);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008626 break;
8627 case NCASE:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008628 funcblocksize = calcsize(funcblocksize, n->ncase.cases);
8629 funcblocksize = calcsize(funcblocksize, n->ncase.expr);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008630 break;
8631 case NCLIST:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008632 funcblocksize = calcsize(funcblocksize, n->nclist.body);
8633 funcblocksize = calcsize(funcblocksize, n->nclist.pattern);
8634 funcblocksize = calcsize(funcblocksize, n->nclist.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008635 break;
8636 case NDEFUN:
8637 case NARG:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008638 funcblocksize = sizenodelist(funcblocksize, n->narg.backquote);
Denys Vlasenko561639a2016-10-07 04:28:33 +02008639 funcblocksize += SHELL_ALIGN(strlen(n->narg.text) + 1); /* was funcstringsize += ... */
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008640 funcblocksize = calcsize(funcblocksize, n->narg.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008641 break;
8642 case NTO:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01008643#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00008644 case NTO2:
8645#endif
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008646 case NCLOBBER:
8647 case NFROM:
8648 case NFROMTO:
8649 case NAPPEND:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008650 funcblocksize = calcsize(funcblocksize, n->nfile.fname);
8651 funcblocksize = calcsize(funcblocksize, n->nfile.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008652 break;
8653 case NTOFD:
8654 case NFROMFD:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008655 funcblocksize = calcsize(funcblocksize, n->ndup.vname);
8656 funcblocksize = calcsize(funcblocksize, n->ndup.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008657 break;
8658 case NHERE:
8659 case NXHERE:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008660 funcblocksize = calcsize(funcblocksize, n->nhere.doc);
8661 funcblocksize = calcsize(funcblocksize, n->nhere.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008662 break;
8663 case NNOT:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008664 funcblocksize = calcsize(funcblocksize, n->nnot.com);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008665 break;
8666 };
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008667 return funcblocksize;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008668}
8669
8670static char *
8671nodeckstrdup(char *s)
8672{
Denys Vlasenko561639a2016-10-07 04:28:33 +02008673 funcstring_end -= SHELL_ALIGN(strlen(s) + 1);
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008674 return strcpy(funcstring_end, s);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008675}
8676
8677static union node *copynode(union node *);
8678
8679static struct nodelist *
8680copynodelist(struct nodelist *lp)
8681{
8682 struct nodelist *start;
8683 struct nodelist **lpp;
8684
8685 lpp = &start;
8686 while (lp) {
8687 *lpp = funcblock;
8688 funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist));
8689 (*lpp)->n = copynode(lp->n);
8690 lp = lp->next;
8691 lpp = &(*lpp)->next;
8692 }
8693 *lpp = NULL;
8694 return start;
8695}
8696
8697static union node *
8698copynode(union node *n)
8699{
8700 union node *new;
8701
8702 if (n == NULL)
8703 return NULL;
8704 new = funcblock;
8705 funcblock = (char *) funcblock + nodesize[n->type];
8706
8707 switch (n->type) {
8708 case NCMD:
8709 new->ncmd.redirect = copynode(n->ncmd.redirect);
8710 new->ncmd.args = copynode(n->ncmd.args);
8711 new->ncmd.assign = copynode(n->ncmd.assign);
8712 break;
8713 case NPIPE:
8714 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00008715 new->npipe.pipe_backgnd = n->npipe.pipe_backgnd;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008716 break;
8717 case NREDIR:
8718 case NBACKGND:
8719 case NSUBSHELL:
8720 new->nredir.redirect = copynode(n->nredir.redirect);
8721 new->nredir.n = copynode(n->nredir.n);
8722 break;
8723 case NAND:
8724 case NOR:
8725 case NSEMI:
8726 case NWHILE:
8727 case NUNTIL:
8728 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8729 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8730 break;
8731 case NIF:
8732 new->nif.elsepart = copynode(n->nif.elsepart);
8733 new->nif.ifpart = copynode(n->nif.ifpart);
8734 new->nif.test = copynode(n->nif.test);
8735 break;
8736 case NFOR:
8737 new->nfor.var = nodeckstrdup(n->nfor.var);
8738 new->nfor.body = copynode(n->nfor.body);
8739 new->nfor.args = copynode(n->nfor.args);
8740 break;
8741 case NCASE:
8742 new->ncase.cases = copynode(n->ncase.cases);
8743 new->ncase.expr = copynode(n->ncase.expr);
8744 break;
8745 case NCLIST:
8746 new->nclist.body = copynode(n->nclist.body);
8747 new->nclist.pattern = copynode(n->nclist.pattern);
8748 new->nclist.next = copynode(n->nclist.next);
8749 break;
8750 case NDEFUN:
8751 case NARG:
8752 new->narg.backquote = copynodelist(n->narg.backquote);
8753 new->narg.text = nodeckstrdup(n->narg.text);
8754 new->narg.next = copynode(n->narg.next);
8755 break;
8756 case NTO:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01008757#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00008758 case NTO2:
8759#endif
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008760 case NCLOBBER:
8761 case NFROM:
8762 case NFROMTO:
8763 case NAPPEND:
8764 new->nfile.fname = copynode(n->nfile.fname);
8765 new->nfile.fd = n->nfile.fd;
8766 new->nfile.next = copynode(n->nfile.next);
8767 break;
8768 case NTOFD:
8769 case NFROMFD:
8770 new->ndup.vname = copynode(n->ndup.vname);
8771 new->ndup.dupfd = n->ndup.dupfd;
8772 new->ndup.fd = n->ndup.fd;
8773 new->ndup.next = copynode(n->ndup.next);
8774 break;
8775 case NHERE:
8776 case NXHERE:
8777 new->nhere.doc = copynode(n->nhere.doc);
8778 new->nhere.fd = n->nhere.fd;
8779 new->nhere.next = copynode(n->nhere.next);
8780 break;
8781 case NNOT:
8782 new->nnot.com = copynode(n->nnot.com);
8783 break;
8784 };
8785 new->type = n->type;
8786 return new;
8787}
8788
8789/*
8790 * Make a copy of a parse tree.
8791 */
8792static struct funcnode *
8793copyfunc(union node *n)
8794{
8795 struct funcnode *f;
8796 size_t blocksize;
8797
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008798 /*funcstringsize = 0;*/
8799 blocksize = offsetof(struct funcnode, n) + calcsize(0, n);
8800 f = ckzalloc(blocksize /* + funcstringsize */);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008801 funcblock = (char *) f + offsetof(struct funcnode, n);
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008802 funcstring_end = (char *) f + blocksize;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008803 copynode(n);
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008804 /* f->count = 0; - ckzalloc did it */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008805 return f;
8806}
8807
8808/*
8809 * Define a shell function.
8810 */
8811static void
Denys Vlasenko7aec8682016-10-25 20:26:02 +02008812defun(union node *func)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008813{
8814 struct cmdentry entry;
8815
8816 INT_OFF;
8817 entry.cmdtype = CMDFUNCTION;
8818 entry.u.func = copyfunc(func);
Denys Vlasenko7aec8682016-10-25 20:26:02 +02008819 addcmdentry(func->narg.text, &entry);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008820 INT_ON;
8821}
8822
Denis Vlasenko4b875702009-03-19 13:30:04 +00008823/* Reasons for skipping commands (see comment on breakcmd routine) */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008824#define SKIPBREAK (1 << 0)
8825#define SKIPCONT (1 << 1)
8826#define SKIPFUNC (1 << 2)
Denis Vlasenko4b875702009-03-19 13:30:04 +00008827static smallint evalskip; /* set to SKIPxxx if we are skipping commands */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008828static int skipcount; /* number of levels to skip */
8829static int funcnest; /* depth of function calls */
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +00008830static int loopnest; /* current loop nesting level */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008831
Denis Vlasenko4b875702009-03-19 13:30:04 +00008832/* Forward decl way out to parsing code - dotrap needs it */
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02008833static int evalstring(char *s, int flags);
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008834
Denis Vlasenko4b875702009-03-19 13:30:04 +00008835/* Called to execute a trap.
8836 * Single callsite - at the end of evaltree().
Denys Vlasenkob563f622010-09-25 17:15:13 +02008837 * If we return non-zero, evaltree raises EXEXIT exception.
Denis Vlasenko4b875702009-03-19 13:30:04 +00008838 *
8839 * Perhaps we should avoid entering new trap handlers
8840 * while we are executing a trap handler. [is it a TODO?]
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008841 */
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008842static void
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008843dotrap(void)
8844{
Denis Vlasenko4b875702009-03-19 13:30:04 +00008845 uint8_t *g;
8846 int sig;
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008847 uint8_t last_status;
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008848
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008849 if (!pending_sig)
8850 return;
8851
8852 last_status = exitstatus;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02008853 pending_sig = 0;
Denys Vlasenkode892052016-10-02 01:49:13 +02008854 barrier();
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008855
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008856 TRACE(("dotrap entered\n"));
Denis Vlasenko4b875702009-03-19 13:30:04 +00008857 for (sig = 1, g = gotsig; sig < NSIG; sig++, g++) {
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008858 char *p;
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008859
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008860 if (!*g)
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008861 continue;
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008862
8863 if (evalskip) {
8864 pending_sig = sig;
8865 break;
8866 }
8867
8868 p = trap[sig];
Denis Vlasenko4b875702009-03-19 13:30:04 +00008869 /* non-trapped SIGINT is handled separately by raise_interrupt,
8870 * don't upset it by resetting gotsig[SIGINT-1] */
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008871 if (sig == SIGINT && !p)
Denis Vlasenko4b875702009-03-19 13:30:04 +00008872 continue;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008873
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008874 TRACE(("sig %d is active, will run handler '%s'\n", sig, p));
Denis Vlasenko4b875702009-03-19 13:30:04 +00008875 *g = 0;
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008876 if (!p)
Denis Vlasenko4b875702009-03-19 13:30:04 +00008877 continue;
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008878 evalstring(p, 0);
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008879 }
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008880 exitstatus = last_status;
8881 TRACE(("dotrap returns\n"));
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008882}
8883
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00008884/* forward declarations - evaluation is fairly recursive business... */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008885static int evalloop(union node *, int);
8886static int evalfor(union node *, int);
8887static int evalcase(union node *, int);
8888static int evalsubshell(union node *, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008889static void expredir(union node *);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008890static int evalpipe(union node *, int);
8891static int evalcommand(union node *, int);
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02008892static int evalbltin(const struct builtincmd *, int, char **, int);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008893static void prehash(union node *);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008894
Eric Andersen62483552001-07-10 06:09:16 +00008895/*
Eric Andersenc470f442003-07-28 09:56:35 +00008896 * Evaluate a parse tree. The value is left in the global variable
8897 * exitstatus.
Eric Andersen62483552001-07-10 06:09:16 +00008898 */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008899static int
Eric Andersenc470f442003-07-28 09:56:35 +00008900evaltree(union node *n, int flags)
Eric Andersen62483552001-07-10 06:09:16 +00008901{
Eric Andersenc470f442003-07-28 09:56:35 +00008902 int checkexit = 0;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008903 int (*evalfn)(union node *, int);
8904 int status = 0;
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008905
Eric Andersenc470f442003-07-28 09:56:35 +00008906 if (n == NULL) {
8907 TRACE(("evaltree(NULL) called\n"));
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02008908 goto out;
Eric Andersen62483552001-07-10 06:09:16 +00008909 }
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008910 TRACE(("evaltree(%p: %d, %d) called\n", n, n->type, flags));
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008911
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008912 dotrap();
8913
Eric Andersenc470f442003-07-28 09:56:35 +00008914 switch (n->type) {
8915 default:
Denis Vlasenkoa7189f02006-11-17 20:29:00 +00008916#if DEBUG
Eric Andersenc470f442003-07-28 09:56:35 +00008917 out1fmt("Node type = %d\n", n->type);
Denys Vlasenko8131eea2009-11-02 14:19:51 +01008918 fflush_all();
Eric Andersenc470f442003-07-28 09:56:35 +00008919 break;
8920#endif
8921 case NNOT:
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008922 status = !evaltree(n->nnot.com, EV_TESTED);
Eric Andersenc470f442003-07-28 09:56:35 +00008923 goto setstatus;
8924 case NREDIR:
8925 expredir(n->nredir.redirect);
Denys Vlasenko1c79aeb2017-07-29 22:51:52 +02008926 pushredir(n->nredir.redirect);
Eric Andersenc470f442003-07-28 09:56:35 +00008927 status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
8928 if (!status) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008929 status = evaltree(n->nredir.n, flags & EV_TESTED);
Eric Andersenc470f442003-07-28 09:56:35 +00008930 }
Denys Vlasenkoeaf94362016-10-25 21:46:03 +02008931 if (n->nredir.redirect)
Denys Vlasenko035486c2017-07-31 04:09:19 +02008932 popredir(/*drop:*/ 0);
Eric Andersenc470f442003-07-28 09:56:35 +00008933 goto setstatus;
8934 case NCMD:
8935 evalfn = evalcommand;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008936 checkexit:
Eric Andersenc470f442003-07-28 09:56:35 +00008937 if (eflag && !(flags & EV_TESTED))
8938 checkexit = ~0;
8939 goto calleval;
8940 case NFOR:
8941 evalfn = evalfor;
8942 goto calleval;
8943 case NWHILE:
8944 case NUNTIL:
8945 evalfn = evalloop;
8946 goto calleval;
8947 case NSUBSHELL:
8948 case NBACKGND:
8949 evalfn = evalsubshell;
Denys Vlasenkocf98b0c2016-10-25 18:19:39 +02008950 goto checkexit;
Eric Andersenc470f442003-07-28 09:56:35 +00008951 case NPIPE:
8952 evalfn = evalpipe;
8953 goto checkexit;
8954 case NCASE:
8955 evalfn = evalcase;
8956 goto calleval;
8957 case NAND:
8958 case NOR:
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008959 case NSEMI: {
8960
Eric Andersenc470f442003-07-28 09:56:35 +00008961#if NAND + 1 != NOR
8962#error NAND + 1 != NOR
8963#endif
8964#if NOR + 1 != NSEMI
8965#error NOR + 1 != NSEMI
8966#endif
Denis Vlasenko87d5fd92008-07-26 13:48:35 +00008967 unsigned is_or = n->type - NAND;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008968 status = evaltree(
Eric Andersenc470f442003-07-28 09:56:35 +00008969 n->nbinary.ch1,
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008970 (flags | ((is_or >> 1) - 1)) & EV_TESTED
Eric Andersenc470f442003-07-28 09:56:35 +00008971 );
Denys Vlasenkobc1a0082016-10-02 15:31:33 +02008972 if ((!status) == is_or || evalskip)
Eric Andersenc470f442003-07-28 09:56:35 +00008973 break;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008974 n = n->nbinary.ch2;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008975 evaln:
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008976 evalfn = evaltree;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008977 calleval:
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008978 status = evalfn(n, flags);
8979 goto setstatus;
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008980 }
Eric Andersenc470f442003-07-28 09:56:35 +00008981 case NIF:
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008982 status = evaltree(n->nif.test, EV_TESTED);
Eric Andersenc470f442003-07-28 09:56:35 +00008983 if (evalskip)
8984 break;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008985 if (!status) {
Eric Andersenc470f442003-07-28 09:56:35 +00008986 n = n->nif.ifpart;
8987 goto evaln;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008988 }
8989 if (n->nif.elsepart) {
Eric Andersenc470f442003-07-28 09:56:35 +00008990 n = n->nif.elsepart;
8991 goto evaln;
8992 }
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008993 status = 0;
8994 goto setstatus;
Eric Andersenc470f442003-07-28 09:56:35 +00008995 case NDEFUN:
Denys Vlasenko7aec8682016-10-25 20:26:02 +02008996 defun(n);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008997 /* Not necessary. To test it:
8998 * "false; f() { qwerty; }; echo $?" should print 0.
8999 */
9000 /* status = 0; */
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009001 setstatus:
Eric Andersenc470f442003-07-28 09:56:35 +00009002 exitstatus = status;
9003 break;
9004 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009005 out:
Denys Vlasenkob563f622010-09-25 17:15:13 +02009006 /* Order of checks below is important:
9007 * signal handlers trigger before exit caused by "set -e".
9008 */
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02009009 dotrap();
9010
9011 if (checkexit & status)
Denis Vlasenkob012b102007-02-19 22:43:01 +00009012 raise_exception(EXEXIT);
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02009013 if (flags & EV_EXIT)
9014 raise_exception(EXEXIT);
Denis Vlasenko653d8e72009-03-19 21:59:35 +00009015
Denis Vlasenko653d8e72009-03-19 21:59:35 +00009016 TRACE(("leaving evaltree (no interrupts)\n"));
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009017 return exitstatus;
Eric Andersen62483552001-07-10 06:09:16 +00009018}
9019
Denys Vlasenko37dc08b2016-10-02 04:38:07 +02009020static int
9021skiploop(void)
Denys Vlasenko35ec8182016-10-01 19:56:52 +02009022{
9023 int skip = evalskip;
9024
9025 switch (skip) {
9026 case 0:
9027 break;
9028 case SKIPBREAK:
9029 case SKIPCONT:
9030 if (--skipcount <= 0) {
9031 evalskip = 0;
9032 break;
9033 }
9034 skip = SKIPBREAK;
9035 break;
9036 }
9037 return skip;
9038}
9039
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009040static int
Eric Andersenc470f442003-07-28 09:56:35 +00009041evalloop(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00009042{
Denys Vlasenko35ec8182016-10-01 19:56:52 +02009043 int skip;
Eric Andersencb57d552001-06-28 07:25:16 +00009044 int status;
9045
9046 loopnest++;
9047 status = 0;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009048 flags &= EV_TESTED;
Denys Vlasenko35ec8182016-10-01 19:56:52 +02009049 do {
Eric Andersenc470f442003-07-28 09:56:35 +00009050 int i;
9051
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009052 i = evaltree(n->nbinary.ch1, EV_TESTED);
Denys Vlasenko35ec8182016-10-01 19:56:52 +02009053 skip = skiploop();
9054 if (skip == SKIPFUNC)
9055 status = i;
9056 if (skip)
9057 continue;
Eric Andersenc470f442003-07-28 09:56:35 +00009058 if (n->type != NWHILE)
9059 i = !i;
9060 if (i != 0)
9061 break;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009062 status = evaltree(n->nbinary.ch2, flags);
Denys Vlasenko35ec8182016-10-01 19:56:52 +02009063 skip = skiploop();
9064 } while (!(skip & ~SKIPCONT));
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009065 loopnest--;
9066
9067 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00009068}
9069
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009070static int
Eric Andersenc470f442003-07-28 09:56:35 +00009071evalfor(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00009072{
9073 struct arglist arglist;
9074 union node *argp;
9075 struct strlist *sp;
9076 struct stackmark smark;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009077 int status = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00009078
9079 setstackmark(&smark);
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00009080 arglist.list = NULL;
Eric Andersencb57d552001-06-28 07:25:16 +00009081 arglist.lastp = &arglist.list;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009082 for (argp = n->nfor.args; argp; argp = argp->narg.next) {
Ron Yorston549deab2015-05-18 09:57:51 +02009083 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
Eric Andersencb57d552001-06-28 07:25:16 +00009084 }
9085 *arglist.lastp = NULL;
9086
Eric Andersencb57d552001-06-28 07:25:16 +00009087 loopnest++;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009088 flags &= EV_TESTED;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009089 for (sp = arglist.list; sp; sp = sp->next) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009090 setvar0(n->nfor.var, sp->text);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009091 status = evaltree(n->nfor.body, flags);
Denys Vlasenko35ec8182016-10-01 19:56:52 +02009092 if (skiploop() & ~SKIPCONT)
Eric Andersencb57d552001-06-28 07:25:16 +00009093 break;
Eric Andersencb57d552001-06-28 07:25:16 +00009094 }
9095 loopnest--;
Eric Andersencb57d552001-06-28 07:25:16 +00009096 popstackmark(&smark);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009097
9098 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00009099}
9100
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009101static int
Eric Andersenc470f442003-07-28 09:56:35 +00009102evalcase(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00009103{
9104 union node *cp;
9105 union node *patp;
9106 struct arglist arglist;
9107 struct stackmark smark;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009108 int status = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00009109
9110 setstackmark(&smark);
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00009111 arglist.list = NULL;
Eric Andersencb57d552001-06-28 07:25:16 +00009112 arglist.lastp = &arglist.list;
Eric Andersencb57d552001-06-28 07:25:16 +00009113 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009114 for (cp = n->ncase.cases; cp && evalskip == 0; cp = cp->nclist.next) {
9115 for (patp = cp->nclist.pattern; patp; patp = patp->narg.next) {
Eric Andersencb57d552001-06-28 07:25:16 +00009116 if (casematch(patp, arglist.list->text)) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009117 /* Ensure body is non-empty as otherwise
9118 * EV_EXIT may prevent us from setting the
9119 * exit status.
9120 */
9121 if (evalskip == 0 && cp->nclist.body) {
9122 status = evaltree(cp->nclist.body, flags);
Eric Andersencb57d552001-06-28 07:25:16 +00009123 }
9124 goto out;
9125 }
9126 }
9127 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009128 out:
Eric Andersencb57d552001-06-28 07:25:16 +00009129 popstackmark(&smark);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009130
9131 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00009132}
9133
Eric Andersenc470f442003-07-28 09:56:35 +00009134/*
9135 * Kick off a subshell to evaluate a tree.
9136 */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009137static int
Eric Andersenc470f442003-07-28 09:56:35 +00009138evalsubshell(union node *n, int flags)
9139{
9140 struct job *jp;
Denys Vlasenko098b7132017-01-11 19:59:03 +01009141 int backgnd = (n->type == NBACKGND); /* FORK_BG(1) if yes, else FORK_FG(0) */
Eric Andersenc470f442003-07-28 09:56:35 +00009142 int status;
9143
9144 expredir(n->nredir.redirect);
Denys Vlasenko238bf182010-05-18 15:49:07 +02009145 if (!backgnd && (flags & EV_EXIT) && !may_have_traps)
Eric Andersenc470f442003-07-28 09:56:35 +00009146 goto nofork;
Denis Vlasenkob012b102007-02-19 22:43:01 +00009147 INT_OFF;
Denys Vlasenko098b7132017-01-11 19:59:03 +01009148 if (backgnd == FORK_FG)
9149 get_tty_state();
Denis Vlasenko68404f12008-03-17 09:00:54 +00009150 jp = makejob(/*n,*/ 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009151 if (forkshell(jp, n, backgnd) == 0) {
Denys Vlasenko238bf182010-05-18 15:49:07 +02009152 /* child */
Denis Vlasenkob012b102007-02-19 22:43:01 +00009153 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +00009154 flags |= EV_EXIT;
9155 if (backgnd)
Denys Vlasenko238bf182010-05-18 15:49:07 +02009156 flags &= ~EV_TESTED;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00009157 nofork:
Eric Andersenc470f442003-07-28 09:56:35 +00009158 redirect(n->nredir.redirect, 0);
9159 evaltreenr(n->nredir.n, flags);
9160 /* never returns */
9161 }
Denys Vlasenko70392332016-10-27 02:31:55 +02009162 /* parent */
Eric Andersenc470f442003-07-28 09:56:35 +00009163 status = 0;
Denys Vlasenko098b7132017-01-11 19:59:03 +01009164 if (backgnd == FORK_FG)
Eric Andersenc470f442003-07-28 09:56:35 +00009165 status = waitforjob(jp);
Denis Vlasenkob012b102007-02-19 22:43:01 +00009166 INT_ON;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009167 return status;
Eric Andersenc470f442003-07-28 09:56:35 +00009168}
9169
Eric Andersenc470f442003-07-28 09:56:35 +00009170/*
9171 * Compute the names of the files in a redirection list.
9172 */
Denis Vlasenko99eb8502007-02-23 21:09:49 +00009173static void fixredir(union node *, const char *, int);
Eric Andersenc470f442003-07-28 09:56:35 +00009174static void
9175expredir(union node *n)
9176{
9177 union node *redir;
9178
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009179 for (redir = n; redir; redir = redir->nfile.next) {
Eric Andersenc470f442003-07-28 09:56:35 +00009180 struct arglist fn;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009181
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00009182 fn.list = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00009183 fn.lastp = &fn.list;
9184 switch (redir->type) {
9185 case NFROMTO:
9186 case NFROM:
9187 case NTO:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01009188#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00009189 case NTO2:
9190#endif
Eric Andersenc470f442003-07-28 09:56:35 +00009191 case NCLOBBER:
9192 case NAPPEND:
9193 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02009194 TRACE(("expredir expanded to '%s'\n", fn.list->text));
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01009195#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00009196 store_expfname:
9197#endif
Denys Vlasenko7c4b13e2013-01-17 13:02:27 +01009198#if 0
9199// By the design of stack allocator, the loop of this kind:
9200// while true; do while true; do break; done </dev/null; done
9201// will look like a memory leak: ash plans to free expfname's
9202// of "/dev/null" as soon as it finishes running the loop
9203// (in this case, never).
9204// This "fix" is wrong:
Jon Tollefson4ba6c5d2012-11-13 19:26:53 +01009205 if (redir->nfile.expfname)
9206 stunalloc(redir->nfile.expfname);
Denys Vlasenko7c4b13e2013-01-17 13:02:27 +01009207// It results in corrupted state of stacked allocations.
9208#endif
Eric Andersenc470f442003-07-28 09:56:35 +00009209 redir->nfile.expfname = fn.list->text;
9210 break;
9211 case NFROMFD:
Denis Vlasenko559691a2008-10-05 18:39:31 +00009212 case NTOFD: /* >& */
Eric Andersenc470f442003-07-28 09:56:35 +00009213 if (redir->ndup.vname) {
9214 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009215 if (fn.list == NULL)
Denis Vlasenkob012b102007-02-19 22:43:01 +00009216 ash_msg_and_raise_error("redir error");
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01009217#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00009218//FIXME: we used expandarg with different args!
9219 if (!isdigit_str9(fn.list->text)) {
9220 /* >&file, not >&fd */
9221 if (redir->nfile.fd != 1) /* 123>&file - BAD */
9222 ash_msg_and_raise_error("redir error");
9223 redir->type = NTO2;
9224 goto store_expfname;
9225 }
9226#endif
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009227 fixredir(redir, fn.list->text, 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009228 }
9229 break;
9230 }
9231 }
9232}
9233
Eric Andersencb57d552001-06-28 07:25:16 +00009234/*
Eric Andersencb57d552001-06-28 07:25:16 +00009235 * Evaluate a pipeline. All the processes in the pipeline are children
9236 * of the process creating the pipeline. (This differs from some versions
9237 * of the shell, which make the last process in a pipeline the parent
9238 * of all the rest.)
9239 */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009240static int
Eric Andersenc470f442003-07-28 09:56:35 +00009241evalpipe(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00009242{
9243 struct job *jp;
9244 struct nodelist *lp;
9245 int pipelen;
9246 int prevfd;
9247 int pip[2];
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009248 int status = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00009249
Eric Andersenc470f442003-07-28 09:56:35 +00009250 TRACE(("evalpipe(0x%lx) called\n", (long)n));
Eric Andersencb57d552001-06-28 07:25:16 +00009251 pipelen = 0;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009252 for (lp = n->npipe.cmdlist; lp; lp = lp->next)
Eric Andersencb57d552001-06-28 07:25:16 +00009253 pipelen++;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009254 flags |= EV_EXIT;
Denis Vlasenkob012b102007-02-19 22:43:01 +00009255 INT_OFF;
Denys Vlasenko098b7132017-01-11 19:59:03 +01009256 if (n->npipe.pipe_backgnd == 0)
9257 get_tty_state();
Denis Vlasenko68404f12008-03-17 09:00:54 +00009258 jp = makejob(/*n,*/ pipelen);
Eric Andersencb57d552001-06-28 07:25:16 +00009259 prevfd = -1;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009260 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009261 prehash(lp->n);
Eric Andersencb57d552001-06-28 07:25:16 +00009262 pip[1] = -1;
9263 if (lp->next) {
9264 if (pipe(pip) < 0) {
9265 close(prevfd);
Denys Vlasenko12ffefb2017-08-23 14:52:56 +02009266 ash_msg_and_raise_perror("can't create pipe");
Eric Andersencb57d552001-06-28 07:25:16 +00009267 }
9268 }
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00009269 if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) {
Denys Vlasenko70392332016-10-27 02:31:55 +02009270 /* child */
Denis Vlasenkob012b102007-02-19 22:43:01 +00009271 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +00009272 if (pip[1] >= 0) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009273 close(pip[0]);
Eric Andersencb57d552001-06-28 07:25:16 +00009274 }
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009275 if (prevfd > 0) {
9276 dup2(prevfd, 0);
9277 close(prevfd);
9278 }
9279 if (pip[1] > 1) {
9280 dup2(pip[1], 1);
9281 close(pip[1]);
9282 }
Eric Andersenc470f442003-07-28 09:56:35 +00009283 evaltreenr(lp->n, flags);
9284 /* never returns */
Eric Andersencb57d552001-06-28 07:25:16 +00009285 }
Denys Vlasenko70392332016-10-27 02:31:55 +02009286 /* parent */
Eric Andersencb57d552001-06-28 07:25:16 +00009287 if (prevfd >= 0)
9288 close(prevfd);
9289 prevfd = pip[0];
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +00009290 /* Don't want to trigger debugging */
9291 if (pip[1] != -1)
9292 close(pip[1]);
Eric Andersencb57d552001-06-28 07:25:16 +00009293 }
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00009294 if (n->npipe.pipe_backgnd == 0) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009295 status = waitforjob(jp);
9296 TRACE(("evalpipe: job done exit status %d\n", status));
Eric Andersencb57d552001-06-28 07:25:16 +00009297 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00009298 INT_ON;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009299
9300 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00009301}
9302
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009303/*
9304 * Controls whether the shell is interactive or not.
9305 */
9306static void
9307setinteractive(int on)
9308{
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009309 static smallint is_interactive;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009310
9311 if (++on == is_interactive)
9312 return;
9313 is_interactive = on;
9314 setsignal(SIGINT);
9315 setsignal(SIGQUIT);
9316 setsignal(SIGTERM);
9317#if !ENABLE_FEATURE_SH_EXTRA_QUIET
9318 if (is_interactive > 1) {
9319 /* Looks like they want an interactive shell */
Denis Vlasenkoca525b42007-06-13 12:27:17 +00009320 static smallint did_banner;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009321
Denis Vlasenkoca525b42007-06-13 12:27:17 +00009322 if (!did_banner) {
Denys Vlasenkoc34c0332009-09-29 12:25:30 +02009323 /* note: ash and hush share this string */
9324 out1fmt("\n\n%s %s\n"
Denys Vlasenko2ec34962014-09-08 16:52:39 +02009325 IF_ASH_HELP("Enter 'help' for a list of built-in commands.\n")
9326 "\n",
Denys Vlasenkoc34c0332009-09-29 12:25:30 +02009327 bb_banner,
9328 "built-in shell (ash)"
9329 );
Denis Vlasenkoca525b42007-06-13 12:27:17 +00009330 did_banner = 1;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009331 }
9332 }
9333#endif
9334}
9335
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009336static void
9337optschanged(void)
9338{
9339#if DEBUG
9340 opentrace();
9341#endif
9342 setinteractive(iflag);
9343 setjobctl(mflag);
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009344#if ENABLE_FEATURE_EDITING_VI
9345 if (viflag)
9346 line_input_state->flags |= VI_MODE;
9347 else
9348 line_input_state->flags &= ~VI_MODE;
9349#else
9350 viflag = 0; /* forcibly keep the option off */
9351#endif
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009352}
9353
Denys Vlasenkob8ab27b2017-07-26 19:22:34 +02009354struct localvar_list {
9355 struct localvar_list *next;
9356 struct localvar *lv;
9357};
9358
9359static struct localvar_list *localvar_stack;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009360
9361/*
9362 * Called after a function returns.
9363 * Interrupts must be off.
9364 */
9365static void
Denys Vlasenko981a0562017-07-26 19:53:11 +02009366poplocalvars(int keep)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009367{
Denys Vlasenkob8ab27b2017-07-26 19:22:34 +02009368 struct localvar_list *ll;
9369 struct localvar *lvp, *next;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009370 struct var *vp;
9371
Denys Vlasenkob8ab27b2017-07-26 19:22:34 +02009372 INT_OFF;
9373 ll = localvar_stack;
9374 localvar_stack = ll->next;
9375
9376 next = ll->lv;
9377 free(ll);
9378
9379 while ((lvp = next) != NULL) {
9380 next = lvp->next;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009381 vp = lvp->vp;
Denys Vlasenkob563f622010-09-25 17:15:13 +02009382 TRACE(("poplocalvar %s\n", vp ? vp->var_text : "-"));
Denys Vlasenko981a0562017-07-26 19:53:11 +02009383 if (keep) {
9384 int bits = VSTRFIXED;
9385
9386 if (lvp->flags != VUNSET) {
9387 if (vp->var_text == lvp->text)
9388 bits |= VTEXTFIXED;
9389 else if (!(lvp->flags & (VTEXTFIXED|VSTACK)))
9390 free((char*)lvp->text);
9391 }
9392
9393 vp->flags &= ~bits;
9394 vp->flags |= (lvp->flags & bits);
9395
9396 if ((vp->flags &
9397 (VEXPORT|VREADONLY|VSTRFIXED|VUNSET)) == VUNSET)
9398 unsetvar(vp->var_text);
9399 } else if (vp == NULL) { /* $- saved */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009400 memcpy(optlist, lvp->text, sizeof(optlist));
9401 free((char*)lvp->text);
9402 optschanged();
Denys Vlasenkod5b500c2017-07-26 19:25:40 +02009403 } else if (lvp->flags == VUNSET) {
9404 vp->flags &= ~(VSTRFIXED|VREADONLY);
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009405 unsetvar(vp->var_text);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009406 } else {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009407 if (vp->var_func)
9408 vp->var_func(var_end(lvp->text));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009409 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009410 free((char*)vp->var_text);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009411 vp->flags = lvp->flags;
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009412 vp->var_text = lvp->text;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009413 }
9414 free(lvp);
9415 }
Denys Vlasenkob8ab27b2017-07-26 19:22:34 +02009416 INT_ON;
9417}
9418
9419/*
9420 * Create a new localvar environment.
9421 */
Denys Vlasenko484fc202017-07-26 19:55:31 +02009422static struct localvar_list *
Denys Vlasenkob8ab27b2017-07-26 19:22:34 +02009423pushlocalvars(void)
9424{
9425 struct localvar_list *ll;
9426
9427 INT_OFF;
9428 ll = ckzalloc(sizeof(*ll));
9429 /*ll->lv = NULL; - zalloc did it */
9430 ll->next = localvar_stack;
9431 localvar_stack = ll;
9432 INT_ON;
Denys Vlasenko484fc202017-07-26 19:55:31 +02009433
9434 return ll->next;
9435}
9436
9437static void
9438unwindlocalvars(struct localvar_list *stop)
9439{
9440 while (localvar_stack != stop)
9441 poplocalvars(0);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009442}
9443
9444static int
9445evalfun(struct funcnode *func, int argc, char **argv, int flags)
9446{
9447 volatile struct shparam saveparam;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009448 struct jmploc *volatile savehandler;
9449 struct jmploc jmploc;
9450 int e;
9451
9452 saveparam = shellparam;
Denys Vlasenkoa2d121c2016-09-30 11:30:11 +02009453 savehandler = exception_handler;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009454 e = setjmp(jmploc.loc);
9455 if (e) {
9456 goto funcdone;
9457 }
9458 INT_OFF;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009459 exception_handler = &jmploc;
Denis Vlasenko01631112007-12-16 17:20:38 +00009460 shellparam.malloced = 0;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009461 func->count++;
9462 funcnest++;
9463 INT_ON;
9464 shellparam.nparam = argc - 1;
9465 shellparam.p = argv + 1;
9466#if ENABLE_ASH_GETOPTS
9467 shellparam.optind = 1;
9468 shellparam.optoff = -1;
9469#endif
Denys Vlasenkob8ab27b2017-07-26 19:22:34 +02009470 pushlocalvars();
Denys Vlasenko7aec8682016-10-25 20:26:02 +02009471 evaltree(func->n.narg.next, flags & EV_TESTED);
Denys Vlasenko981a0562017-07-26 19:53:11 +02009472 poplocalvars(0);
Denis Vlasenko01631112007-12-16 17:20:38 +00009473 funcdone:
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009474 INT_OFF;
9475 funcnest--;
9476 freefunc(func);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009477 freeparam(&shellparam);
9478 shellparam = saveparam;
9479 exception_handler = savehandler;
9480 INT_ON;
9481 evalskip &= ~SKIPFUNC;
9482 return e;
9483}
9484
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009485/*
9486 * Make a variable a local variable. When a variable is made local, it's
9487 * value and flags are saved in a localvar structure. The saved values
9488 * will be restored when the shell function returns. We handle the name
Denys Vlasenkoe0a4e102015-05-13 02:20:14 +02009489 * "-" as a special case: it makes changes to "set +-options" local
9490 * (options will be restored on return from the function).
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009491 */
9492static void
9493mklocal(char *name)
9494{
9495 struct localvar *lvp;
9496 struct var **vpp;
9497 struct var *vp;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009498 char *eq = strchr(name, '=');
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009499
9500 INT_OFF;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009501 /* Cater for duplicate "local". Examples:
9502 * x=0; f() { local x=1; echo $x; local x; echo $x; }; f; echo $x
9503 * x=0; f() { local x=1; echo $x; local x=2; echo $x; }; f; echo $x
9504 */
Denys Vlasenkob8ab27b2017-07-26 19:22:34 +02009505 lvp = localvar_stack->lv;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009506 while (lvp) {
Eugene Rudoy1285aa62015-04-26 23:32:00 +02009507 if (lvp->vp && varcmp(lvp->vp->var_text, name) == 0) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009508 if (eq)
9509 setvareq(name, 0);
9510 /* else:
9511 * it's a duplicate "local VAR" declaration, do nothing
9512 */
Denys Vlasenko06b11492016-11-04 16:43:18 +01009513 goto ret;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009514 }
9515 lvp = lvp->next;
9516 }
9517
9518 lvp = ckzalloc(sizeof(*lvp));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009519 if (LONE_DASH(name)) {
9520 char *p;
9521 p = ckmalloc(sizeof(optlist));
9522 lvp->text = memcpy(p, optlist, sizeof(optlist));
9523 vp = NULL;
9524 } else {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009525 vpp = hashvar(name);
9526 vp = *findvar(vpp, name);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009527 if (vp == NULL) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009528 /* variable did not exist yet */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009529 if (eq)
Denys Vlasenkod04fc712017-07-26 20:06:48 +02009530 vp = setvareq(name, VSTRFIXED);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009531 else
Denys Vlasenkod04fc712017-07-26 20:06:48 +02009532 vp = setvar(name, NULL, VSTRFIXED);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009533 lvp->flags = VUNSET;
9534 } else {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009535 lvp->text = vp->var_text;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009536 lvp->flags = vp->flags;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009537 /* make sure neither "struct var" nor string gets freed
9538 * during (un)setting:
9539 */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009540 vp->flags |= VSTRFIXED|VTEXTFIXED;
9541 if (eq)
9542 setvareq(name, 0);
Denys Vlasenko109ee5d2014-03-16 18:41:11 +01009543 else
9544 /* "local VAR" unsets VAR: */
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009545 setvar0(name, NULL);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009546 }
9547 }
9548 lvp->vp = vp;
Denys Vlasenkob8ab27b2017-07-26 19:22:34 +02009549 lvp->next = localvar_stack->lv;
9550 localvar_stack->lv = lvp;
Denys Vlasenko06b11492016-11-04 16:43:18 +01009551 ret:
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009552 INT_ON;
9553}
9554
9555/*
9556 * The "local" command.
9557 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009558static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009559localcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009560{
9561 char *name;
9562
Denys Vlasenkob8ab27b2017-07-26 19:22:34 +02009563 if (!localvar_stack)
Ron Yorstonef2386b2015-10-29 16:19:14 +00009564 ash_msg_and_raise_error("not in a function");
9565
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009566 argv = argptr;
9567 while ((name = *argv++) != NULL) {
9568 mklocal(name);
9569 }
9570 return 0;
9571}
9572
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009573static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009574falsecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009575{
9576 return 1;
9577}
9578
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009579static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009580truecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009581{
9582 return 0;
9583}
9584
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009585static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009586execcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009587{
Denys Vlasenko6c149f42017-04-12 21:31:32 +02009588 optionarg = NULL;
9589 while (nextopt("a:") != '\0')
9590 /* nextopt() sets optionarg to "-a ARGV0" */;
9591
9592 argv = argptr;
9593 if (argv[0]) {
9594 char *prog;
9595
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009596 iflag = 0; /* exit on error */
9597 mflag = 0;
9598 optschanged();
Denys Vlasenkoe5814a52016-07-16 18:33:55 +02009599 /* We should set up signals for "exec CMD"
9600 * the same way as for "CMD" without "exec".
9601 * But optschanged->setinteractive->setsignal
9602 * still thought we are a root shell. Therefore, for example,
9603 * SIGQUIT is still set to IGN. Fix it:
9604 */
9605 shlvl++;
9606 setsignal(SIGQUIT);
9607 /*setsignal(SIGTERM); - unnecessary because of iflag=0 */
9608 /*setsignal(SIGTSTP); - unnecessary because of mflag=0 */
9609 /*setsignal(SIGTTOU); - unnecessary because of mflag=0 */
9610
Denys Vlasenko6c149f42017-04-12 21:31:32 +02009611 prog = argv[0];
9612 if (optionarg)
9613 argv[0] = optionarg;
9614 shellexec(prog, argv, pathval(), 0);
Denys Vlasenkoe5814a52016-07-16 18:33:55 +02009615 /* NOTREACHED */
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009616 }
9617 return 0;
9618}
9619
9620/*
9621 * The return command.
9622 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009623static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009624returncmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009625{
9626 /*
9627 * If called outside a function, do what ksh does;
9628 * skip the rest of the file.
9629 */
Denys Vlasenko6a0710e2016-09-30 14:18:34 +02009630 evalskip = SKIPFUNC;
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009631 return argv[1] ? number(argv[1]) : exitstatus;
9632}
9633
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009634/* Forward declarations for builtintab[] */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009635static int breakcmd(int, char **) FAST_FUNC;
9636static int dotcmd(int, char **) FAST_FUNC;
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009637static int evalcmd(int, char **, int) FAST_FUNC;
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009638static int exitcmd(int, char **) FAST_FUNC;
9639static int exportcmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009640#if ENABLE_ASH_GETOPTS
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009641static int getoptscmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009642#endif
Denys Vlasenko2ec34962014-09-08 16:52:39 +02009643#if ENABLE_ASH_HELP
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009644static int helpcmd(int, char **) FAST_FUNC;
Denis Vlasenko52764022007-02-24 13:42:56 +00009645#endif
Flemming Madsend96ffda2013-04-07 18:47:24 +02009646#if MAX_HISTORY
9647static int historycmd(int, char **) FAST_FUNC;
9648#endif
Denys Vlasenko0b883582016-12-23 16:49:07 +01009649#if ENABLE_FEATURE_SH_MATH
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009650static int letcmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009651#endif
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009652static int readcmd(int, char **) FAST_FUNC;
9653static int setcmd(int, char **) FAST_FUNC;
9654static int shiftcmd(int, char **) FAST_FUNC;
9655static int timescmd(int, char **) FAST_FUNC;
9656static int trapcmd(int, char **) FAST_FUNC;
9657static int umaskcmd(int, char **) FAST_FUNC;
9658static int unsetcmd(int, char **) FAST_FUNC;
9659static int ulimitcmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009660
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009661#define BUILTIN_NOSPEC "0"
9662#define BUILTIN_SPECIAL "1"
9663#define BUILTIN_REGULAR "2"
9664#define BUILTIN_SPEC_REG "3"
9665#define BUILTIN_ASSIGN "4"
9666#define BUILTIN_SPEC_ASSG "5"
9667#define BUILTIN_REG_ASSG "6"
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009668#define BUILTIN_SPEC_REG_ASSG "7"
9669
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009670/* Stubs for calling non-FAST_FUNC's */
Denys Vlasenko265062d2017-01-10 15:13:30 +01009671#if ENABLE_ASH_ECHO
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009672static int FAST_FUNC echocmd(int argc, char **argv) { return echo_main(argc, argv); }
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009673#endif
Denys Vlasenko265062d2017-01-10 15:13:30 +01009674#if ENABLE_ASH_PRINTF
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009675static int FAST_FUNC printfcmd(int argc, char **argv) { return printf_main(argc, argv); }
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009676#endif
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01009677#if ENABLE_ASH_TEST || BASH_TEST2
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009678static int FAST_FUNC testcmd(int argc, char **argv) { return test_main(argc, argv); }
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009679#endif
Denis Vlasenko468aea22008-04-01 14:47:57 +00009680
Denis Vlasenkof7d56652008-03-25 05:51:41 +00009681/* Keep these in proper order since it is searched via bsearch() */
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009682static const struct builtincmd builtintab[] = {
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009683 { BUILTIN_SPEC_REG "." , dotcmd },
9684 { BUILTIN_SPEC_REG ":" , truecmd },
Denys Vlasenko265062d2017-01-10 15:13:30 +01009685#if ENABLE_ASH_TEST
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009686 { BUILTIN_REGULAR "[" , testcmd },
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01009687#endif
9688#if BASH_TEST2
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009689 { BUILTIN_REGULAR "[[" , testcmd },
Denis Vlasenko80591b02008-03-25 07:49:43 +00009690#endif
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009691#if ENABLE_ASH_ALIAS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009692 { BUILTIN_REG_ASSG "alias" , aliascmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009693#endif
9694#if JOBS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009695 { BUILTIN_REGULAR "bg" , fg_bgcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009696#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009697 { BUILTIN_SPEC_REG "break" , breakcmd },
9698 { BUILTIN_REGULAR "cd" , cdcmd },
9699 { BUILTIN_NOSPEC "chdir" , cdcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009700#if ENABLE_ASH_CMDCMD
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009701 { BUILTIN_REGULAR "command" , commandcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009702#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009703 { BUILTIN_SPEC_REG "continue", breakcmd },
Denys Vlasenko265062d2017-01-10 15:13:30 +01009704#if ENABLE_ASH_ECHO
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009705 { BUILTIN_REGULAR "echo" , echocmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009706#endif
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009707 { BUILTIN_SPEC_REG "eval" , NULL }, /*evalcmd() has a differing prototype*/
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009708 { BUILTIN_SPEC_REG "exec" , execcmd },
9709 { BUILTIN_SPEC_REG "exit" , exitcmd },
9710 { BUILTIN_SPEC_REG_ASSG "export" , exportcmd },
9711 { BUILTIN_REGULAR "false" , falsecmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009712#if JOBS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009713 { BUILTIN_REGULAR "fg" , fg_bgcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009714#endif
9715#if ENABLE_ASH_GETOPTS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009716 { BUILTIN_REGULAR "getopts" , getoptscmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009717#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009718 { BUILTIN_NOSPEC "hash" , hashcmd },
Denys Vlasenko2ec34962014-09-08 16:52:39 +02009719#if ENABLE_ASH_HELP
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009720 { BUILTIN_NOSPEC "help" , helpcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009721#endif
Flemming Madsend96ffda2013-04-07 18:47:24 +02009722#if MAX_HISTORY
9723 { BUILTIN_NOSPEC "history" , historycmd },
9724#endif
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009725#if JOBS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009726 { BUILTIN_REGULAR "jobs" , jobscmd },
9727 { BUILTIN_REGULAR "kill" , killcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009728#endif
Denys Vlasenko0b883582016-12-23 16:49:07 +01009729#if ENABLE_FEATURE_SH_MATH
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009730 { BUILTIN_NOSPEC "let" , letcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009731#endif
Denys Vlasenko85241c72017-07-26 20:00:08 +02009732 { BUILTIN_SPEC_REG_ASSG "local" , localcmd },
Denys Vlasenko265062d2017-01-10 15:13:30 +01009733#if ENABLE_ASH_PRINTF
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009734 { BUILTIN_REGULAR "printf" , printfcmd },
Denis Vlasenkocd2663f2008-06-01 22:36:39 +00009735#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009736 { BUILTIN_NOSPEC "pwd" , pwdcmd },
9737 { BUILTIN_REGULAR "read" , readcmd },
9738 { BUILTIN_SPEC_REG_ASSG "readonly", exportcmd },
9739 { BUILTIN_SPEC_REG "return" , returncmd },
9740 { BUILTIN_SPEC_REG "set" , setcmd },
9741 { BUILTIN_SPEC_REG "shift" , shiftcmd },
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01009742#if BASH_SOURCE
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009743 { BUILTIN_SPEC_REG "source" , dotcmd },
Denys Vlasenko82731b42010-05-17 17:49:52 +02009744#endif
Denys Vlasenko265062d2017-01-10 15:13:30 +01009745#if ENABLE_ASH_TEST
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009746 { BUILTIN_REGULAR "test" , testcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009747#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009748 { BUILTIN_SPEC_REG "times" , timescmd },
9749 { BUILTIN_SPEC_REG "trap" , trapcmd },
9750 { BUILTIN_REGULAR "true" , truecmd },
9751 { BUILTIN_NOSPEC "type" , typecmd },
9752 { BUILTIN_NOSPEC "ulimit" , ulimitcmd },
9753 { BUILTIN_REGULAR "umask" , umaskcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009754#if ENABLE_ASH_ALIAS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009755 { BUILTIN_REGULAR "unalias" , unaliascmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009756#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009757 { BUILTIN_SPEC_REG "unset" , unsetcmd },
9758 { BUILTIN_REGULAR "wait" , waitcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009759};
9760
Denis Vlasenko80591b02008-03-25 07:49:43 +00009761/* Should match the above table! */
9762#define COMMANDCMD (builtintab + \
Denys Vlasenko928e2a72016-09-29 00:30:31 +02009763 /* . : */ 2 + \
Denys Vlasenko265062d2017-01-10 15:13:30 +01009764 /* [ */ 1 * ENABLE_ASH_TEST + \
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01009765 /* [[ */ 1 * BASH_TEST2 + \
Denys Vlasenko928e2a72016-09-29 00:30:31 +02009766 /* alias */ 1 * ENABLE_ASH_ALIAS + \
9767 /* bg */ 1 * ENABLE_ASH_JOB_CONTROL + \
9768 /* break cd cddir */ 3)
9769#define EVALCMD (COMMANDCMD + \
9770 /* command */ 1 * ENABLE_ASH_CMDCMD + \
9771 /* continue */ 1 + \
Denys Vlasenko265062d2017-01-10 15:13:30 +01009772 /* echo */ 1 * ENABLE_ASH_ECHO + \
Denys Vlasenko928e2a72016-09-29 00:30:31 +02009773 0)
9774#define EXECCMD (EVALCMD + \
9775 /* eval */ 1)
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009776
9777/*
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009778 * Search the table of builtin commands.
9779 */
Denys Vlasenko888527c2016-10-02 16:54:17 +02009780static int
9781pstrcmp1(const void *a, const void *b)
9782{
9783 return strcmp((char*)a, *(char**)b + 1);
9784}
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009785static struct builtincmd *
9786find_builtin(const char *name)
9787{
9788 struct builtincmd *bp;
9789
9790 bp = bsearch(
Denis Vlasenko80b8b392007-06-25 10:55:35 +00009791 name, builtintab, ARRAY_SIZE(builtintab), sizeof(builtintab[0]),
Denys Vlasenko888527c2016-10-02 16:54:17 +02009792 pstrcmp1
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009793 );
9794 return bp;
9795}
9796
9797/*
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009798 * Execute a simple command.
9799 */
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009800static int
9801isassignment(const char *p)
Paul Foxc3850c82005-07-20 18:23:39 +00009802{
9803 const char *q = endofname(p);
9804 if (p == q)
9805 return 0;
9806 return *q == '=';
9807}
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009808static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009809bltincmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009810{
9811 /* Preserve exitstatus of a previous possible redirection
9812 * as POSIX mandates */
9813 return back_exitstatus;
9814}
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009815static int
Eric Andersenc470f442003-07-28 09:56:35 +00009816evalcommand(union node *cmd, int flags)
9817{
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00009818 static const struct builtincmd null_bltin = {
9819 "\0\0", bltincmd /* why three NULs? */
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009820 };
Denys Vlasenko484fc202017-07-26 19:55:31 +02009821 struct localvar_list *localvar_stop;
Denys Vlasenko1c79aeb2017-07-29 22:51:52 +02009822 struct redirtab *redir_stop;
Eric Andersenc470f442003-07-28 09:56:35 +00009823 struct stackmark smark;
9824 union node *argp;
9825 struct arglist arglist;
9826 struct arglist varlist;
9827 char **argv;
9828 int argc;
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009829 const struct strlist *sp;
Eric Andersenc470f442003-07-28 09:56:35 +00009830 struct cmdentry cmdentry;
9831 struct job *jp;
9832 char *lastarg;
9833 const char *path;
9834 int spclbltin;
Eric Andersenc470f442003-07-28 09:56:35 +00009835 int status;
9836 char **nargv;
Denis Vlasenko34c73c42008-08-16 11:48:02 +00009837 smallint cmd_is_exec;
Eric Andersenc470f442003-07-28 09:56:35 +00009838
9839 /* First expand the arguments. */
9840 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
9841 setstackmark(&smark);
Denys Vlasenko484fc202017-07-26 19:55:31 +02009842 localvar_stop = pushlocalvars();
Eric Andersenc470f442003-07-28 09:56:35 +00009843 back_exitstatus = 0;
9844
9845 cmdentry.cmdtype = CMDBUILTIN;
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00009846 cmdentry.u.cmd = &null_bltin;
Eric Andersenc470f442003-07-28 09:56:35 +00009847 varlist.lastp = &varlist.list;
9848 *varlist.lastp = NULL;
9849 arglist.lastp = &arglist.list;
9850 *arglist.lastp = NULL;
9851
9852 argc = 0;
Denis Vlasenkob012b102007-02-19 22:43:01 +00009853 if (cmd->ncmd.args) {
Denys Vlasenkod07a15b2017-07-30 16:51:05 +02009854 struct builtincmd *bcmd;
9855 smallint pseudovarflag;
9856
Paul Foxc3850c82005-07-20 18:23:39 +00009857 bcmd = find_builtin(cmd->ncmd.args->narg.text);
9858 pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd);
Paul Foxc3850c82005-07-20 18:23:39 +00009859
Denys Vlasenkod07a15b2017-07-30 16:51:05 +02009860 for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) {
9861 struct strlist **spp;
Eric Andersenc470f442003-07-28 09:56:35 +00009862
Denys Vlasenkod07a15b2017-07-30 16:51:05 +02009863 spp = arglist.lastp;
9864 if (pseudovarflag && isassignment(argp->narg.text))
9865 expandarg(argp, &arglist, EXP_VARTILDE);
9866 else
9867 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
Paul Foxc3850c82005-07-20 18:23:39 +00009868
Denys Vlasenkod07a15b2017-07-30 16:51:05 +02009869 for (sp = *spp; sp; sp = sp->next)
9870 argc++;
9871 }
Eric Andersenc470f442003-07-28 09:56:35 +00009872 }
9873
Denys Vlasenko65a8b852016-10-26 22:29:11 +02009874 /* Reserve one extra spot at the front for shellexec. */
9875 nargv = stalloc(sizeof(char *) * (argc + 2));
9876 argv = ++nargv;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009877 for (sp = arglist.list; sp; sp = sp->next) {
Eric Andersenc470f442003-07-28 09:56:35 +00009878 TRACE(("evalcommand arg: %s\n", sp->text));
9879 *nargv++ = sp->text;
9880 }
9881 *nargv = NULL;
9882
9883 lastarg = NULL;
9884 if (iflag && funcnest == 0 && argc > 0)
9885 lastarg = nargv[-1];
9886
9887 expredir(cmd->ncmd.redirect);
Denys Vlasenko1c79aeb2017-07-29 22:51:52 +02009888 redir_stop = pushredir(cmd->ncmd.redirect);
Denys Vlasenkod07a15b2017-07-30 16:51:05 +02009889 preverrout_fd = 2;
Denys Vlasenkof8cdc7a2017-08-04 15:24:49 +02009890 if (BASH_XTRACEFD && xflag) {
9891 /* NB: bash closes fd == $BASH_XTRACEFD when it is changed.
9892 * we do not emulate this. We only use its value.
9893 */
9894 const char *xtracefd = lookupvar("BASH_XTRACEFD");
9895 if (xtracefd && is_number(xtracefd))
9896 preverrout_fd = atoi(xtracefd);
9897
9898 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009899 status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH | REDIR_SAVEFD2);
Eric Andersenc470f442003-07-28 09:56:35 +00009900
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009901 path = vpath.var_text;
Eric Andersenc470f442003-07-28 09:56:35 +00009902 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
9903 struct strlist **spp;
9904 char *p;
9905
9906 spp = varlist.lastp;
9907 expandarg(argp, &varlist, EXP_VARTILDE);
9908
Denys Vlasenko981a0562017-07-26 19:53:11 +02009909 mklocal((*spp)->text);
9910
Eric Andersenc470f442003-07-28 09:56:35 +00009911 /*
9912 * Modify the command lookup path, if a PATH= assignment
9913 * is present
9914 */
9915 p = (*spp)->text;
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009916 if (varcmp(p, path) == 0)
Eric Andersenc470f442003-07-28 09:56:35 +00009917 path = p;
9918 }
9919
9920 /* Print the command if xflag is set. */
9921 if (xflag) {
Denys Vlasenko42ba7572017-07-21 13:20:14 +02009922 const char *pfx = "";
Eric Andersenc470f442003-07-28 09:56:35 +00009923
Denys Vlasenko46999802017-07-29 21:12:29 +02009924 fdprintf(preverrout_fd, "%s", expandstr(ps4val(), DQSYNTAX));
Denys Vlasenko42ba7572017-07-21 13:20:14 +02009925
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009926 sp = varlist.list;
Denys Vlasenko42ba7572017-07-21 13:20:14 +02009927 while (sp) {
9928 char *varval = sp->text;
9929 char *eq = strchrnul(varval, '=');
9930 if (*eq)
9931 eq++;
9932 fdprintf(preverrout_fd, "%s%.*s%s",
9933 pfx,
9934 (int)(eq - varval), varval,
9935 maybe_single_quote(eq)
9936 );
9937 sp = sp->next;
9938 pfx = " ";
9939 }
9940
9941 sp = arglist.list;
9942 while (sp) {
9943 fdprintf(preverrout_fd, "%s%s",
9944 pfx,
9945 /* always quote if matches reserved word: */
9946 findkwd(sp->text)
9947 ? single_quote(sp->text)
9948 : maybe_single_quote(sp->text)
9949 );
9950 sp = sp->next;
9951 pfx = " ";
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009952 }
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00009953 safe_write(preverrout_fd, "\n", 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009954 }
9955
9956 cmd_is_exec = 0;
9957 spclbltin = -1;
9958
9959 /* Now locate the command. */
9960 if (argc) {
Eric Andersenc470f442003-07-28 09:56:35 +00009961 int cmd_flag = DO_ERR;
Denys Vlasenko0b4980c2012-09-25 12:49:29 +02009962#if ENABLE_ASH_CMDCMD
9963 const char *oldpath = path + 5;
9964#endif
Eric Andersenc470f442003-07-28 09:56:35 +00009965 path += 5;
Eric Andersenc470f442003-07-28 09:56:35 +00009966 for (;;) {
9967 find_command(argv[0], &cmdentry, cmd_flag, path);
9968 if (cmdentry.cmdtype == CMDUNKNOWN) {
Denys Vlasenko8131eea2009-11-02 14:19:51 +01009969 flush_stdout_stderr();
Denis Vlasenko6514c5e2008-07-24 13:41:37 +00009970 status = 127;
Eric Andersenc470f442003-07-28 09:56:35 +00009971 goto bail;
9972 }
9973
9974 /* implement bltin and command here */
9975 if (cmdentry.cmdtype != CMDBUILTIN)
9976 break;
9977 if (spclbltin < 0)
9978 spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd);
9979 if (cmdentry.u.cmd == EXECCMD)
Denis Vlasenko34c73c42008-08-16 11:48:02 +00009980 cmd_is_exec = 1;
Denis Vlasenko131ae172007-02-18 13:00:19 +00009981#if ENABLE_ASH_CMDCMD
Eric Andersenc470f442003-07-28 09:56:35 +00009982 if (cmdentry.u.cmd == COMMANDCMD) {
Eric Andersenc470f442003-07-28 09:56:35 +00009983 path = oldpath;
9984 nargv = parse_command_args(argv, &path);
9985 if (!nargv)
9986 break;
Denys Vlasenkocac4d002016-10-01 03:02:25 +02009987 /* It's "command [-p] PROG ARGS" (that is, no -Vv).
9988 * nargv => "PROG". path is updated if -p.
9989 */
Eric Andersenc470f442003-07-28 09:56:35 +00009990 argc -= nargv - argv;
9991 argv = nargv;
9992 cmd_flag |= DO_NOFUNC;
9993 } else
9994#endif
9995 break;
9996 }
9997 }
9998
9999 if (status) {
Ron Yorstonea7d2f62017-01-03 11:18:23 +010010000 bail:
10001 exitstatus = status;
10002
Eric Andersenc470f442003-07-28 09:56:35 +000010003 /* We have a redirection error. */
10004 if (spclbltin > 0)
Denis Vlasenkob012b102007-02-19 22:43:01 +000010005 raise_exception(EXERROR);
Ron Yorstonea7d2f62017-01-03 11:18:23 +010010006
Eric Andersenc470f442003-07-28 09:56:35 +000010007 goto out;
10008 }
10009
10010 /* Execute the command. */
10011 switch (cmdentry.cmdtype) {
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +020010012 default: {
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +000010013
Denys Vlasenko82d1c1f2017-12-31 17:30:02 +010010014#if ENABLE_FEATURE_SH_NOFORK && NUM_APPLETS > 1
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +020010015/* (1) BUG: if variables are set, we need to fork, or save/restore them
10016 * around run_nofork_applet() call.
10017 * (2) Should this check also be done in forkshell()?
10018 * (perhaps it should, so that "VAR=VAL nofork" at least avoids exec...)
10019 */
Denis Vlasenko7465dbc2008-04-13 02:25:53 +000010020 /* find_command() encodes applet_no as (-2 - applet_no) */
10021 int applet_no = (- cmdentry.u.index - 2);
Denis Vlasenko9bc80d72008-04-12 20:07:53 +000010022 if (applet_no >= 0 && APPLET_IS_NOFORK(applet_no)) {
Denys Vlasenkoa5060b82017-11-03 14:16:25 +010010023 char **sv_environ;
10024
10025 INT_OFF;
10026 sv_environ = environ;
10027 environ = listvars(VEXPORT, VUNSET, varlist.list, /*end:*/ NULL);
Denys Vlasenkod329e342017-08-04 14:50:03 +020010028 /*
10029 * Run <applet>_main().
10030 * Signals (^C) can't interrupt here.
10031 * Otherwise we can mangle stdio or malloc internal state.
10032 * This makes applets which can run for a long time
10033 * and/or wait for user input ineligible for NOFORK:
10034 * for example, "yes" or "rm" (rm -i waits for input).
10035 */
Ron Yorston5ccb0e92016-10-20 12:24:02 +010010036 status = run_nofork_applet(applet_no, argv);
Denys Vlasenkoa5060b82017-11-03 14:16:25 +010010037 environ = sv_environ;
Denys Vlasenkod329e342017-08-04 14:50:03 +020010038 /*
10039 * Try enabling NOFORK for "yes" applet.
10040 * ^C _will_ stop it (write returns EINTR),
10041 * but this causes stdout FILE to be stuck
10042 * and needing clearerr(). What if other applets
10043 * also can get EINTRs? Do we need to switch
10044 * our signals to SA_RESTART?
10045 */
10046 /*clearerr(stdout);*/
10047 INT_ON;
Denis Vlasenko9bc80d72008-04-12 20:07:53 +000010048 break;
10049 }
Denis Vlasenko9bc80d72008-04-12 20:07:53 +000010050#endif
Denys Vlasenkocfd392b2017-08-03 19:56:29 +020010051 /* Can we avoid forking? For example, very last command
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +020010052 * in a script or a subshell does not need forking,
10053 * we can just exec it.
10054 */
Denys Vlasenko238bf182010-05-18 15:49:07 +020010055 if (!(flags & EV_EXIT) || may_have_traps) {
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +020010056 /* No, forking off a child is necessary */
Denis Vlasenkob012b102007-02-19 22:43:01 +000010057 INT_OFF;
Denys Vlasenko098b7132017-01-11 19:59:03 +010010058 get_tty_state();
Denis Vlasenko68404f12008-03-17 09:00:54 +000010059 jp = makejob(/*cmd,*/ 1);
Eric Andersenc470f442003-07-28 09:56:35 +000010060 if (forkshell(jp, cmd, FORK_FG) != 0) {
Denys Vlasenko238bf182010-05-18 15:49:07 +020010061 /* parent */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020010062 status = waitforjob(jp);
Denis Vlasenkob012b102007-02-19 22:43:01 +000010063 INT_ON;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020010064 TRACE(("forked child exited with %d\n", status));
Eric Andersenc470f442003-07-28 09:56:35 +000010065 break;
10066 }
Denys Vlasenko238bf182010-05-18 15:49:07 +020010067 /* child */
Denis Vlasenkob012b102007-02-19 22:43:01 +000010068 FORCE_INT_ON;
Denys Vlasenkoc7f95d22010-05-18 15:52:23 +020010069 /* fall through to exec'ing external program */
Eric Andersenc470f442003-07-28 09:56:35 +000010070 }
10071 listsetvar(varlist.list, VEXPORT|VSTACK);
Denys Vlasenkoe139ae32017-04-12 21:02:33 +020010072 shellexec(argv[0], argv, path, cmdentry.u.index);
Eric Andersenc470f442003-07-28 09:56:35 +000010073 /* NOTREACHED */
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +020010074 } /* default */
Eric Andersenc470f442003-07-28 09:56:35 +000010075 case CMDBUILTIN:
Denys Vlasenko85241c72017-07-26 20:00:08 +020010076 if (spclbltin > 0 || argc == 0) {
10077 poplocalvars(1);
10078 if (cmd_is_exec && argc > 1)
10079 listsetvar(varlist.list, VEXPORT);
10080 }
Denys Vlasenko981a0562017-07-26 19:53:11 +020010081
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +000010082 /* Tight loop with builtins only:
10083 * "while kill -0 $child; do true; done"
10084 * will never exit even if $child died, unless we do this
10085 * to reap the zombie and make kill detect that it's gone: */
10086 dowait(DOWAIT_NONBLOCK, NULL);
10087
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020010088 if (evalbltin(cmdentry.u.cmd, argc, argv, flags)) {
Denys Vlasenkoc0663c72016-10-27 21:09:01 +020010089 if (exception_type == EXERROR && spclbltin <= 0) {
10090 FORCE_INT_ON;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020010091 goto readstatus;
Eric Andersenc470f442003-07-28 09:56:35 +000010092 }
Denys Vlasenkoc0663c72016-10-27 21:09:01 +020010093 raise:
10094 longjmp(exception_handler->loc, 1);
Eric Andersenc470f442003-07-28 09:56:35 +000010095 }
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020010096 goto readstatus;
Eric Andersenc470f442003-07-28 09:56:35 +000010097
10098 case CMDFUNCTION:
Denys Vlasenko981a0562017-07-26 19:53:11 +020010099 poplocalvars(1);
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +000010100 /* See above for the rationale */
10101 dowait(DOWAIT_NONBLOCK, NULL);
Eric Andersenc470f442003-07-28 09:56:35 +000010102 if (evalfun(cmdentry.u.func, argc, argv, flags))
10103 goto raise;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020010104 readstatus:
10105 status = exitstatus;
Eric Andersenc470f442003-07-28 09:56:35 +000010106 break;
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +020010107 } /* switch */
Eric Andersenc470f442003-07-28 09:56:35 +000010108
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010109 out:
Denys Vlasenkoeaf94362016-10-25 21:46:03 +020010110 if (cmd->ncmd.redirect)
Denys Vlasenko035486c2017-07-31 04:09:19 +020010111 popredir(/*drop:*/ cmd_is_exec);
Denys Vlasenko1c79aeb2017-07-29 22:51:52 +020010112 unwindredir(redir_stop);
Denys Vlasenko484fc202017-07-26 19:55:31 +020010113 unwindlocalvars(localvar_stop);
Denis Vlasenko6514c5e2008-07-24 13:41:37 +000010114 if (lastarg) {
Eric Andersenc470f442003-07-28 09:56:35 +000010115 /* dsl: I think this is intended to be used to support
10116 * '_' in 'vi' command mode during line editing...
10117 * However I implemented that within libedit itself.
10118 */
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020010119 setvar0("_", lastarg);
Denis Vlasenko6514c5e2008-07-24 13:41:37 +000010120 }
Eric Andersenc470f442003-07-28 09:56:35 +000010121 popstackmark(&smark);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020010122
10123 return status;
Eric Andersenc470f442003-07-28 09:56:35 +000010124}
10125
10126static int
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020010127evalbltin(const struct builtincmd *cmd, int argc, char **argv, int flags)
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010128{
Eric Andersenc470f442003-07-28 09:56:35 +000010129 char *volatile savecmdname;
10130 struct jmploc *volatile savehandler;
10131 struct jmploc jmploc;
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020010132 int status;
Eric Andersenc470f442003-07-28 09:56:35 +000010133 int i;
10134
10135 savecmdname = commandname;
Denys Vlasenkoa2d121c2016-09-30 11:30:11 +020010136 savehandler = exception_handler;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010137 i = setjmp(jmploc.loc);
10138 if (i)
Eric Andersenc470f442003-07-28 09:56:35 +000010139 goto cmddone;
Denis Vlasenko2da584f2007-02-19 22:44:05 +000010140 exception_handler = &jmploc;
Eric Andersenc470f442003-07-28 09:56:35 +000010141 commandname = argv[0];
10142 argptr = argv + 1;
10143 optptr = NULL; /* initialize nextopt */
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020010144 if (cmd == EVALCMD)
10145 status = evalcmd(argc, argv, flags);
10146 else
10147 status = (*cmd->builtin)(argc, argv);
Denis Vlasenkob012b102007-02-19 22:43:01 +000010148 flush_stdout_stderr();
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020010149 status |= ferror(stdout);
10150 exitstatus = status;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010151 cmddone:
Rob Landleyf296f0b2006-07-06 01:09:21 +000010152 clearerr(stdout);
Eric Andersenc470f442003-07-28 09:56:35 +000010153 commandname = savecmdname;
Denis Vlasenko2da584f2007-02-19 22:44:05 +000010154 exception_handler = savehandler;
Eric Andersenc470f442003-07-28 09:56:35 +000010155
10156 return i;
10157}
10158
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010159static int
10160goodname(const char *p)
Glenn L McGrath16e45d72004-02-04 08:24:39 +000010161{
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +020010162 return endofname(p)[0] == '\0';
Glenn L McGrath16e45d72004-02-04 08:24:39 +000010163}
10164
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010165
Glenn L McGrath50812ff2002-08-23 13:14:48 +000010166/*
10167 * Search for a command. This is called before we fork so that the
10168 * location of the command will be available in the parent as well as
Glenn L McGrath16e45d72004-02-04 08:24:39 +000010169 * the child. The check for "goodname" is an overly conservative
10170 * check that the name will not be subject to expansion.
Glenn L McGrath50812ff2002-08-23 13:14:48 +000010171 */
Eric Andersenc470f442003-07-28 09:56:35 +000010172static void
10173prehash(union node *n)
Glenn L McGrath50812ff2002-08-23 13:14:48 +000010174{
10175 struct cmdentry entry;
10176
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000010177 if (n->type == NCMD && n->ncmd.args && goodname(n->ncmd.args->narg.text))
10178 find_command(n->ncmd.args->narg.text, &entry, 0, pathval());
Glenn L McGrath50812ff2002-08-23 13:14:48 +000010179}
10180
Eric Andersencb57d552001-06-28 07:25:16 +000010181
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000010182/* ============ Builtin commands
10183 *
10184 * Builtin commands whose functions are closely tied to evaluation
10185 * are implemented here.
Eric Andersencb57d552001-06-28 07:25:16 +000010186 */
10187
10188/*
Eric Andersencb57d552001-06-28 07:25:16 +000010189 * Handle break and continue commands. Break, continue, and return are
10190 * all handled by setting the evalskip flag. The evaluation routines
10191 * above all check this flag, and if it is set they start skipping
10192 * commands rather than executing them. The variable skipcount is
10193 * the number of loops to break/continue, or the number of function
10194 * levels to return. (The latter is always 1.) It should probably
10195 * be an error to break out of more loops than exist, but it isn't
10196 * in the standard shell so we don't make it one here.
10197 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010198static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010199breakcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000010200{
Denis Vlasenko68404f12008-03-17 09:00:54 +000010201 int n = argv[1] ? number(argv[1]) : 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010202
Aaron Lehmann2aef3a62001-12-31 06:03:12 +000010203 if (n <= 0)
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +020010204 ash_msg_and_raise_error(msg_illnum, argv[1]);
Eric Andersencb57d552001-06-28 07:25:16 +000010205 if (n > loopnest)
10206 n = loopnest;
10207 if (n > 0) {
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000010208 evalskip = (**argv == 'c') ? SKIPCONT : SKIPBREAK;
Eric Andersencb57d552001-06-28 07:25:16 +000010209 skipcount = n;
10210 }
10211 return 0;
10212}
10213
Eric Andersenc470f442003-07-28 09:56:35 +000010214
Denys Vlasenko70392332016-10-27 02:31:55 +020010215/*
Eric Andersen90898442003-08-06 11:20:52 +000010216 * This implements the input routines used by the parser.
Eric Andersencb57d552001-06-28 07:25:16 +000010217 */
Denis Vlasenko99eb8502007-02-23 21:09:49 +000010218
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010219enum {
10220 INPUT_PUSH_FILE = 1,
10221 INPUT_NOFILE_OK = 2,
10222};
Eric Andersencb57d552001-06-28 07:25:16 +000010223
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010224static smallint checkkwd;
Denis Vlasenko99eb8502007-02-23 21:09:49 +000010225/* values of checkkwd variable */
10226#define CHKALIAS 0x1
10227#define CHKKWD 0x2
10228#define CHKNL 0x4
Denys Vlasenkoa7328982017-07-29 19:57:28 +020010229#define CHKEOFMARK 0x8
Denis Vlasenko99eb8502007-02-23 21:09:49 +000010230
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010231/*
10232 * Push a string back onto the input at this current parsefile level.
10233 * We handle aliases this way.
10234 */
10235#if !ENABLE_ASH_ALIAS
10236#define pushstring(s, ap) pushstring(s)
10237#endif
10238static void
10239pushstring(char *s, struct alias *ap)
10240{
10241 struct strpush *sp;
10242 int len;
10243
10244 len = strlen(s);
10245 INT_OFF;
10246 if (g_parsefile->strpush) {
10247 sp = ckzalloc(sizeof(*sp));
10248 sp->prev = g_parsefile->strpush;
10249 } else {
10250 sp = &(g_parsefile->basestrpush);
10251 }
10252 g_parsefile->strpush = sp;
10253 sp->prev_string = g_parsefile->next_to_pgetc;
10254 sp->prev_left_in_line = g_parsefile->left_in_line;
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010255 sp->unget = g_parsefile->unget;
10256 memcpy(sp->lastc, g_parsefile->lastc, sizeof(sp->lastc));
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010257#if ENABLE_ASH_ALIAS
10258 sp->ap = ap;
10259 if (ap) {
10260 ap->flag |= ALIASINUSE;
10261 sp->string = s;
10262 }
10263#endif
10264 g_parsefile->next_to_pgetc = s;
10265 g_parsefile->left_in_line = len;
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010266 g_parsefile->unget = 0;
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010267 INT_ON;
10268}
10269
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010270static void
10271popstring(void)
Eric Andersenc470f442003-07-28 09:56:35 +000010272{
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010273 struct strpush *sp = g_parsefile->strpush;
Eric Andersenc470f442003-07-28 09:56:35 +000010274
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010275 INT_OFF;
Denis Vlasenko131ae172007-02-18 13:00:19 +000010276#if ENABLE_ASH_ALIAS
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010277 if (sp->ap) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010278 if (g_parsefile->next_to_pgetc[-1] == ' '
10279 || g_parsefile->next_to_pgetc[-1] == '\t'
10280 ) {
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010281 checkkwd |= CHKALIAS;
Glenn L McGrath28939ad2004-07-21 10:20:19 +000010282 }
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010283 if (sp->string != sp->ap->val) {
10284 free(sp->string);
10285 }
10286 sp->ap->flag &= ~ALIASINUSE;
10287 if (sp->ap->flag & ALIASDEAD) {
10288 unalias(sp->ap->name);
10289 }
Glenn L McGrath28939ad2004-07-21 10:20:19 +000010290 }
Denis Vlasenko8e1c7152007-01-22 07:21:38 +000010291#endif
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010292 g_parsefile->next_to_pgetc = sp->prev_string;
10293 g_parsefile->left_in_line = sp->prev_left_in_line;
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010294 g_parsefile->unget = sp->unget;
10295 memcpy(g_parsefile->lastc, sp->lastc, sizeof(sp->lastc));
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010296 g_parsefile->strpush = sp->prev;
10297 if (sp != &(g_parsefile->basestrpush))
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010298 free(sp);
10299 INT_ON;
10300}
Denis Vlasenko8e1c7152007-01-22 07:21:38 +000010301
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010302static int
10303preadfd(void)
Eric Andersencb57d552001-06-28 07:25:16 +000010304{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010305 int nr;
Denis Vlasenko6a0ad252008-07-25 13:34:05 +000010306 char *buf = g_parsefile->buf;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010307
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010308 g_parsefile->next_to_pgetc = buf;
Denis Vlasenko38f63192007-01-22 09:03:07 +000010309#if ENABLE_FEATURE_EDITING
Denis Vlasenko85c24712008-03-17 09:04:04 +000010310 retry:
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010311 if (!iflag || g_parsefile->pf_fd != STDIN_FILENO)
Ron Yorston61d6ae22015-04-19 10:50:25 +010010312 nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1);
Eric Andersenc470f442003-07-28 09:56:35 +000010313 else {
Denys Vlasenko66c5b122011-02-08 05:07:02 +010010314# if ENABLE_ASH_IDLE_TIMEOUT
Denys Vlasenko84ea60e2017-08-02 17:27:28 +020010315 int timeout = -1;
Denys Vlasenko66c5b122011-02-08 05:07:02 +010010316 if (iflag) {
10317 const char *tmout_var = lookupvar("TMOUT");
10318 if (tmout_var) {
10319 timeout = atoi(tmout_var) * 1000;
10320 if (timeout <= 0)
10321 timeout = -1;
10322 }
10323 }
Denys Vlasenko84ea60e2017-08-02 17:27:28 +020010324 line_input_state->timeout = timeout;
Denys Vlasenko66c5b122011-02-08 05:07:02 +010010325# endif
Denys Vlasenko8c52f802011-02-04 17:36:21 +010010326# if ENABLE_FEATURE_TAB_COMPLETION
Denis Vlasenko8e1c7152007-01-22 07:21:38 +000010327 line_input_state->path_lookup = pathval();
Denys Vlasenko8c52f802011-02-04 17:36:21 +010010328# endif
Denys Vlasenkoe9ab07c2014-08-13 18:00:08 +020010329 reinit_unicode_for_ash();
Denys Vlasenko84ea60e2017-08-02 17:27:28 +020010330 nr = read_line_input(line_input_state, cmdedit_prompt, buf, IBUFSIZ);
Denis Vlasenko8e1c7152007-01-22 07:21:38 +000010331 if (nr == 0) {
Denys Vlasenko4b89d512016-11-25 03:41:03 +010010332 /* ^C pressed, "convert" to SIGINT */
10333 write(STDOUT_FILENO, "^C", 2);
Denis Vlasenko8e1c7152007-01-22 07:21:38 +000010334 if (trap[SIGINT]) {
Glenn L McGrath16e45d72004-02-04 08:24:39 +000010335 buf[0] = '\n';
Denis Vlasenko8e1c7152007-01-22 07:21:38 +000010336 buf[1] = '\0';
Glenn L McGrath16e45d72004-02-04 08:24:39 +000010337 raise(SIGINT);
10338 return 1;
10339 }
Denys Vlasenko8660aeb2016-11-24 17:44:02 +010010340 exitstatus = 128 + SIGINT;
Denys Vlasenko4b89d512016-11-25 03:41:03 +010010341 bb_putchar('\n');
Eric Andersenc470f442003-07-28 09:56:35 +000010342 goto retry;
10343 }
Denys Vlasenko66c5b122011-02-08 05:07:02 +010010344 if (nr < 0) {
10345 if (errno == 0) {
10346 /* Ctrl+D pressed */
10347 nr = 0;
10348 }
10349# if ENABLE_ASH_IDLE_TIMEOUT
10350 else if (errno == EAGAIN && timeout > 0) {
Denys Vlasenkod60752f2015-10-07 22:42:45 +020010351 puts("\007timed out waiting for input: auto-logout");
Denys Vlasenko66c5b122011-02-08 05:07:02 +010010352 exitshell();
10353 }
10354# endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010355 }
Eric Andersencb57d552001-06-28 07:25:16 +000010356 }
10357#else
Ron Yorston61d6ae22015-04-19 10:50:25 +010010358 nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1);
Eric Andersencb57d552001-06-28 07:25:16 +000010359#endif
10360
Denys Vlasenko80c5b682011-05-08 21:21:10 +020010361#if 0 /* disabled: nonblock_immune_read() handles this problem */
Eric Andersencb57d552001-06-28 07:25:16 +000010362 if (nr < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +000010363 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
Denis Vlasenkod37f2222007-08-19 13:42:08 +000010364 int flags = fcntl(0, F_GETFL);
Denis Vlasenko9cb220b2007-12-09 10:03:28 +000010365 if (flags >= 0 && (flags & O_NONBLOCK)) {
10366 flags &= ~O_NONBLOCK;
Eric Andersencb57d552001-06-28 07:25:16 +000010367 if (fcntl(0, F_SETFL, flags) >= 0) {
10368 out2str("sh: turning off NDELAY mode\n");
10369 goto retry;
10370 }
10371 }
10372 }
10373 }
Denis Vlasenkoe376d452008-02-20 22:23:24 +000010374#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010375 return nr;
10376}
10377
10378/*
10379 * Refill the input buffer and return the next input character:
10380 *
10381 * 1) If a string was pushed back on the input, pop it;
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010382 * 2) If an EOF was pushed back (g_parsefile->left_in_line < -BIGNUM)
10383 * or we are reading from a string so we can't refill the buffer,
10384 * return EOF.
Denys Vlasenko883cea42009-07-11 15:31:59 +020010385 * 3) If there is more stuff in this buffer, use it else call read to fill it.
Eric Andersencb57d552001-06-28 07:25:16 +000010386 * 4) Process input up to the next newline, deleting nul characters.
10387 */
Denis Vlasenko727752d2008-11-28 03:41:47 +000010388//#define pgetc_debug(...) bb_error_msg(__VA_ARGS__)
10389#define pgetc_debug(...) ((void)0)
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010390static int pgetc(void);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010391static int
Eric Andersenc470f442003-07-28 09:56:35 +000010392preadbuffer(void)
Eric Andersencb57d552001-06-28 07:25:16 +000010393{
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010394 char *q;
Eric Andersencb57d552001-06-28 07:25:16 +000010395 int more;
Eric Andersencb57d552001-06-28 07:25:16 +000010396
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010397 if (g_parsefile->strpush) {
Denis Vlasenko131ae172007-02-18 13:00:19 +000010398#if ENABLE_ASH_ALIAS
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010399 if (g_parsefile->left_in_line == -1
10400 && g_parsefile->strpush->ap
10401 && g_parsefile->next_to_pgetc[-1] != ' '
10402 && g_parsefile->next_to_pgetc[-1] != '\t'
Denis Vlasenko16898402008-11-25 01:34:52 +000010403 ) {
Denis Vlasenko727752d2008-11-28 03:41:47 +000010404 pgetc_debug("preadbuffer PEOA");
Eric Andersencb57d552001-06-28 07:25:16 +000010405 return PEOA;
10406 }
Eric Andersen2870d962001-07-02 17:27:21 +000010407#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010408 popstring();
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010409 return pgetc();
Eric Andersencb57d552001-06-28 07:25:16 +000010410 }
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010411 /* on both branches above g_parsefile->left_in_line < 0.
Denis Vlasenko727752d2008-11-28 03:41:47 +000010412 * "pgetc" needs refilling.
10413 */
10414
Denis Vlasenkoe27dafd2008-11-28 04:01:03 +000010415 /* -90 is our -BIGNUM. Below we use -99 to mark "EOF on read",
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010416 * pungetc() may increment it a few times.
Denis Vlasenkoe27dafd2008-11-28 04:01:03 +000010417 * Assuming it won't increment it to less than -90.
Denis Vlasenko727752d2008-11-28 03:41:47 +000010418 */
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010419 if (g_parsefile->left_in_line < -90 || g_parsefile->buf == NULL) {
Denis Vlasenko727752d2008-11-28 03:41:47 +000010420 pgetc_debug("preadbuffer PEOF1");
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010421 /* even in failure keep left_in_line and next_to_pgetc
10422 * in lock step, for correct multi-layer pungetc.
10423 * left_in_line was decremented before preadbuffer(),
10424 * must inc next_to_pgetc: */
10425 g_parsefile->next_to_pgetc++;
Eric Andersencb57d552001-06-28 07:25:16 +000010426 return PEOF;
Denis Vlasenko727752d2008-11-28 03:41:47 +000010427 }
Eric Andersencb57d552001-06-28 07:25:16 +000010428
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010429 more = g_parsefile->left_in_buffer;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010430 if (more <= 0) {
Denis Vlasenko727752d2008-11-28 03:41:47 +000010431 flush_stdout_stderr();
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010432 again:
10433 more = preadfd();
10434 if (more <= 0) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010435 /* don't try reading again */
10436 g_parsefile->left_in_line = -99;
Denis Vlasenko727752d2008-11-28 03:41:47 +000010437 pgetc_debug("preadbuffer PEOF2");
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010438 g_parsefile->next_to_pgetc++;
Eric Andersencb57d552001-06-28 07:25:16 +000010439 return PEOF;
10440 }
10441 }
10442
Denis Vlasenko727752d2008-11-28 03:41:47 +000010443 /* Find out where's the end of line.
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010444 * Set g_parsefile->left_in_line
10445 * and g_parsefile->left_in_buffer acordingly.
Denis Vlasenko727752d2008-11-28 03:41:47 +000010446 * NUL chars are deleted.
10447 */
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010448 q = g_parsefile->next_to_pgetc;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010449 for (;;) {
Denis Vlasenko727752d2008-11-28 03:41:47 +000010450 char c;
Eric Andersencb57d552001-06-28 07:25:16 +000010451
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010452 more--;
Eric Andersenc470f442003-07-28 09:56:35 +000010453
Denis Vlasenko727752d2008-11-28 03:41:47 +000010454 c = *q;
10455 if (c == '\0') {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010456 memmove(q, q + 1, more);
Denis Vlasenko727752d2008-11-28 03:41:47 +000010457 } else {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010458 q++;
10459 if (c == '\n') {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010460 g_parsefile->left_in_line = q - g_parsefile->next_to_pgetc - 1;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010461 break;
10462 }
Eric Andersencb57d552001-06-28 07:25:16 +000010463 }
10464
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010465 if (more <= 0) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010466 g_parsefile->left_in_line = q - g_parsefile->next_to_pgetc - 1;
10467 if (g_parsefile->left_in_line < 0)
Eric Andersencb57d552001-06-28 07:25:16 +000010468 goto again;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010469 break;
Eric Andersencb57d552001-06-28 07:25:16 +000010470 }
10471 }
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010472 g_parsefile->left_in_buffer = more;
Eric Andersencb57d552001-06-28 07:25:16 +000010473
Eric Andersencb57d552001-06-28 07:25:16 +000010474 if (vflag) {
Denis Vlasenko727752d2008-11-28 03:41:47 +000010475 char save = *q;
10476 *q = '\0';
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010477 out2str(g_parsefile->next_to_pgetc);
Denis Vlasenko727752d2008-11-28 03:41:47 +000010478 *q = save;
Eric Andersencb57d552001-06-28 07:25:16 +000010479 }
10480
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010481 pgetc_debug("preadbuffer at %d:%p'%s'",
10482 g_parsefile->left_in_line,
10483 g_parsefile->next_to_pgetc,
10484 g_parsefile->next_to_pgetc);
Denys Vlasenkocd716832009-11-28 22:14:02 +010010485 return (unsigned char)*g_parsefile->next_to_pgetc++;
Eric Andersencb57d552001-06-28 07:25:16 +000010486}
10487
Denys Vlasenkoce332a22016-10-02 23:47:34 +020010488static void
10489nlprompt(void)
10490{
10491 g_parsefile->linno++;
10492 setprompt_if(doprompt, 2);
10493}
10494static void
10495nlnoprompt(void)
10496{
10497 g_parsefile->linno++;
10498 needprompt = doprompt;
10499}
10500
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010501static int
10502pgetc(void)
10503{
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010504 int c;
10505
10506 pgetc_debug("pgetc at %d:%p'%s'",
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010507 g_parsefile->left_in_line,
10508 g_parsefile->next_to_pgetc,
10509 g_parsefile->next_to_pgetc);
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010510 if (g_parsefile->unget)
10511 return g_parsefile->lastc[--g_parsefile->unget];
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010512
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010513 if (--g_parsefile->left_in_line >= 0)
Denys Vlasenko2fe66b12016-12-12 17:39:12 +010010514 c = (unsigned char)*g_parsefile->next_to_pgetc++;
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010515 else
10516 c = preadbuffer();
10517
10518 g_parsefile->lastc[1] = g_parsefile->lastc[0];
10519 g_parsefile->lastc[0] = c;
10520
10521 return c;
10522}
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010523
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010524#if ENABLE_ASH_ALIAS
10525static int
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010010526pgetc_without_PEOA(void)
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010527{
10528 int c;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010529 do {
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010530 pgetc_debug("pgetc at %d:%p'%s'",
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010531 g_parsefile->left_in_line,
10532 g_parsefile->next_to_pgetc,
10533 g_parsefile->next_to_pgetc);
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010534 c = pgetc();
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010535 } while (c == PEOA);
10536 return c;
10537}
10538#else
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010010539# define pgetc_without_PEOA() pgetc()
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010540#endif
10541
10542/*
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010543 * Undo a call to pgetc. Only two characters may be pushed back.
Eric Andersenc470f442003-07-28 09:56:35 +000010544 * PEOF may be pushed back.
10545 */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010546static void
Eric Andersenc470f442003-07-28 09:56:35 +000010547pungetc(void)
10548{
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010549 g_parsefile->unget++;
Eric Andersencb57d552001-06-28 07:25:16 +000010550}
10551
Denys Vlasenko73c3e072016-09-29 17:17:04 +020010552/* This one eats backslash+newline */
10553static int
10554pgetc_eatbnl(void)
10555{
10556 int c;
10557
10558 while ((c = pgetc()) == '\\') {
10559 if (pgetc() != '\n') {
10560 pungetc();
10561 break;
10562 }
10563
Denys Vlasenkoce332a22016-10-02 23:47:34 +020010564 nlprompt();
Denys Vlasenko73c3e072016-09-29 17:17:04 +020010565 }
10566
10567 return c;
10568}
10569
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010570/*
10571 * To handle the "." command, a stack of input files is used. Pushfile
10572 * adds a new entry to the stack and popfile restores the previous level.
10573 */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010574static void
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010575pushfile(void)
Eric Andersenc470f442003-07-28 09:56:35 +000010576{
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010577 struct parsefile *pf;
10578
Denis Vlasenko597906c2008-02-20 16:38:54 +000010579 pf = ckzalloc(sizeof(*pf));
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010580 pf->prev = g_parsefile;
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010581 pf->pf_fd = -1;
Denis Vlasenko597906c2008-02-20 16:38:54 +000010582 /*pf->strpush = NULL; - ckzalloc did it */
10583 /*pf->basestrpush.prev = NULL;*/
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010584 /*pf->unget = 0;*/
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010585 g_parsefile = pf;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010586}
10587
10588static void
10589popfile(void)
10590{
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010591 struct parsefile *pf = g_parsefile;
Eric Andersenc470f442003-07-28 09:56:35 +000010592
Denys Vlasenko493b9ca2016-10-30 18:27:14 +010010593 if (pf == &basepf)
10594 return;
10595
Denis Vlasenkob012b102007-02-19 22:43:01 +000010596 INT_OFF;
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010597 if (pf->pf_fd >= 0)
10598 close(pf->pf_fd);
Denis Vlasenko60818682007-09-28 22:07:23 +000010599 free(pf->buf);
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010600 while (pf->strpush)
10601 popstring();
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010602 g_parsefile = pf->prev;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010603 free(pf);
Denis Vlasenkob012b102007-02-19 22:43:01 +000010604 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +000010605}
10606
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010607/*
10608 * Return to top level.
10609 */
10610static void
10611popallfiles(void)
10612{
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010613 while (g_parsefile != &basepf)
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010614 popfile();
10615}
10616
10617/*
10618 * Close the file(s) that the shell is reading commands from. Called
10619 * after a fork is done.
10620 */
10621static void
10622closescript(void)
10623{
10624 popallfiles();
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010625 if (g_parsefile->pf_fd > 0) {
10626 close(g_parsefile->pf_fd);
10627 g_parsefile->pf_fd = 0;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010628 }
10629}
10630
10631/*
10632 * Like setinputfile, but takes an open file descriptor. Call this with
10633 * interrupts off.
10634 */
10635static void
10636setinputfd(int fd, int push)
10637{
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010638 if (push) {
10639 pushfile();
Denis Vlasenko727752d2008-11-28 03:41:47 +000010640 g_parsefile->buf = NULL;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010641 }
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010642 g_parsefile->pf_fd = fd;
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010643 if (g_parsefile->buf == NULL)
10644 g_parsefile->buf = ckmalloc(IBUFSIZ);
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010645 g_parsefile->left_in_buffer = 0;
10646 g_parsefile->left_in_line = 0;
10647 g_parsefile->linno = 1;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010648}
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010649
Eric Andersenc470f442003-07-28 09:56:35 +000010650/*
10651 * Set the input to take input from a file. If push is set, push the
10652 * old input onto the stack first.
10653 */
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010654static int
10655setinputfile(const char *fname, int flags)
Eric Andersenc470f442003-07-28 09:56:35 +000010656{
10657 int fd;
Eric Andersenc470f442003-07-28 09:56:35 +000010658
Denis Vlasenkob012b102007-02-19 22:43:01 +000010659 INT_OFF;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010660 fd = open(fname, O_RDONLY);
10661 if (fd < 0) {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010662 if (flags & INPUT_NOFILE_OK)
10663 goto out;
Denys Vlasenkob7adf7a2016-10-25 17:00:13 +020010664 exitstatus = 127;
Johannes Schindelin20a63b22017-08-22 22:03:17 +020010665 ash_msg_and_raise_perror("can't open '%s'", fname);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010666 }
Denys Vlasenko64774602016-10-26 15:24:30 +020010667 if (fd < 10)
10668 fd = savefd(fd);
Denys Vlasenkoe19923f2016-10-26 15:38:44 +020010669 else
10670 close_on_exec_on(fd);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010671 setinputfd(fd, flags & INPUT_PUSH_FILE);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010672 out:
Denis Vlasenkob012b102007-02-19 22:43:01 +000010673 INT_ON;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010674 return fd;
Eric Andersenc470f442003-07-28 09:56:35 +000010675}
10676
Eric Andersencb57d552001-06-28 07:25:16 +000010677/*
10678 * Like setinputfile, but takes input from a string.
10679 */
Eric Andersenc470f442003-07-28 09:56:35 +000010680static void
10681setinputstring(char *string)
Eric Andersen62483552001-07-10 06:09:16 +000010682{
Denis Vlasenkob012b102007-02-19 22:43:01 +000010683 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +000010684 pushfile();
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010685 g_parsefile->next_to_pgetc = string;
10686 g_parsefile->left_in_line = strlen(string);
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010687 g_parsefile->buf = NULL;
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010688 g_parsefile->linno = 1;
Denis Vlasenkob012b102007-02-19 22:43:01 +000010689 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +000010690}
10691
10692
Denys Vlasenko70392332016-10-27 02:31:55 +020010693/*
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010694 * Routines to check for mail.
Eric Andersencb57d552001-06-28 07:25:16 +000010695 */
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010696
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010697#if ENABLE_ASH_MAIL
Eric Andersencb57d552001-06-28 07:25:16 +000010698
Denys Vlasenko23841622015-10-09 15:52:03 +020010699/* Hash of mtimes of mailboxes */
10700static unsigned mailtime_hash;
Eric Andersenc470f442003-07-28 09:56:35 +000010701/* Set if MAIL or MAILPATH is changed. */
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010702static smallint mail_var_path_changed;
Eric Andersencb57d552001-06-28 07:25:16 +000010703
Eric Andersencb57d552001-06-28 07:25:16 +000010704/*
Eric Andersenc470f442003-07-28 09:56:35 +000010705 * Print appropriate message(s) if mail has arrived.
10706 * If mail_var_path_changed is set,
10707 * then the value of MAIL has mail_var_path_changed,
10708 * so we just update the values.
Eric Andersencb57d552001-06-28 07:25:16 +000010709 */
Eric Andersenc470f442003-07-28 09:56:35 +000010710static void
10711chkmail(void)
Eric Andersencb57d552001-06-28 07:25:16 +000010712{
Eric Andersencb57d552001-06-28 07:25:16 +000010713 const char *mpath;
10714 char *p;
10715 char *q;
Denys Vlasenko23841622015-10-09 15:52:03 +020010716 unsigned new_hash;
Eric Andersencb57d552001-06-28 07:25:16 +000010717 struct stackmark smark;
10718 struct stat statb;
10719
Eric Andersencb57d552001-06-28 07:25:16 +000010720 setstackmark(&smark);
Eric Andersenc470f442003-07-28 09:56:35 +000010721 mpath = mpathset() ? mpathval() : mailval();
Denys Vlasenko23841622015-10-09 15:52:03 +020010722 new_hash = 0;
10723 for (;;) {
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020010724 p = path_advance(&mpath, nullstr);
Eric Andersencb57d552001-06-28 07:25:16 +000010725 if (p == NULL)
10726 break;
10727 if (*p == '\0')
10728 continue;
Denis Vlasenkof7d56652008-03-25 05:51:41 +000010729 for (q = p; *q; q++)
10730 continue;
Denis Vlasenkoa7189f02006-11-17 20:29:00 +000010731#if DEBUG
Eric Andersencb57d552001-06-28 07:25:16 +000010732 if (q[-1] != '/')
10733 abort();
10734#endif
Eric Andersenc470f442003-07-28 09:56:35 +000010735 q[-1] = '\0'; /* delete trailing '/' */
10736 if (stat(p, &statb) < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +000010737 continue;
Eric Andersencb57d552001-06-28 07:25:16 +000010738 }
Denys Vlasenko23841622015-10-09 15:52:03 +020010739 /* Very simplistic "hash": just a sum of all mtimes */
10740 new_hash += (unsigned)statb.st_mtime;
10741 }
10742 if (!mail_var_path_changed && mailtime_hash != new_hash) {
Denys Vlasenko4cd99e72015-10-09 16:02:53 +020010743 if (mailtime_hash != 0)
10744 out2str("you have mail\n");
Denys Vlasenko23841622015-10-09 15:52:03 +020010745 mailtime_hash = new_hash;
Eric Andersencb57d552001-06-28 07:25:16 +000010746 }
Eric Andersenc470f442003-07-28 09:56:35 +000010747 mail_var_path_changed = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010748 popstackmark(&smark);
10749}
Eric Andersencb57d552001-06-28 07:25:16 +000010750
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010751static void FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010752changemail(const char *val UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000010753{
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010754 mail_var_path_changed = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000010755}
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010756
Denis Vlasenko131ae172007-02-18 13:00:19 +000010757#endif /* ASH_MAIL */
Eric Andersenc470f442003-07-28 09:56:35 +000010758
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010759
10760/* ============ ??? */
10761
Eric Andersencb57d552001-06-28 07:25:16 +000010762/*
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010763 * Set the shell parameters.
Eric Andersencb57d552001-06-28 07:25:16 +000010764 */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010765static void
10766setparam(char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000010767{
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010768 char **newparam;
10769 char **ap;
10770 int nparam;
Eric Andersencb57d552001-06-28 07:25:16 +000010771
Denis Vlasenkof7d56652008-03-25 05:51:41 +000010772 for (nparam = 0; argv[nparam]; nparam++)
10773 continue;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010774 ap = newparam = ckmalloc((nparam + 1) * sizeof(*ap));
10775 while (*argv) {
10776 *ap++ = ckstrdup(*argv++);
Eric Andersencb57d552001-06-28 07:25:16 +000010777 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010778 *ap = NULL;
10779 freeparam(&shellparam);
Denis Vlasenko01631112007-12-16 17:20:38 +000010780 shellparam.malloced = 1;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010781 shellparam.nparam = nparam;
10782 shellparam.p = newparam;
10783#if ENABLE_ASH_GETOPTS
10784 shellparam.optind = 1;
10785 shellparam.optoff = -1;
10786#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010787}
10788
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010789/*
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010790 * Process shell options. The global variable argptr contains a pointer
10791 * to the argument list; we advance it past the options.
Denis Vlasenko94e87bc2008-02-14 16:51:58 +000010792 *
10793 * SUSv3 section 2.8.1 "Consequences of Shell Errors" says:
10794 * For a non-interactive shell, an error condition encountered
10795 * by a special built-in ... shall cause the shell to write a diagnostic message
10796 * to standard error and exit as shown in the following table:
Denis Vlasenko56244732008-02-17 15:14:04 +000010797 * Error Special Built-In
Denis Vlasenko94e87bc2008-02-14 16:51:58 +000010798 * ...
10799 * Utility syntax error (option or operand error) Shall exit
10800 * ...
10801 * However, in bug 1142 (http://busybox.net/bugs/view.php?id=1142)
10802 * we see that bash does not do that (set "finishes" with error code 1 instead,
10803 * and shell continues), and people rely on this behavior!
10804 * Testcase:
10805 * set -o barfoo 2>/dev/null
10806 * echo $?
10807 *
10808 * Oh well. Let's mimic that.
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010809 */
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010810static int
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010811plus_minus_o(char *name, int val)
Eric Andersen62483552001-07-10 06:09:16 +000010812{
10813 int i;
10814
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010815 if (name) {
10816 for (i = 0; i < NOPTS; i++) {
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000010817 if (strcmp(name, optnames(i)) == 0) {
Eric Andersenc470f442003-07-28 09:56:35 +000010818 optlist[i] = val;
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010819 return 0;
Eric Andersen62483552001-07-10 06:09:16 +000010820 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010821 }
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010822 ash_msg("illegal option %co %s", val ? '-' : '+', name);
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010823 return 1;
Eric Andersen62483552001-07-10 06:09:16 +000010824 }
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000010825 for (i = 0; i < NOPTS; i++) {
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010826 if (val) {
10827 out1fmt("%-16s%s\n", optnames(i), optlist[i] ? "on" : "off");
10828 } else {
10829 out1fmt("set %co %s\n", optlist[i] ? '-' : '+', optnames(i));
10830 }
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000010831 }
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010832 return 0;
Eric Andersen62483552001-07-10 06:09:16 +000010833}
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010834static void
10835setoption(int flag, int val)
10836{
10837 int i;
10838
10839 for (i = 0; i < NOPTS; i++) {
10840 if (optletters(i) == flag) {
10841 optlist[i] = val;
10842 return;
10843 }
10844 }
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010845 ash_msg_and_raise_error("illegal option %c%c", val ? '-' : '+', flag);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010846 /* NOTREACHED */
10847}
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010848static int
Denys Vlasenkoec05df12017-07-31 19:43:47 +020010849options(int cmdline, int *login_sh)
Eric Andersencb57d552001-06-28 07:25:16 +000010850{
10851 char *p;
10852 int val;
10853 int c;
10854
10855 if (cmdline)
10856 minusc = NULL;
10857 while ((p = *argptr) != NULL) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010858 c = *p++;
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010859 if (c != '-' && c != '+')
10860 break;
10861 argptr++;
10862 val = 0; /* val = 0 if c == '+' */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010863 if (c == '-') {
Eric Andersencb57d552001-06-28 07:25:16 +000010864 val = 1;
Denis Vlasenko9f739442006-12-16 23:49:13 +000010865 if (p[0] == '\0' || LONE_DASH(p)) {
Eric Andersen2870d962001-07-02 17:27:21 +000010866 if (!cmdline) {
10867 /* "-" means turn off -x and -v */
10868 if (p[0] == '\0')
10869 xflag = vflag = 0;
10870 /* "--" means reset params */
10871 else if (*argptr == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +000010872 setparam(argptr);
Eric Andersen2870d962001-07-02 17:27:21 +000010873 }
Denys Vlasenkob0b83432011-03-07 12:34:59 +010010874 break; /* "-" or "--" terminates options */
Eric Andersencb57d552001-06-28 07:25:16 +000010875 }
Eric Andersencb57d552001-06-28 07:25:16 +000010876 }
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010877 /* first char was + or - */
Eric Andersencb57d552001-06-28 07:25:16 +000010878 while ((c = *p++) != '\0') {
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010879 /* bash 3.2 indeed handles -c CMD and +c CMD the same */
Eric Andersencb57d552001-06-28 07:25:16 +000010880 if (c == 'c' && cmdline) {
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010881 minusc = p; /* command is after shell args */
Eric Andersencb57d552001-06-28 07:25:16 +000010882 } else if (c == 'o') {
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010883 if (plus_minus_o(*argptr, val)) {
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010884 /* it already printed err message */
10885 return 1; /* error */
10886 }
Eric Andersencb57d552001-06-28 07:25:16 +000010887 if (*argptr)
10888 argptr++;
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010889 } else if (cmdline && (c == 'l')) { /* -l or +l == --login */
Denys Vlasenkoec05df12017-07-31 19:43:47 +020010890 if (login_sh)
10891 *login_sh = 1;
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010892 /* bash does not accept +-login, we also won't */
10893 } else if (cmdline && val && (c == '-')) { /* long options */
Denys Vlasenkoec05df12017-07-31 19:43:47 +020010894 if (strcmp(p, "login") == 0) {
10895 if (login_sh)
10896 *login_sh = 1;
10897 }
Robert Griebl64f70cc2002-05-14 23:22:06 +000010898 break;
Eric Andersencb57d552001-06-28 07:25:16 +000010899 } else {
10900 setoption(c, val);
10901 }
10902 }
10903 }
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010904 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010905}
10906
Eric Andersencb57d552001-06-28 07:25:16 +000010907/*
Eric Andersencb57d552001-06-28 07:25:16 +000010908 * The shift builtin command.
10909 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010910static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010911shiftcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000010912{
10913 int n;
10914 char **ap1, **ap2;
10915
10916 n = 1;
Denis Vlasenko68404f12008-03-17 09:00:54 +000010917 if (argv[1])
Eric Andersencb57d552001-06-28 07:25:16 +000010918 n = number(argv[1]);
10919 if (n > shellparam.nparam)
Ingo van Lil9c8e94b2018-01-05 15:04:23 +010010920 return 1;
Denis Vlasenkob012b102007-02-19 22:43:01 +000010921 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +000010922 shellparam.nparam -= n;
Denis Vlasenko2da584f2007-02-19 22:44:05 +000010923 for (ap1 = shellparam.p; --n >= 0; ap1++) {
Denis Vlasenko01631112007-12-16 17:20:38 +000010924 if (shellparam.malloced)
Denis Vlasenkob012b102007-02-19 22:43:01 +000010925 free(*ap1);
Eric Andersencb57d552001-06-28 07:25:16 +000010926 }
10927 ap2 = shellparam.p;
Denis Vlasenkof7d56652008-03-25 05:51:41 +000010928 while ((*ap2++ = *ap1++) != NULL)
10929 continue;
Denis Vlasenko131ae172007-02-18 13:00:19 +000010930#if ENABLE_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +000010931 shellparam.optind = 1;
10932 shellparam.optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +000010933#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +000010934 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +000010935 return 0;
10936}
10937
Eric Andersencb57d552001-06-28 07:25:16 +000010938/*
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010939 * POSIX requires that 'set' (but not export or readonly) output the
10940 * variables in lexicographic order - by the locale's collating order (sigh).
10941 * Maybe we could keep them in an ordered balanced binary tree
10942 * instead of hashed lists.
10943 * For now just roll 'em through qsort for printing...
10944 */
10945static int
10946showvars(const char *sep_prefix, int on, int off)
10947{
10948 const char *sep;
10949 char **ep, **epend;
10950
Denys Vlasenkoa5060b82017-11-03 14:16:25 +010010951 ep = listvars(on, off, /*strlist:*/ NULL, &epend);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010952 qsort(ep, epend - ep, sizeof(char *), vpcmp);
10953
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010954 sep = *sep_prefix ? " " : sep_prefix;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010955
10956 for (; ep < epend; ep++) {
10957 const char *p;
10958 const char *q;
10959
Denys Vlasenko9c143ce2017-11-02 12:56:24 +010010960 p = endofname(*ep);
10961/* Used to have simple "p = strchrnul(*ep, '=')" here instead, but this
10962 * makes "export -p" to have output not suitable for "eval":
10963 * import os
10964 * os.environ["test-test"]="test"
10965 * if os.fork() == 0:
10966 * os.execv("ash", [ 'ash', '-c', 'eval $(export -p); echo OK' ]) # fixes this
10967 * os.execv("ash", [ 'ash', '-c', 'env | grep test-test' ])
10968 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010969 q = nullstr;
Denys Vlasenko9c143ce2017-11-02 12:56:24 +010010970 if (*p == '=')
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010971 q = single_quote(++p);
10972 out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
10973 }
10974 return 0;
10975}
10976
10977/*
Eric Andersencb57d552001-06-28 07:25:16 +000010978 * The set command builtin.
10979 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010980static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010981setcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +000010982{
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010983 int retval;
10984
Denis Vlasenko68404f12008-03-17 09:00:54 +000010985 if (!argv[1])
Eric Andersenc470f442003-07-28 09:56:35 +000010986 return showvars(nullstr, 0, VUNSET);
Denys Vlasenkob0b83432011-03-07 12:34:59 +010010987
Denis Vlasenkob012b102007-02-19 22:43:01 +000010988 INT_OFF;
Denys Vlasenkoec05df12017-07-31 19:43:47 +020010989 retval = options(/*cmdline:*/ 0, NULL);
Denys Vlasenkob0b83432011-03-07 12:34:59 +010010990 if (retval == 0) { /* if no parse error... */
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010991 optschanged();
10992 if (*argptr != NULL) {
10993 setparam(argptr);
10994 }
Eric Andersencb57d552001-06-28 07:25:16 +000010995 }
Denis Vlasenkob012b102007-02-19 22:43:01 +000010996 INT_ON;
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010997 return retval;
Eric Andersencb57d552001-06-28 07:25:16 +000010998}
10999
Denis Vlasenko131ae172007-02-18 13:00:19 +000011000#if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020011001static void FAST_FUNC
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000011002change_random(const char *value)
Eric Andersenef02f822004-03-11 13:34:24 +000011003{
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020011004 uint32_t t;
11005
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011006 if (value == NULL) {
Eric Andersen16767e22004-03-16 05:14:10 +000011007 /* "get", generate */
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020011008 t = next_random(&random_gen);
Eric Andersen16767e22004-03-16 05:14:10 +000011009 /* set without recursion */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +020011010 setvar(vrandom.var_text, utoa(t), VNOFUNC);
Eric Andersen16767e22004-03-16 05:14:10 +000011011 vrandom.flags &= ~VNOFUNC;
11012 } else {
11013 /* set/reset */
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020011014 t = strtoul(value, NULL, 10);
11015 INIT_RANDOM_T(&random_gen, (t ? t : 1), t);
Eric Andersen16767e22004-03-16 05:14:10 +000011016 }
Eric Andersenef02f822004-03-11 13:34:24 +000011017}
Eric Andersen16767e22004-03-16 05:14:10 +000011018#endif
11019
Denis Vlasenko131ae172007-02-18 13:00:19 +000011020#if ENABLE_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +000011021static int
Denys Vlasenko35c2a132016-10-26 17:34:26 +020011022getopts(char *optstr, char *optvar, char **optfirst)
Eric Andersencb57d552001-06-28 07:25:16 +000011023{
11024 char *p, *q;
11025 char c = '?';
11026 int done = 0;
Denys Vlasenko9c541002015-10-07 15:44:36 +020011027 char sbuf[2];
Eric Andersena48b0a32003-10-22 10:56:47 +000011028 char **optnext;
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020011029 int ind = shellparam.optind;
11030 int off = shellparam.optoff;
Eric Andersencb57d552001-06-28 07:25:16 +000011031
Denys Vlasenko9c541002015-10-07 15:44:36 +020011032 sbuf[1] = '\0';
11033
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020011034 shellparam.optind = -1;
11035 optnext = optfirst + ind - 1;
Eric Andersena48b0a32003-10-22 10:56:47 +000011036
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020011037 if (ind <= 1 || off < 0 || (int)strlen(optnext[-1]) < off)
Eric Andersencb57d552001-06-28 07:25:16 +000011038 p = NULL;
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020011039 else
11040 p = optnext[-1] + off;
Eric Andersencb57d552001-06-28 07:25:16 +000011041 if (p == NULL || *p == '\0') {
11042 /* Current word is done, advance */
Eric Andersencb57d552001-06-28 07:25:16 +000011043 p = *optnext;
11044 if (p == NULL || *p != '-' || *++p == '\0') {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011045 atend:
Denys Vlasenko9832bba2017-08-15 15:44:41 +020011046 unsetvar("OPTARG");
Eric Andersencb57d552001-06-28 07:25:16 +000011047 p = NULL;
11048 done = 1;
11049 goto out;
11050 }
11051 optnext++;
Denis Vlasenko9f739442006-12-16 23:49:13 +000011052 if (LONE_DASH(p)) /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +000011053 goto atend;
11054 }
11055
11056 c = *p++;
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +000011057 for (q = optstr; *q != c;) {
Eric Andersencb57d552001-06-28 07:25:16 +000011058 if (*q == '\0') {
Denys Vlasenko9832bba2017-08-15 15:44:41 +020011059 /* OPTERR is a bashism */
11060 const char *cp = lookupvar("OPTERR");
11061 if ((cp && LONE_CHAR(cp, '0'))
11062 || (optstr[0] == ':')
11063 ) {
Denys Vlasenko9c541002015-10-07 15:44:36 +020011064 sbuf[0] = c;
11065 /*sbuf[1] = '\0'; - already is */
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020011066 setvar0("OPTARG", sbuf);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011067 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000011068 fprintf(stderr, "Illegal option -%c\n", c);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011069 unsetvar("OPTARG");
Eric Andersencb57d552001-06-28 07:25:16 +000011070 }
11071 c = '?';
Eric Andersenc470f442003-07-28 09:56:35 +000011072 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +000011073 }
11074 if (*++q == ':')
11075 q++;
11076 }
11077
11078 if (*++q == ':') {
11079 if (*p == '\0' && (p = *optnext) == NULL) {
Denys Vlasenko9832bba2017-08-15 15:44:41 +020011080 /* OPTERR is a bashism */
11081 const char *cp = lookupvar("OPTERR");
11082 if ((cp && LONE_CHAR(cp, '0'))
11083 || (optstr[0] == ':')
11084 ) {
Denys Vlasenko9c541002015-10-07 15:44:36 +020011085 sbuf[0] = c;
11086 /*sbuf[1] = '\0'; - already is */
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020011087 setvar0("OPTARG", sbuf);
Eric Andersencb57d552001-06-28 07:25:16 +000011088 c = ':';
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011089 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000011090 fprintf(stderr, "No arg for -%c option\n", c);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011091 unsetvar("OPTARG");
Eric Andersencb57d552001-06-28 07:25:16 +000011092 c = '?';
11093 }
Eric Andersenc470f442003-07-28 09:56:35 +000011094 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +000011095 }
11096
11097 if (p == *optnext)
11098 optnext++;
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020011099 setvar0("OPTARG", p);
Eric Andersencb57d552001-06-28 07:25:16 +000011100 p = NULL;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011101 } else
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020011102 setvar0("OPTARG", nullstr);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011103 out:
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020011104 ind = optnext - optfirst + 1;
11105 setvar("OPTIND", itoa(ind), VNOFUNC);
Denys Vlasenko9c541002015-10-07 15:44:36 +020011106 sbuf[0] = c;
11107 /*sbuf[1] = '\0'; - already is */
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020011108 setvar0(optvar, sbuf);
11109
11110 shellparam.optoff = p ? p - *(optnext - 1) : -1;
11111 shellparam.optind = ind;
11112
Eric Andersencb57d552001-06-28 07:25:16 +000011113 return done;
11114}
Eric Andersenc470f442003-07-28 09:56:35 +000011115
11116/*
11117 * The getopts builtin. Shellparam.optnext points to the next argument
11118 * to be processed. Shellparam.optptr points to the next character to
11119 * be processed in the current argument. If shellparam.optnext is NULL,
11120 * then it's the first time getopts has been called.
11121 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020011122static int FAST_FUNC
Eric Andersenc470f442003-07-28 09:56:35 +000011123getoptscmd(int argc, char **argv)
11124{
11125 char **optbase;
11126
11127 if (argc < 3)
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +000011128 ash_msg_and_raise_error("usage: getopts optstring var [arg]");
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011129 if (argc == 3) {
Eric Andersenc470f442003-07-28 09:56:35 +000011130 optbase = shellparam.p;
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020011131 if ((unsigned)shellparam.optind > shellparam.nparam + 1) {
Eric Andersenc470f442003-07-28 09:56:35 +000011132 shellparam.optind = 1;
11133 shellparam.optoff = -1;
11134 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011135 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000011136 optbase = &argv[3];
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020011137 if ((unsigned)shellparam.optind > argc - 2) {
Eric Andersenc470f442003-07-28 09:56:35 +000011138 shellparam.optind = 1;
11139 shellparam.optoff = -1;
11140 }
11141 }
11142
Denys Vlasenko35c2a132016-10-26 17:34:26 +020011143 return getopts(argv[1], argv[2], optbase);
Eric Andersenc470f442003-07-28 09:56:35 +000011144}
Denis Vlasenko131ae172007-02-18 13:00:19 +000011145#endif /* ASH_GETOPTS */
Eric Andersencb57d552001-06-28 07:25:16 +000011146
Eric Andersencb57d552001-06-28 07:25:16 +000011147
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011148/* ============ Shell parser */
Eric Andersencb57d552001-06-28 07:25:16 +000011149
Denis Vlasenkob07a4962008-06-22 13:16:23 +000011150struct heredoc {
11151 struct heredoc *next; /* next here document in list */
11152 union node *here; /* redirection node */
11153 char *eofmark; /* string indicating end of input */
11154 smallint striptabs; /* if set, strip leading tabs */
11155};
11156
11157static smallint tokpushback; /* last token pushed back */
Denis Vlasenkob07a4962008-06-22 13:16:23 +000011158static smallint quoteflag; /* set if (part of) last token was quoted */
11159static token_id_t lasttoken; /* last token read (integer id Txxx) */
11160static struct heredoc *heredoclist; /* list of here documents to read */
11161static char *wordtext; /* text of last word returned by readtoken */
11162static struct nodelist *backquotelist;
11163static union node *redirnode;
11164static struct heredoc *heredoc;
Denis Vlasenko99eb8502007-02-23 21:09:49 +000011165
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020011166static const char *
11167tokname(char *buf, int tok)
11168{
11169 if (tok < TSEMI)
Denys Vlasenko888527c2016-10-02 16:54:17 +020011170 return tokname_array[tok];
11171 sprintf(buf, "\"%s\"", tokname_array[tok]);
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020011172 return buf;
11173}
11174
11175/* raise_error_unexpected_syntax:
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011176 * Called when an unexpected token is read during the parse. The argument
11177 * is the token that is expected, or -1 if more than one type of token can
11178 * occur at this point.
11179 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000011180static void raise_error_unexpected_syntax(int) NORETURN;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011181static void
11182raise_error_unexpected_syntax(int token)
11183{
11184 char msg[64];
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020011185 char buf[16];
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011186 int l;
11187
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020011188 l = sprintf(msg, "unexpected %s", tokname(buf, lasttoken));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011189 if (token >= 0)
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020011190 sprintf(msg + l, " (expecting %s)", tokname(buf, token));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011191 raise_error_syntax(msg);
11192 /* NOTREACHED */
11193}
Eric Andersencb57d552001-06-28 07:25:16 +000011194
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011195/* parsing is heavily cross-recursive, need these forward decls */
11196static union node *andor(void);
11197static union node *pipeline(void);
11198static union node *parse_command(void);
11199static void parseheredoc(void);
Ron Yorstonc0e00762015-10-29 11:30:55 +000011200static int peektoken(void);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011201static int readtoken(void);
Eric Andersencb57d552001-06-28 07:25:16 +000011202
Eric Andersenc470f442003-07-28 09:56:35 +000011203static union node *
11204list(int nlflag)
Eric Andersencb57d552001-06-28 07:25:16 +000011205{
11206 union node *n1, *n2, *n3;
11207 int tok;
11208
Eric Andersencb57d552001-06-28 07:25:16 +000011209 n1 = NULL;
11210 for (;;) {
Ron Yorstonc0e00762015-10-29 11:30:55 +000011211 switch (peektoken()) {
11212 case TNL:
11213 if (!(nlflag & 1))
11214 break;
11215 parseheredoc();
11216 return n1;
11217
11218 case TEOF:
11219 if (!n1 && (nlflag & 1))
11220 n1 = NODE_EOF;
11221 parseheredoc();
11222 return n1;
11223 }
11224
11225 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Denys Vlasenko888527c2016-10-02 16:54:17 +020011226 if (nlflag == 2 && ((1 << peektoken()) & tokendlist))
Ron Yorstonc0e00762015-10-29 11:30:55 +000011227 return n1;
11228 nlflag |= 2;
11229
Eric Andersencb57d552001-06-28 07:25:16 +000011230 n2 = andor();
11231 tok = readtoken();
11232 if (tok == TBACKGND) {
Eric Andersenc470f442003-07-28 09:56:35 +000011233 if (n2->type == NPIPE) {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +000011234 n2->npipe.pipe_backgnd = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011235 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000011236 if (n2->type != NREDIR) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011237 n3 = stzalloc(sizeof(struct nredir));
Eric Andersenc470f442003-07-28 09:56:35 +000011238 n3->nredir.n = n2;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011239 /*n3->nredir.redirect = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011240 n2 = n3;
11241 }
11242 n2->type = NBACKGND;
Eric Andersencb57d552001-06-28 07:25:16 +000011243 }
11244 }
11245 if (n1 == NULL) {
11246 n1 = n2;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011247 } else {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011248 n3 = stzalloc(sizeof(struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +000011249 n3->type = NSEMI;
11250 n3->nbinary.ch1 = n1;
11251 n3->nbinary.ch2 = n2;
11252 n1 = n3;
11253 }
11254 switch (tok) {
Ron Yorstonc0e00762015-10-29 11:30:55 +000011255 case TNL:
11256 case TEOF:
11257 tokpushback = 1;
11258 /* fall through */
Eric Andersencb57d552001-06-28 07:25:16 +000011259 case TBACKGND:
11260 case TSEMI:
Eric Andersencb57d552001-06-28 07:25:16 +000011261 break;
Eric Andersencb57d552001-06-28 07:25:16 +000011262 default:
Ron Yorstonc0e00762015-10-29 11:30:55 +000011263 if ((nlflag & 1))
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011264 raise_error_unexpected_syntax(-1);
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011265 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011266 return n1;
11267 }
11268 }
11269}
11270
Eric Andersenc470f442003-07-28 09:56:35 +000011271static union node *
11272andor(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011273{
Eric Andersencb57d552001-06-28 07:25:16 +000011274 union node *n1, *n2, *n3;
11275 int t;
11276
Eric Andersencb57d552001-06-28 07:25:16 +000011277 n1 = pipeline();
11278 for (;;) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011279 t = readtoken();
11280 if (t == TAND) {
Eric Andersencb57d552001-06-28 07:25:16 +000011281 t = NAND;
11282 } else if (t == TOR) {
11283 t = NOR;
11284 } else {
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011285 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011286 return n1;
11287 }
Eric Andersenc470f442003-07-28 09:56:35 +000011288 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000011289 n2 = pipeline();
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011290 n3 = stzalloc(sizeof(struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +000011291 n3->type = t;
11292 n3->nbinary.ch1 = n1;
11293 n3->nbinary.ch2 = n2;
11294 n1 = n3;
11295 }
11296}
11297
Eric Andersenc470f442003-07-28 09:56:35 +000011298static union node *
11299pipeline(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011300{
Eric Andersencb57d552001-06-28 07:25:16 +000011301 union node *n1, *n2, *pipenode;
11302 struct nodelist *lp, *prev;
11303 int negate;
11304
11305 negate = 0;
11306 TRACE(("pipeline: entered\n"));
11307 if (readtoken() == TNOT) {
11308 negate = !negate;
Eric Andersenc470f442003-07-28 09:56:35 +000011309 checkkwd = CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000011310 } else
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011311 tokpushback = 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011312 n1 = parse_command();
Eric Andersencb57d552001-06-28 07:25:16 +000011313 if (readtoken() == TPIPE) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011314 pipenode = stzalloc(sizeof(struct npipe));
Eric Andersencb57d552001-06-28 07:25:16 +000011315 pipenode->type = NPIPE;
Denis Vlasenko2dc240c2008-07-24 06:07:50 +000011316 /*pipenode->npipe.pipe_backgnd = 0; - stzalloc did it */
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011317 lp = stzalloc(sizeof(struct nodelist));
Eric Andersencb57d552001-06-28 07:25:16 +000011318 pipenode->npipe.cmdlist = lp;
11319 lp->n = n1;
11320 do {
11321 prev = lp;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011322 lp = stzalloc(sizeof(struct nodelist));
Eric Andersenc470f442003-07-28 09:56:35 +000011323 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011324 lp->n = parse_command();
Eric Andersencb57d552001-06-28 07:25:16 +000011325 prev->next = lp;
11326 } while (readtoken() == TPIPE);
11327 lp->next = NULL;
11328 n1 = pipenode;
11329 }
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011330 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011331 if (negate) {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011332 n2 = stzalloc(sizeof(struct nnot));
Eric Andersencb57d552001-06-28 07:25:16 +000011333 n2->type = NNOT;
11334 n2->nnot.com = n1;
11335 return n2;
Denis Vlasenko2da584f2007-02-19 22:44:05 +000011336 }
11337 return n1;
Eric Andersencb57d552001-06-28 07:25:16 +000011338}
11339
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011340static union node *
11341makename(void)
11342{
11343 union node *n;
11344
Denis Vlasenko597906c2008-02-20 16:38:54 +000011345 n = stzalloc(sizeof(struct narg));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011346 n->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011347 /*n->narg.next = NULL; - stzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011348 n->narg.text = wordtext;
11349 n->narg.backquote = backquotelist;
11350 return n;
11351}
11352
11353static void
11354fixredir(union node *n, const char *text, int err)
11355{
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000011356 int fd;
11357
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011358 TRACE(("Fix redir %s %d\n", text, err));
11359 if (!err)
11360 n->ndup.vname = NULL;
11361
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000011362 fd = bb_strtou(text, NULL, 10);
11363 if (!errno && fd >= 0)
11364 n->ndup.dupfd = fd;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011365 else if (LONE_DASH(text))
11366 n->ndup.dupfd = -1;
11367 else {
11368 if (err)
Denis Vlasenko559691a2008-10-05 18:39:31 +000011369 raise_error_syntax("bad fd number");
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011370 n->ndup.vname = makename();
11371 }
11372}
11373
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011374static void
11375parsefname(void)
11376{
11377 union node *n = redirnode;
11378
Denys Vlasenkoa7328982017-07-29 19:57:28 +020011379 if (n->type == NHERE)
11380 checkkwd = CHKEOFMARK;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011381 if (readtoken() != TWORD)
11382 raise_error_unexpected_syntax(-1);
11383 if (n->type == NHERE) {
11384 struct heredoc *here = heredoc;
11385 struct heredoc *p;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011386
11387 if (quoteflag == 0)
11388 n->type = NXHERE;
11389 TRACE(("Here document %d\n", n->type));
Denys Vlasenko740058b2018-01-09 17:01:00 +010011390 rmescapes(wordtext, 0, NULL);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011391 here->eofmark = wordtext;
11392 here->next = NULL;
11393 if (heredoclist == NULL)
11394 heredoclist = here;
11395 else {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011396 for (p = heredoclist; p->next; p = p->next)
11397 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011398 p->next = here;
11399 }
11400 } else if (n->type == NTOFD || n->type == NFROMFD) {
11401 fixredir(n, wordtext, 0);
11402 } else {
11403 n->nfile.fname = makename();
11404 }
11405}
Eric Andersencb57d552001-06-28 07:25:16 +000011406
Eric Andersenc470f442003-07-28 09:56:35 +000011407static union node *
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011408simplecmd(void)
11409{
11410 union node *args, **app;
11411 union node *n = NULL;
11412 union node *vars, **vpp;
11413 union node **rpp, *redir;
11414 int savecheckkwd;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011415#if BASH_TEST2
Denis Vlasenko80591b02008-03-25 07:49:43 +000011416 smallint double_brackets_flag = 0;
11417#endif
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011418 IF_BASH_FUNCTION(smallint function_flag = 0;)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011419
11420 args = NULL;
11421 app = &args;
11422 vars = NULL;
11423 vpp = &vars;
11424 redir = NULL;
11425 rpp = &redir;
11426
11427 savecheckkwd = CHKALIAS;
11428 for (;;) {
Denis Vlasenko80591b02008-03-25 07:49:43 +000011429 int t;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011430 checkkwd = savecheckkwd;
Denis Vlasenko80591b02008-03-25 07:49:43 +000011431 t = readtoken();
11432 switch (t) {
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011433#if BASH_FUNCTION
Ron Yorston95ebcf72015-11-03 09:42:23 +000011434 case TFUNCTION:
11435 if (peektoken() != TWORD)
11436 raise_error_unexpected_syntax(TWORD);
11437 function_flag = 1;
11438 break;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011439#endif
11440#if BASH_TEST2
Denis Vlasenko80591b02008-03-25 07:49:43 +000011441 case TAND: /* "&&" */
11442 case TOR: /* "||" */
11443 if (!double_brackets_flag) {
11444 tokpushback = 1;
11445 goto out;
11446 }
11447 wordtext = (char *) (t == TAND ? "-a" : "-o");
11448#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011449 case TWORD:
Denis Vlasenko597906c2008-02-20 16:38:54 +000011450 n = stzalloc(sizeof(struct narg));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011451 n->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011452 /*n->narg.next = NULL; - stzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011453 n->narg.text = wordtext;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011454#if BASH_TEST2
Denis Vlasenko80591b02008-03-25 07:49:43 +000011455 if (strcmp("[[", wordtext) == 0)
11456 double_brackets_flag = 1;
11457 else if (strcmp("]]", wordtext) == 0)
11458 double_brackets_flag = 0;
11459#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011460 n->narg.backquote = backquotelist;
11461 if (savecheckkwd && isassignment(wordtext)) {
11462 *vpp = n;
11463 vpp = &n->narg.next;
11464 } else {
11465 *app = n;
11466 app = &n->narg.next;
11467 savecheckkwd = 0;
11468 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011469#if BASH_FUNCTION
Ron Yorston95ebcf72015-11-03 09:42:23 +000011470 if (function_flag) {
11471 checkkwd = CHKNL | CHKKWD;
11472 switch (peektoken()) {
11473 case TBEGIN:
11474 case TIF:
11475 case TCASE:
11476 case TUNTIL:
11477 case TWHILE:
11478 case TFOR:
11479 goto do_func;
11480 case TLP:
11481 function_flag = 0;
11482 break;
11483 case TWORD:
11484 if (strcmp("[[", wordtext) == 0)
11485 goto do_func;
11486 /* fall through */
11487 default:
11488 raise_error_unexpected_syntax(-1);
11489 }
11490 }
11491#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011492 break;
11493 case TREDIR:
11494 *rpp = n = redirnode;
11495 rpp = &n->nfile.next;
11496 parsefname(); /* read name of redirection file */
11497 break;
11498 case TLP:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011499 IF_BASH_FUNCTION(do_func:)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011500 if (args && app == &args->narg.next
11501 && !vars && !redir
11502 ) {
11503 struct builtincmd *bcmd;
11504 const char *name;
11505
11506 /* We have a function */
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011507 if (IF_BASH_FUNCTION(!function_flag &&) readtoken() != TRP)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011508 raise_error_unexpected_syntax(TRP);
11509 name = n->narg.text;
11510 if (!goodname(name)
11511 || ((bcmd = find_builtin(name)) && IS_BUILTIN_SPECIAL(bcmd))
11512 ) {
Denis Vlasenko559691a2008-10-05 18:39:31 +000011513 raise_error_syntax("bad function name");
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011514 }
11515 n->type = NDEFUN;
11516 checkkwd = CHKNL | CHKKWD | CHKALIAS;
11517 n->narg.next = parse_command();
11518 return n;
11519 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011520 IF_BASH_FUNCTION(function_flag = 0;)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011521 /* fall through */
11522 default:
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011523 tokpushback = 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011524 goto out;
11525 }
11526 }
11527 out:
11528 *app = NULL;
11529 *vpp = NULL;
11530 *rpp = NULL;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011531 n = stzalloc(sizeof(struct ncmd));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011532 n->type = NCMD;
11533 n->ncmd.args = args;
11534 n->ncmd.assign = vars;
11535 n->ncmd.redirect = redir;
11536 return n;
11537}
11538
11539static union node *
11540parse_command(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011541{
Eric Andersencb57d552001-06-28 07:25:16 +000011542 union node *n1, *n2;
11543 union node *ap, **app;
11544 union node *cp, **cpp;
11545 union node *redir, **rpp;
Eric Andersenc470f442003-07-28 09:56:35 +000011546 union node **rpp2;
Eric Andersencb57d552001-06-28 07:25:16 +000011547 int t;
11548
11549 redir = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +000011550 rpp2 = &redir;
Eric Andersen88cec252001-09-06 17:35:20 +000011551
Eric Andersencb57d552001-06-28 07:25:16 +000011552 switch (readtoken()) {
Eric Andersenc470f442003-07-28 09:56:35 +000011553 default:
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011554 raise_error_unexpected_syntax(-1);
Eric Andersenc470f442003-07-28 09:56:35 +000011555 /* NOTREACHED */
Eric Andersencb57d552001-06-28 07:25:16 +000011556 case TIF:
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011557 n1 = stzalloc(sizeof(struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +000011558 n1->type = NIF;
11559 n1->nif.test = list(0);
11560 if (readtoken() != TTHEN)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011561 raise_error_unexpected_syntax(TTHEN);
Eric Andersencb57d552001-06-28 07:25:16 +000011562 n1->nif.ifpart = list(0);
11563 n2 = n1;
11564 while (readtoken() == TELIF) {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011565 n2->nif.elsepart = stzalloc(sizeof(struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +000011566 n2 = n2->nif.elsepart;
11567 n2->type = NIF;
11568 n2->nif.test = list(0);
11569 if (readtoken() != TTHEN)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011570 raise_error_unexpected_syntax(TTHEN);
Eric Andersencb57d552001-06-28 07:25:16 +000011571 n2->nif.ifpart = list(0);
11572 }
11573 if (lasttoken == TELSE)
11574 n2->nif.elsepart = list(0);
11575 else {
11576 n2->nif.elsepart = NULL;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011577 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011578 }
Eric Andersenc470f442003-07-28 09:56:35 +000011579 t = TFI;
Eric Andersencb57d552001-06-28 07:25:16 +000011580 break;
11581 case TWHILE:
Eric Andersenc470f442003-07-28 09:56:35 +000011582 case TUNTIL: {
Eric Andersencb57d552001-06-28 07:25:16 +000011583 int got;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011584 n1 = stzalloc(sizeof(struct nbinary));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011585 n1->type = (lasttoken == TWHILE) ? NWHILE : NUNTIL;
Eric Andersencb57d552001-06-28 07:25:16 +000011586 n1->nbinary.ch1 = list(0);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011587 got = readtoken();
11588 if (got != TDO) {
Denys Vlasenko888527c2016-10-02 16:54:17 +020011589 TRACE(("expecting DO got '%s' %s\n", tokname_array[got],
Denis Vlasenko131ae172007-02-18 13:00:19 +000011590 got == TWORD ? wordtext : ""));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011591 raise_error_unexpected_syntax(TDO);
Eric Andersencb57d552001-06-28 07:25:16 +000011592 }
11593 n1->nbinary.ch2 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +000011594 t = TDONE;
Eric Andersencb57d552001-06-28 07:25:16 +000011595 break;
11596 }
11597 case TFOR:
Denis Vlasenko2dc240c2008-07-24 06:07:50 +000011598 if (readtoken() != TWORD || quoteflag || !goodname(wordtext))
Denis Vlasenko559691a2008-10-05 18:39:31 +000011599 raise_error_syntax("bad for loop variable");
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011600 n1 = stzalloc(sizeof(struct nfor));
Eric Andersencb57d552001-06-28 07:25:16 +000011601 n1->type = NFOR;
11602 n1->nfor.var = wordtext;
Ron Yorstonab80e012015-08-03 13:46:00 +010011603 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000011604 if (readtoken() == TIN) {
11605 app = &ap;
11606 while (readtoken() == TWORD) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011607 n2 = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000011608 n2->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011609 /*n2->narg.next = NULL; - stzalloc did it */
Eric Andersencb57d552001-06-28 07:25:16 +000011610 n2->narg.text = wordtext;
11611 n2->narg.backquote = backquotelist;
11612 *app = n2;
11613 app = &n2->narg.next;
11614 }
11615 *app = NULL;
11616 n1->nfor.args = ap;
11617 if (lasttoken != TNL && lasttoken != TSEMI)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011618 raise_error_unexpected_syntax(-1);
Eric Andersencb57d552001-06-28 07:25:16 +000011619 } else {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011620 n2 = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000011621 n2->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011622 /*n2->narg.next = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011623 n2->narg.text = (char *)dolatstr;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011624 /*n2->narg.backquote = NULL;*/
Eric Andersencb57d552001-06-28 07:25:16 +000011625 n1->nfor.args = n2;
11626 /*
11627 * Newline or semicolon here is optional (but note
11628 * that the original Bourne shell only allowed NL).
11629 */
Ron Yorstonab80e012015-08-03 13:46:00 +010011630 if (lasttoken != TSEMI)
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011631 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011632 }
Eric Andersenc470f442003-07-28 09:56:35 +000011633 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000011634 if (readtoken() != TDO)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011635 raise_error_unexpected_syntax(TDO);
Eric Andersencb57d552001-06-28 07:25:16 +000011636 n1->nfor.body = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +000011637 t = TDONE;
Eric Andersencb57d552001-06-28 07:25:16 +000011638 break;
11639 case TCASE:
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011640 n1 = stzalloc(sizeof(struct ncase));
Eric Andersencb57d552001-06-28 07:25:16 +000011641 n1->type = NCASE;
11642 if (readtoken() != TWORD)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011643 raise_error_unexpected_syntax(TWORD);
Denis Vlasenko597906c2008-02-20 16:38:54 +000011644 n1->ncase.expr = n2 = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000011645 n2->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011646 /*n2->narg.next = NULL; - stzalloc did it */
Eric Andersencb57d552001-06-28 07:25:16 +000011647 n2->narg.text = wordtext;
11648 n2->narg.backquote = backquotelist;
Ron Yorston383b8852015-08-03 13:46:25 +010011649 checkkwd = CHKNL | CHKKWD | CHKALIAS;
11650 if (readtoken() != TIN)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011651 raise_error_unexpected_syntax(TIN);
Eric Andersencb57d552001-06-28 07:25:16 +000011652 cpp = &n1->ncase.cases;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011653 next_case:
Eric Andersenc470f442003-07-28 09:56:35 +000011654 checkkwd = CHKNL | CHKKWD;
11655 t = readtoken();
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011656 while (t != TESAC) {
Eric Andersencb57d552001-06-28 07:25:16 +000011657 if (lasttoken == TLP)
11658 readtoken();
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011659 *cpp = cp = stzalloc(sizeof(struct nclist));
Eric Andersencb57d552001-06-28 07:25:16 +000011660 cp->type = NCLIST;
11661 app = &cp->nclist.pattern;
11662 for (;;) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011663 *app = ap = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000011664 ap->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011665 /*ap->narg.next = NULL; - stzalloc did it */
Eric Andersencb57d552001-06-28 07:25:16 +000011666 ap->narg.text = wordtext;
11667 ap->narg.backquote = backquotelist;
Eric Andersenc470f442003-07-28 09:56:35 +000011668 if (readtoken() != TPIPE)
Eric Andersencb57d552001-06-28 07:25:16 +000011669 break;
11670 app = &ap->narg.next;
11671 readtoken();
11672 }
Denis Vlasenko597906c2008-02-20 16:38:54 +000011673 //ap->narg.next = NULL;
Eric Andersencb57d552001-06-28 07:25:16 +000011674 if (lasttoken != TRP)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011675 raise_error_unexpected_syntax(TRP);
Eric Andersenc470f442003-07-28 09:56:35 +000011676 cp->nclist.body = list(2);
Eric Andersencb57d552001-06-28 07:25:16 +000011677
Eric Andersenc470f442003-07-28 09:56:35 +000011678 cpp = &cp->nclist.next;
11679
11680 checkkwd = CHKNL | CHKKWD;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011681 t = readtoken();
11682 if (t != TESAC) {
Eric Andersencb57d552001-06-28 07:25:16 +000011683 if (t != TENDCASE)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011684 raise_error_unexpected_syntax(TENDCASE);
11685 goto next_case;
Eric Andersencb57d552001-06-28 07:25:16 +000011686 }
Eric Andersenc470f442003-07-28 09:56:35 +000011687 }
Eric Andersencb57d552001-06-28 07:25:16 +000011688 *cpp = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +000011689 goto redir;
Eric Andersencb57d552001-06-28 07:25:16 +000011690 case TLP:
Denis Vlasenko597906c2008-02-20 16:38:54 +000011691 n1 = stzalloc(sizeof(struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +000011692 n1->type = NSUBSHELL;
11693 n1->nredir.n = list(0);
Denis Vlasenko597906c2008-02-20 16:38:54 +000011694 /*n1->nredir.redirect = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011695 t = TRP;
Eric Andersencb57d552001-06-28 07:25:16 +000011696 break;
11697 case TBEGIN:
11698 n1 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +000011699 t = TEND;
Eric Andersencb57d552001-06-28 07:25:16 +000011700 break;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011701 IF_BASH_FUNCTION(case TFUNCTION:)
Eric Andersencb57d552001-06-28 07:25:16 +000011702 case TWORD:
Eric Andersenc470f442003-07-28 09:56:35 +000011703 case TREDIR:
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011704 tokpushback = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000011705 return simplecmd();
Eric Andersencb57d552001-06-28 07:25:16 +000011706 }
11707
Eric Andersenc470f442003-07-28 09:56:35 +000011708 if (readtoken() != t)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011709 raise_error_unexpected_syntax(t);
Eric Andersenc470f442003-07-28 09:56:35 +000011710
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011711 redir:
Eric Andersencb57d552001-06-28 07:25:16 +000011712 /* Now check for redirection which may follow command */
Eric Andersenc470f442003-07-28 09:56:35 +000011713 checkkwd = CHKKWD | CHKALIAS;
11714 rpp = rpp2;
Eric Andersencb57d552001-06-28 07:25:16 +000011715 while (readtoken() == TREDIR) {
11716 *rpp = n2 = redirnode;
11717 rpp = &n2->nfile.next;
11718 parsefname();
11719 }
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011720 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011721 *rpp = NULL;
11722 if (redir) {
11723 if (n1->type != NSUBSHELL) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011724 n2 = stzalloc(sizeof(struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +000011725 n2->type = NREDIR;
11726 n2->nredir.n = n1;
11727 n1 = n2;
11728 }
11729 n1->nredir.redirect = redir;
11730 }
Eric Andersencb57d552001-06-28 07:25:16 +000011731 return n1;
11732}
11733
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011734#if BASH_DOLLAR_SQUOTE
Denys Vlasenko37dc08b2016-10-02 04:38:07 +020011735static int
11736decode_dollar_squote(void)
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011737{
11738 static const char C_escapes[] ALIGN1 = "nrbtfav""x\\01234567";
11739 int c, cnt;
11740 char *p;
11741 char buf[4];
11742
11743 c = pgetc();
11744 p = strchr(C_escapes, c);
11745 if (p) {
11746 buf[0] = c;
11747 p = buf;
11748 cnt = 3;
11749 if ((unsigned char)(c - '0') <= 7) { /* \ooo */
11750 do {
11751 c = pgetc();
11752 *++p = c;
11753 } while ((unsigned char)(c - '0') <= 7 && --cnt);
11754 pungetc();
11755 } else if (c == 'x') { /* \xHH */
11756 do {
11757 c = pgetc();
11758 *++p = c;
11759 } while (isxdigit(c) && --cnt);
11760 pungetc();
11761 if (cnt == 3) { /* \x but next char is "bad" */
11762 c = 'x';
11763 goto unrecognized;
11764 }
11765 } else { /* simple seq like \\ or \t */
11766 p++;
11767 }
11768 *p = '\0';
11769 p = buf;
11770 c = bb_process_escape_sequence((void*)&p);
11771 } else { /* unrecognized "\z": print both chars unless ' or " */
11772 if (c != '\'' && c != '"') {
11773 unrecognized:
11774 c |= 0x100; /* "please encode \, then me" */
11775 }
11776 }
11777 return c;
11778}
11779#endif
11780
Denys Vlasenko46999802017-07-29 21:12:29 +020011781/* Used by expandstr to get here-doc like behaviour. */
11782#define FAKEEOFMARK ((char*)(uintptr_t)1)
11783
11784static ALWAYS_INLINE int
11785realeofmark(const char *eofmark)
11786{
11787 return eofmark && eofmark != FAKEEOFMARK;
11788}
11789
Eric Andersencb57d552001-06-28 07:25:16 +000011790/*
11791 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
11792 * is not NULL, read a here document. In the latter case, eofmark is the
11793 * word which marks the end of the document and striptabs is true if
Denys Vlasenkocd716832009-11-28 22:14:02 +010011794 * leading tabs should be stripped from the document. The argument c
Eric Andersencb57d552001-06-28 07:25:16 +000011795 * is the first character of the input token or document.
11796 *
11797 * Because C does not have internal subroutines, I have simulated them
11798 * using goto's to implement the subroutine linkage. The following macros
11799 * will run code that appears at the end of readtoken1.
11800 */
Eric Andersen2870d962001-07-02 17:27:21 +000011801#define CHECKEND() {goto checkend; checkend_return:;}
11802#define PARSEREDIR() {goto parseredir; parseredir_return:;}
11803#define PARSESUB() {goto parsesub; parsesub_return:;}
11804#define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
11805#define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
11806#define PARSEARITH() {goto parsearith; parsearith_return:;}
Eric Andersencb57d552001-06-28 07:25:16 +000011807static int
Denys Vlasenkocd716832009-11-28 22:14:02 +010011808readtoken1(int c, int syntax, char *eofmark, int striptabs)
Manuel Novoa III 16815d42001-08-10 19:36:07 +000011809{
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011810 /* NB: syntax parameter fits into smallint */
Denys Vlasenkocd716832009-11-28 22:14:02 +010011811 /* c parameter is an unsigned char or PEOF or PEOA */
Eric Andersencb57d552001-06-28 07:25:16 +000011812 char *out;
Denys Vlasenko50e6d422016-09-30 11:35:54 +020011813 size_t len;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011814 struct nodelist *bqlist;
11815 smallint quotef;
11816 smallint dblquote;
11817 smallint oldstyle;
Denys Vlasenko0b883582016-12-23 16:49:07 +010011818 IF_FEATURE_SH_MATH(smallint prevsyntax;) /* syntax before arithmetic */
Denis Vlasenko46a53062007-09-24 18:30:02 +000011819 smallint pssyntax; /* we are expanding a prompt string */
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011820 int varnest; /* levels of variables expansion */
Denys Vlasenko0b883582016-12-23 16:49:07 +010011821 IF_FEATURE_SH_MATH(int arinest;) /* levels of arithmetic expansion */
11822 IF_FEATURE_SH_MATH(int parenlevel;) /* levels of parens in arithmetic */
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011823 int dqvarnest; /* levels of variables expansion within double quotes */
11824
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011825 IF_BASH_DOLLAR_SQUOTE(smallint bash_dollar_squote = 0;)
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011826
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011827 startlinno = g_parsefile->linno;
Eric Andersencb57d552001-06-28 07:25:16 +000011828 bqlist = NULL;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011829 quotef = 0;
Denys Vlasenko0b883582016-12-23 16:49:07 +010011830 IF_FEATURE_SH_MATH(prevsyntax = 0;)
Denys Vlasenko5f0a75f2017-07-29 22:58:44 +020011831#if ENABLE_ASH_EXPAND_PRMT
Denis Vlasenko46a53062007-09-24 18:30:02 +000011832 pssyntax = (syntax == PSSYNTAX);
11833 if (pssyntax)
11834 syntax = DQSYNTAX;
Denys Vlasenko5f0a75f2017-07-29 22:58:44 +020011835#else
11836 pssyntax = 0; /* constant */
11837#endif
Denis Vlasenko46a53062007-09-24 18:30:02 +000011838 dblquote = (syntax == DQSYNTAX);
Eric Andersencb57d552001-06-28 07:25:16 +000011839 varnest = 0;
Denys Vlasenko0b883582016-12-23 16:49:07 +010011840 IF_FEATURE_SH_MATH(arinest = 0;)
11841 IF_FEATURE_SH_MATH(parenlevel = 0;)
Eric Andersencb57d552001-06-28 07:25:16 +000011842 dqvarnest = 0;
11843
11844 STARTSTACKSTR(out);
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011845 loop:
11846 /* For each line, until end of word */
Denys Vlasenko958581a2010-09-12 15:04:27 +020011847 CHECKEND(); /* set c to PEOF if at end of here document */
11848 for (;;) { /* until end of line or end of word */
11849 CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */
11850 switch (SIT(c, syntax)) {
11851 case CNL: /* '\n' */
11852 if (syntax == BASESYNTAX)
11853 goto endword; /* exit outer loop */
11854 USTPUTC(c, out);
Denys Vlasenkoce332a22016-10-02 23:47:34 +020011855 nlprompt();
Denys Vlasenko958581a2010-09-12 15:04:27 +020011856 c = pgetc();
11857 goto loop; /* continue outer loop */
11858 case CWORD:
11859 USTPUTC(c, out);
11860 break;
11861 case CCTL:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011862#if BASH_DOLLAR_SQUOTE
Denys Vlasenko958581a2010-09-12 15:04:27 +020011863 if (c == '\\' && bash_dollar_squote) {
11864 c = decode_dollar_squote();
Denys Vlasenko13f20912016-09-25 20:54:25 +020011865 if (c == '\0') {
11866 /* skip $'\000', $'\x00' (like bash) */
11867 break;
11868 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020011869 if (c & 0x100) {
Denys Vlasenko13f20912016-09-25 20:54:25 +020011870 /* Unknown escape. Encode as '\z' */
Denys Vlasenko958581a2010-09-12 15:04:27 +020011871 c = (unsigned char)c;
Denys Vlasenko13f20912016-09-25 20:54:25 +020011872 if (eofmark == NULL || dblquote)
11873 USTPUTC(CTLESC, out);
11874 USTPUTC('\\', out);
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011875 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020011876 }
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011877#endif
Denys Vlasenko13f20912016-09-25 20:54:25 +020011878 if (eofmark == NULL || dblquote)
11879 USTPUTC(CTLESC, out);
Denys Vlasenko958581a2010-09-12 15:04:27 +020011880 USTPUTC(c, out);
11881 break;
11882 case CBACK: /* backslash */
11883 c = pgetc_without_PEOA();
11884 if (c == PEOF) {
11885 USTPUTC(CTLESC, out);
11886 USTPUTC('\\', out);
11887 pungetc();
11888 } else if (c == '\n') {
Denys Vlasenkoce332a22016-10-02 23:47:34 +020011889 nlprompt();
Denys Vlasenko958581a2010-09-12 15:04:27 +020011890 } else {
Denys Vlasenko5f0a75f2017-07-29 22:58:44 +020011891 if (pssyntax && c == '$') {
Eric Andersenc470f442003-07-28 09:56:35 +000011892 USTPUTC(CTLESC, out);
Eric Andersencb57d552001-06-28 07:25:16 +000011893 USTPUTC('\\', out);
Denys Vlasenko958581a2010-09-12 15:04:27 +020011894 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020011895 /* Backslash is retained if we are in "str" and next char isn't special */
11896 if (dblquote
11897 && c != '\\'
11898 && c != '`'
11899 && c != '$'
11900 && (c != '"' || eofmark != NULL)
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011901 ) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020011902 USTPUTC('\\', out);
Eric Andersencb57d552001-06-28 07:25:16 +000011903 }
Ron Yorston549deab2015-05-18 09:57:51 +020011904 USTPUTC(CTLESC, out);
Denys Vlasenko0ff78a02010-08-30 15:20:07 +020011905 USTPUTC(c, out);
Denys Vlasenko958581a2010-09-12 15:04:27 +020011906 quotef = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011907 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020011908 break;
11909 case CSQUOTE:
11910 syntax = SQSYNTAX;
11911 quotemark:
11912 if (eofmark == NULL) {
11913 USTPUTC(CTLQUOTEMARK, out);
11914 }
11915 break;
11916 case CDQUOTE:
11917 syntax = DQSYNTAX;
11918 dblquote = 1;
11919 goto quotemark;
11920 case CENDQUOTE:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011921 IF_BASH_DOLLAR_SQUOTE(bash_dollar_squote = 0;)
Ron Yorston7e4ed262015-05-18 09:54:43 +020011922 if (eofmark != NULL && varnest == 0) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020011923 USTPUTC(c, out);
11924 } else {
11925 if (dqvarnest == 0) {
11926 syntax = BASESYNTAX;
11927 dblquote = 0;
11928 }
11929 quotef = 1;
11930 goto quotemark;
11931 }
11932 break;
11933 case CVAR: /* '$' */
11934 PARSESUB(); /* parse substitution */
11935 break;
11936 case CENDVAR: /* '}' */
11937 if (varnest > 0) {
11938 varnest--;
11939 if (dqvarnest > 0) {
11940 dqvarnest--;
11941 }
11942 c = CTLENDVAR;
11943 }
11944 USTPUTC(c, out);
11945 break;
Denys Vlasenko0b883582016-12-23 16:49:07 +010011946#if ENABLE_FEATURE_SH_MATH
Denys Vlasenko958581a2010-09-12 15:04:27 +020011947 case CLP: /* '(' in arithmetic */
11948 parenlevel++;
11949 USTPUTC(c, out);
11950 break;
11951 case CRP: /* ')' in arithmetic */
11952 if (parenlevel > 0) {
11953 parenlevel--;
11954 } else {
Denys Vlasenko459293b2016-09-29 17:58:58 +020011955 if (pgetc_eatbnl() == ')') {
Ron Yorstonad88bde2015-05-18 09:56:16 +020011956 c = CTLENDARI;
Denys Vlasenko958581a2010-09-12 15:04:27 +020011957 if (--arinest == 0) {
11958 syntax = prevsyntax;
Denys Vlasenko958581a2010-09-12 15:04:27 +020011959 }
11960 } else {
11961 /*
11962 * unbalanced parens
11963 * (don't 2nd guess - no error)
11964 */
11965 pungetc();
11966 }
11967 }
11968 USTPUTC(c, out);
11969 break;
11970#endif
11971 case CBQUOTE: /* '`' */
11972 PARSEBACKQOLD();
11973 break;
11974 case CENDFILE:
11975 goto endword; /* exit outer loop */
11976 case CIGN:
11977 break;
11978 default:
11979 if (varnest == 0) {
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011980#if BASH_REDIR_OUTPUT
Denys Vlasenko958581a2010-09-12 15:04:27 +020011981 if (c == '&') {
Denys Vlasenko459293b2016-09-29 17:58:58 +020011982//Can't call pgetc_eatbnl() here, this requires three-deep pungetc()
Denys Vlasenko958581a2010-09-12 15:04:27 +020011983 if (pgetc() == '>')
11984 c = 0x100 + '>'; /* flag &> */
11985 pungetc();
11986 }
11987#endif
11988 goto endword; /* exit outer loop */
11989 }
11990 IF_ASH_ALIAS(if (c != PEOA))
11991 USTPUTC(c, out);
11992 }
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020011993 c = pgetc();
Denys Vlasenko958581a2010-09-12 15:04:27 +020011994 } /* for (;;) */
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011995 endword:
Denys Vlasenko958581a2010-09-12 15:04:27 +020011996
Denys Vlasenko0b883582016-12-23 16:49:07 +010011997#if ENABLE_FEATURE_SH_MATH
Eric Andersencb57d552001-06-28 07:25:16 +000011998 if (syntax == ARISYNTAX)
Denis Vlasenko559691a2008-10-05 18:39:31 +000011999 raise_error_syntax("missing '))'");
Eric Andersenc470f442003-07-28 09:56:35 +000012000#endif
Ron Yorston0e056f72015-07-01 16:45:40 +010012001 if (syntax != BASESYNTAX && eofmark == NULL)
Denis Vlasenko559691a2008-10-05 18:39:31 +000012002 raise_error_syntax("unterminated quoted string");
Eric Andersencb57d552001-06-28 07:25:16 +000012003 if (varnest != 0) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000012004 startlinno = g_parsefile->linno;
Eric Andersenc470f442003-07-28 09:56:35 +000012005 /* { */
Denis Vlasenko559691a2008-10-05 18:39:31 +000012006 raise_error_syntax("missing '}'");
Eric Andersencb57d552001-06-28 07:25:16 +000012007 }
12008 USTPUTC('\0', out);
Eric Andersenc470f442003-07-28 09:56:35 +000012009 len = out - (char *)stackblock();
Eric Andersencb57d552001-06-28 07:25:16 +000012010 out = stackblock();
12011 if (eofmark == NULL) {
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010012012 if ((c == '>' || c == '<' IF_BASH_REDIR_OUTPUT( || c == 0x100 + '>'))
Denis Vlasenko834dee72008-10-07 09:18:30 +000012013 && quotef == 0
12014 ) {
Denis Vlasenko559691a2008-10-05 18:39:31 +000012015 if (isdigit_str9(out)) {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000012016 PARSEREDIR(); /* passed as params: out, c */
12017 lasttoken = TREDIR;
12018 return lasttoken;
12019 }
12020 /* else: non-number X seen, interpret it
12021 * as "NNNX>file" = "NNNX >file" */
Eric Andersencb57d552001-06-28 07:25:16 +000012022 }
Denis Vlasenkoef527f52008-06-23 01:52:30 +000012023 pungetc();
Eric Andersencb57d552001-06-28 07:25:16 +000012024 }
12025 quoteflag = quotef;
12026 backquotelist = bqlist;
12027 grabstackblock(len);
12028 wordtext = out;
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000012029 lasttoken = TWORD;
12030 return lasttoken;
Eric Andersencb57d552001-06-28 07:25:16 +000012031/* end of readtoken routine */
12032
Eric Andersencb57d552001-06-28 07:25:16 +000012033/*
12034 * Check to see whether we are at the end of the here document. When this
12035 * is called, c is set to the first character of the next input line. If
12036 * we are at the end of the here document, this routine sets the c to PEOF.
12037 */
Eric Andersenc470f442003-07-28 09:56:35 +000012038checkend: {
Denys Vlasenko46999802017-07-29 21:12:29 +020012039 if (realeofmark(eofmark)) {
Denys Vlasenkoa7328982017-07-29 19:57:28 +020012040 int markloc;
12041 char *p;
12042
Denis Vlasenko131ae172007-02-18 13:00:19 +000012043#if ENABLE_ASH_ALIAS
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010012044 if (c == PEOA)
12045 c = pgetc_without_PEOA();
Eric Andersenc470f442003-07-28 09:56:35 +000012046#endif
12047 if (striptabs) {
12048 while (c == '\t') {
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010012049 c = pgetc_without_PEOA();
Eric Andersencb57d552001-06-28 07:25:16 +000012050 }
Eric Andersenc470f442003-07-28 09:56:35 +000012051 }
Eric Andersencb57d552001-06-28 07:25:16 +000012052
Denys Vlasenkoa7328982017-07-29 19:57:28 +020012053 markloc = out - (char *)stackblock();
12054 for (p = eofmark; STPUTC(c, out), *p; p++) {
12055 if (c != *p)
12056 goto more_heredoc;
12057
12058 c = pgetc_without_PEOA();
12059 }
12060
12061 if (c == '\n' || c == PEOF) {
12062 c = PEOF;
12063 g_parsefile->linno++;
12064 needprompt = doprompt;
12065 } else {
12066 int len_here;
12067
12068 more_heredoc:
12069 p = (char *)stackblock() + markloc + 1;
12070 len_here = out - p;
12071
12072 if (len_here) {
12073 len_here -= (c >= PEOF);
12074 c = p[-1];
12075
12076 if (len_here) {
12077 char *str;
12078
12079 str = alloca(len_here + 1);
12080 *(char *)mempcpy(str, p, len_here) = '\0';
12081
12082 pushstring(str, NULL);
Eric Andersencb57d552001-06-28 07:25:16 +000012083 }
12084 }
12085 }
Denys Vlasenkoa7328982017-07-29 19:57:28 +020012086
12087 STADJUST((char *)stackblock() + markloc - out, out);
Eric Andersencb57d552001-06-28 07:25:16 +000012088 }
Eric Andersenc470f442003-07-28 09:56:35 +000012089 goto checkend_return;
12090}
Eric Andersencb57d552001-06-28 07:25:16 +000012091
Eric Andersencb57d552001-06-28 07:25:16 +000012092/*
12093 * Parse a redirection operator. The variable "out" points to a string
12094 * specifying the fd to be redirected. The variable "c" contains the
12095 * first character of the redirection operator.
12096 */
Eric Andersenc470f442003-07-28 09:56:35 +000012097parseredir: {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000012098 /* out is already checked to be a valid number or "" */
12099 int fd = (*out == '\0' ? -1 : atoi(out));
Eric Andersenc470f442003-07-28 09:56:35 +000012100 union node *np;
Eric Andersencb57d552001-06-28 07:25:16 +000012101
Denis Vlasenko597906c2008-02-20 16:38:54 +000012102 np = stzalloc(sizeof(struct nfile));
Eric Andersenc470f442003-07-28 09:56:35 +000012103 if (c == '>') {
12104 np->nfile.fd = 1;
12105 c = pgetc();
12106 if (c == '>')
12107 np->type = NAPPEND;
12108 else if (c == '|')
12109 np->type = NCLOBBER;
12110 else if (c == '&')
12111 np->type = NTOFD;
Denis Vlasenko559691a2008-10-05 18:39:31 +000012112 /* it also can be NTO2 (>&file), but we can't figure it out yet */
Eric Andersenc470f442003-07-28 09:56:35 +000012113 else {
12114 np->type = NTO;
12115 pungetc();
Eric Andersencb57d552001-06-28 07:25:16 +000012116 }
Denis Vlasenko834dee72008-10-07 09:18:30 +000012117 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010012118#if BASH_REDIR_OUTPUT
Denis Vlasenko834dee72008-10-07 09:18:30 +000012119 else if (c == 0x100 + '>') { /* this flags &> redirection */
12120 np->nfile.fd = 1;
12121 pgetc(); /* this is '>', no need to check */
12122 np->type = NTO2;
12123 }
12124#endif
12125 else { /* c == '<' */
Denis Vlasenko597906c2008-02-20 16:38:54 +000012126 /*np->nfile.fd = 0; - stzalloc did it */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000012127 c = pgetc();
12128 switch (c) {
Eric Andersenc470f442003-07-28 09:56:35 +000012129 case '<':
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000012130 if (sizeof(struct nfile) != sizeof(struct nhere)) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000012131 np = stzalloc(sizeof(struct nhere));
12132 /*np->nfile.fd = 0; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000012133 }
12134 np->type = NHERE;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000012135 heredoc = stzalloc(sizeof(struct heredoc));
Eric Andersenc470f442003-07-28 09:56:35 +000012136 heredoc->here = np;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000012137 c = pgetc();
12138 if (c == '-') {
Eric Andersenc470f442003-07-28 09:56:35 +000012139 heredoc->striptabs = 1;
12140 } else {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000012141 /*heredoc->striptabs = 0; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000012142 pungetc();
12143 }
12144 break;
12145
12146 case '&':
12147 np->type = NFROMFD;
12148 break;
12149
12150 case '>':
12151 np->type = NFROMTO;
12152 break;
12153
12154 default:
12155 np->type = NFROM;
12156 pungetc();
12157 break;
12158 }
Eric Andersencb57d552001-06-28 07:25:16 +000012159 }
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000012160 if (fd >= 0)
12161 np->nfile.fd = fd;
Eric Andersenc470f442003-07-28 09:56:35 +000012162 redirnode = np;
12163 goto parseredir_return;
12164}
Eric Andersencb57d552001-06-28 07:25:16 +000012165
Eric Andersencb57d552001-06-28 07:25:16 +000012166/*
12167 * Parse a substitution. At this point, we have read the dollar sign
12168 * and nothing else.
12169 */
Denis Vlasenkocc571512007-02-23 21:10:35 +000012170
12171/* is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise
12172 * (assuming ascii char codes, as the original implementation did) */
12173#define is_special(c) \
Denis Vlasenkoef527f52008-06-23 01:52:30 +000012174 (((unsigned)(c) - 33 < 32) \
12175 && ((0xc1ff920dU >> ((unsigned)(c) - 33)) & 1))
Eric Andersenc470f442003-07-28 09:56:35 +000012176parsesub: {
Denys Vlasenkocd716832009-11-28 22:14:02 +010012177 unsigned char subtype;
Eric Andersenc470f442003-07-28 09:56:35 +000012178 int typeloc;
Eric Andersencb57d552001-06-28 07:25:16 +000012179
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012180 c = pgetc_eatbnl();
Denys Vlasenkoa7328982017-07-29 19:57:28 +020012181 if ((checkkwd & CHKEOFMARK)
12182 || c > 255 /* PEOA or PEOF */
Denis Vlasenkoef527f52008-06-23 01:52:30 +000012183 || (c != '(' && c != '{' && !is_name(c) && !is_special(c))
Eric Andersenc470f442003-07-28 09:56:35 +000012184 ) {
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010012185#if BASH_DOLLAR_SQUOTE
Ron Yorston84ba50c2016-04-03 22:43:14 +010012186 if (syntax != DQSYNTAX && c == '\'')
Denis Vlasenkoef527f52008-06-23 01:52:30 +000012187 bash_dollar_squote = 1;
12188 else
12189#endif
12190 USTPUTC('$', out);
Eric Andersenc470f442003-07-28 09:56:35 +000012191 pungetc();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012192 } else if (c == '(') {
12193 /* $(command) or $((arith)) */
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012194 if (pgetc_eatbnl() == '(') {
Denys Vlasenko0b883582016-12-23 16:49:07 +010012195#if ENABLE_FEATURE_SH_MATH
Eric Andersenc470f442003-07-28 09:56:35 +000012196 PARSEARITH();
12197#else
Denys Vlasenko4f8079d2017-07-17 17:11:48 +020012198 raise_error_syntax("support for $((arith)) is disabled");
Eric Andersenc470f442003-07-28 09:56:35 +000012199#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012200 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000012201 pungetc();
12202 PARSEBACKQNEW();
12203 }
12204 } else {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012205 /* $VAR, $<specialchar>, ${...}, or PEOA/PEOF */
Eric Andersenc470f442003-07-28 09:56:35 +000012206 USTPUTC(CTLVAR, out);
12207 typeloc = out - (char *)stackblock();
Denys Vlasenko3df14102016-10-26 16:41:13 +020012208 STADJUST(1, out);
Eric Andersenc470f442003-07-28 09:56:35 +000012209 subtype = VSNORMAL;
12210 if (c == '{') {
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012211 c = pgetc_eatbnl();
Denys Vlasenkof15aa572016-10-26 15:56:53 +020012212 subtype = 0;
Eric Andersenc470f442003-07-28 09:56:35 +000012213 }
Denys Vlasenkof15aa572016-10-26 15:56:53 +020012214 varname:
Denys Vlasenko3df14102016-10-26 16:41:13 +020012215 if (is_name(c)) {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012216 /* $[{[#]]NAME[}] */
Eric Andersenc470f442003-07-28 09:56:35 +000012217 do {
12218 STPUTC(c, out);
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012219 c = pgetc_eatbnl();
Denys Vlasenko3df14102016-10-26 16:41:13 +020012220 } while (is_in_name(c));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012221 } else if (isdigit(c)) {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012222 /* $[{[#]]NUM[}] */
Eric Andersenc470f442003-07-28 09:56:35 +000012223 do {
12224 STPUTC(c, out);
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012225 c = pgetc_eatbnl();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012226 } while (isdigit(c));
Denys Vlasenko452cc1d2017-08-14 14:23:45 +020012227 } else {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012228 /* $[{[#]]<specialchar>[}] */
Denys Vlasenkof15aa572016-10-26 15:56:53 +020012229 int cc = c;
12230
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012231 c = pgetc_eatbnl();
Denys Vlasenkof15aa572016-10-26 15:56:53 +020012232 if (!subtype && cc == '#') {
12233 subtype = VSLENGTH;
12234 if (c == '_' || isalnum(c))
12235 goto varname;
12236 cc = c;
12237 c = pgetc_eatbnl();
12238 if (cc == '}' || c != '}') {
12239 pungetc();
12240 subtype = 0;
12241 c = cc;
12242 cc = '#';
12243 }
12244 }
Denys Vlasenko452cc1d2017-08-14 14:23:45 +020012245
12246 if (!is_special(cc)) {
12247 if (subtype == VSLENGTH)
12248 subtype = 0;
12249 goto badsub;
12250 }
12251
Denys Vlasenkof15aa572016-10-26 15:56:53 +020012252 USTPUTC(cc, out);
Denis Vlasenko559691a2008-10-05 18:39:31 +000012253 }
Denys Vlasenko452cc1d2017-08-14 14:23:45 +020012254
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012255 if (c != '}' && subtype == VSLENGTH) {
12256 /* ${#VAR didn't end with } */
Cristian Ionescu-Idbohrn301f5ec2009-10-05 02:07:23 +020012257 goto badsub;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012258 }
Eric Andersencb57d552001-06-28 07:25:16 +000012259
Eric Andersenc470f442003-07-28 09:56:35 +000012260 if (subtype == 0) {
Denys Vlasenkof8ddbe12016-07-25 03:56:00 +020012261 static const char types[] ALIGN1 = "}-+?=";
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012262 /* ${VAR...} but not $VAR or ${#VAR} */
12263 /* c == first char after VAR */
Eric Andersenc470f442003-07-28 09:56:35 +000012264 switch (c) {
12265 case ':':
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012266 c = pgetc_eatbnl();
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010012267#if BASH_SUBSTR
Denys Vlasenkof8ddbe12016-07-25 03:56:00 +020012268 /* This check is only needed to not misinterpret
12269 * ${VAR:-WORD}, ${VAR:+WORD}, ${VAR:=WORD}, ${VAR:?WORD}
12270 * constructs.
12271 */
12272 if (!strchr(types, c)) {
Denis Vlasenko92e13c22008-03-25 01:17:40 +000012273 subtype = VSSUBSTR;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012274 pungetc();
Denys Vlasenko88e15702016-10-26 01:55:56 +020012275 break; /* "goto badsub" is bigger (!) */
Denis Vlasenko92e13c22008-03-25 01:17:40 +000012276 }
12277#endif
Denys Vlasenko3df14102016-10-26 16:41:13 +020012278 subtype = VSNUL;
Eric Andersenc470f442003-07-28 09:56:35 +000012279 /*FALLTHROUGH*/
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012280 default: {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012281 const char *p = strchr(types, c);
Eric Andersenc470f442003-07-28 09:56:35 +000012282 if (p == NULL)
Denys Vlasenko88e15702016-10-26 01:55:56 +020012283 break;
Denys Vlasenko3df14102016-10-26 16:41:13 +020012284 subtype |= p - types + VSNORMAL;
Eric Andersenc470f442003-07-28 09:56:35 +000012285 break;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012286 }
Eric Andersenc470f442003-07-28 09:56:35 +000012287 case '%':
Denis Vlasenko92e13c22008-03-25 01:17:40 +000012288 case '#': {
12289 int cc = c;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012290 subtype = (c == '#' ? VSTRIMLEFT : VSTRIMRIGHT);
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012291 c = pgetc_eatbnl();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012292 if (c != cc)
Denys Vlasenko88e15702016-10-26 01:55:56 +020012293 goto badsub;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012294 subtype++;
Denis Vlasenko92e13c22008-03-25 01:17:40 +000012295 break;
12296 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010012297#if BASH_PATTERN_SUBST
Denis Vlasenko92e13c22008-03-25 01:17:40 +000012298 case '/':
Denys Vlasenko6040fe82010-09-12 15:03:16 +020012299 /* ${v/[/]pattern/repl} */
12300//TODO: encode pattern and repl separately.
12301// Currently ${v/$var_with_slash/repl} is horribly broken
Denis Vlasenko92e13c22008-03-25 01:17:40 +000012302 subtype = VSREPLACE;
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012303 c = pgetc_eatbnl();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012304 if (c != '/')
Denys Vlasenko88e15702016-10-26 01:55:56 +020012305 goto badsub;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012306 subtype++; /* VSREPLACEALL */
Denis Vlasenko92e13c22008-03-25 01:17:40 +000012307 break;
12308#endif
Eric Andersencb57d552001-06-28 07:25:16 +000012309 }
Eric Andersenc470f442003-07-28 09:56:35 +000012310 } else {
Denys Vlasenko88e15702016-10-26 01:55:56 +020012311 badsub:
Eric Andersenc470f442003-07-28 09:56:35 +000012312 pungetc();
12313 }
Denys Vlasenko3df14102016-10-26 16:41:13 +020012314 ((unsigned char *)stackblock())[typeloc] = subtype;
Eric Andersenc470f442003-07-28 09:56:35 +000012315 if (subtype != VSNORMAL) {
12316 varnest++;
Denys Vlasenko3df14102016-10-26 16:41:13 +020012317 if (dblquote)
Eric Andersenc470f442003-07-28 09:56:35 +000012318 dqvarnest++;
Eric Andersencb57d552001-06-28 07:25:16 +000012319 }
Denys Vlasenko88e15702016-10-26 01:55:56 +020012320 STPUTC('=', out);
Eric Andersencb57d552001-06-28 07:25:16 +000012321 }
Eric Andersenc470f442003-07-28 09:56:35 +000012322 goto parsesub_return;
12323}
Eric Andersencb57d552001-06-28 07:25:16 +000012324
Eric Andersencb57d552001-06-28 07:25:16 +000012325/*
12326 * Called to parse command substitutions. Newstyle is set if the command
12327 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
12328 * list of commands (passed by reference), and savelen is the number of
12329 * characters on the top of the stack which must be preserved.
12330 */
Eric Andersenc470f442003-07-28 09:56:35 +000012331parsebackq: {
12332 struct nodelist **nlpp;
Eric Andersenc470f442003-07-28 09:56:35 +000012333 union node *n;
Ron Yorston072fc602015-07-01 16:46:18 +010012334 char *str;
Eric Andersenc470f442003-07-28 09:56:35 +000012335 size_t savelen;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000012336 smallint saveprompt = 0;
12337
Eric Andersenc470f442003-07-28 09:56:35 +000012338 str = NULL;
12339 savelen = out - (char *)stackblock();
12340 if (savelen > 0) {
Denys Vlasenko7bc3d392016-09-17 20:53:47 +020012341 /*
12342 * FIXME: this can allocate very large block on stack and SEGV.
12343 * Example:
12344 * echo "..<100kbytes>..`true` $(true) `true` ..."
Denys Vlasenko73737592016-09-17 20:58:22 +020012345 * allocates 100kb for every command subst. With about
Denys Vlasenko7bc3d392016-09-17 20:53:47 +020012346 * a hundred command substitutions stack overflows.
12347 * With larger prepended string, SEGV happens sooner.
12348 */
Ron Yorston072fc602015-07-01 16:46:18 +010012349 str = alloca(savelen);
Eric Andersenc470f442003-07-28 09:56:35 +000012350 memcpy(str, stackblock(), savelen);
12351 }
Denys Vlasenko7bc3d392016-09-17 20:53:47 +020012352
Eric Andersenc470f442003-07-28 09:56:35 +000012353 if (oldstyle) {
12354 /* We must read until the closing backquote, giving special
Denys Vlasenko60cb48c2013-01-14 15:57:44 +010012355 * treatment to some slashes, and then push the string and
12356 * reread it as input, interpreting it normally.
12357 */
Eric Andersenc470f442003-07-28 09:56:35 +000012358 char *pout;
Eric Andersenc470f442003-07-28 09:56:35 +000012359 size_t psavelen;
12360 char *pstr;
12361
Eric Andersenc470f442003-07-28 09:56:35 +000012362 STARTSTACKSTR(pout);
12363 for (;;) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020012364 int pc;
12365
12366 setprompt_if(needprompt, 2);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000012367 pc = pgetc();
12368 switch (pc) {
Eric Andersenc470f442003-07-28 09:56:35 +000012369 case '`':
12370 goto done;
12371
12372 case '\\':
Denis Vlasenko5cedb752007-02-18 19:56:41 +000012373 pc = pgetc();
12374 if (pc == '\n') {
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012375 nlprompt();
Eric Andersenc470f442003-07-28 09:56:35 +000012376 /*
12377 * If eating a newline, avoid putting
12378 * the newline into the new character
12379 * stream (via the STPUTC after the
12380 * switch).
12381 */
12382 continue;
12383 }
12384 if (pc != '\\' && pc != '`' && pc != '$'
Denys Vlasenko76bc2d62009-11-29 01:37:46 +010012385 && (!dblquote || pc != '"')
12386 ) {
Eric Andersenc470f442003-07-28 09:56:35 +000012387 STPUTC('\\', pout);
Denys Vlasenko76bc2d62009-11-29 01:37:46 +010012388 }
Denys Vlasenkocd716832009-11-28 22:14:02 +010012389 if (pc <= 255 /* not PEOA or PEOF */) {
Eric Andersenc470f442003-07-28 09:56:35 +000012390 break;
12391 }
12392 /* fall through */
12393
12394 case PEOF:
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010012395 IF_ASH_ALIAS(case PEOA:)
Denis Vlasenko41eb3002008-11-28 03:42:31 +000012396 startlinno = g_parsefile->linno;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000012397 raise_error_syntax("EOF in backquote substitution");
Eric Andersenc470f442003-07-28 09:56:35 +000012398
12399 case '\n':
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012400 nlnoprompt();
Eric Andersenc470f442003-07-28 09:56:35 +000012401 break;
12402
12403 default:
12404 break;
12405 }
12406 STPUTC(pc, pout);
12407 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +000012408 done:
Eric Andersenc470f442003-07-28 09:56:35 +000012409 STPUTC('\0', pout);
12410 psavelen = pout - (char *)stackblock();
12411 if (psavelen > 0) {
12412 pstr = grabstackstr(pout);
12413 setinputstring(pstr);
12414 }
12415 }
12416 nlpp = &bqlist;
12417 while (*nlpp)
12418 nlpp = &(*nlpp)->next;
Denis Vlasenko597906c2008-02-20 16:38:54 +000012419 *nlpp = stzalloc(sizeof(**nlpp));
12420 /* (*nlpp)->next = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000012421
12422 if (oldstyle) {
12423 saveprompt = doprompt;
12424 doprompt = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000012425 }
12426
Eric Andersenc470f442003-07-28 09:56:35 +000012427 n = list(2);
12428
12429 if (oldstyle)
12430 doprompt = saveprompt;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012431 else if (readtoken() != TRP)
12432 raise_error_unexpected_syntax(TRP);
Eric Andersenc470f442003-07-28 09:56:35 +000012433
12434 (*nlpp)->n = n;
12435 if (oldstyle) {
12436 /*
12437 * Start reading from old file again, ignoring any pushed back
12438 * tokens left from the backquote parsing
12439 */
12440 popfile();
12441 tokpushback = 0;
12442 }
12443 while (stackblocksize() <= savelen)
12444 growstackblock();
12445 STARTSTACKSTR(out);
12446 if (str) {
12447 memcpy(out, str, savelen);
12448 STADJUST(savelen, out);
Eric Andersenc470f442003-07-28 09:56:35 +000012449 }
Ron Yorston549deab2015-05-18 09:57:51 +020012450 USTPUTC(CTLBACKQ, out);
Eric Andersenc470f442003-07-28 09:56:35 +000012451 if (oldstyle)
12452 goto parsebackq_oldreturn;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000012453 goto parsebackq_newreturn;
Eric Andersenc470f442003-07-28 09:56:35 +000012454}
12455
Denys Vlasenko0b883582016-12-23 16:49:07 +010012456#if ENABLE_FEATURE_SH_MATH
Eric Andersencb57d552001-06-28 07:25:16 +000012457/*
12458 * Parse an arithmetic expansion (indicate start of one and set state)
12459 */
Eric Andersenc470f442003-07-28 09:56:35 +000012460parsearith: {
Eric Andersenc470f442003-07-28 09:56:35 +000012461 if (++arinest == 1) {
12462 prevsyntax = syntax;
12463 syntax = ARISYNTAX;
Eric Andersencb57d552001-06-28 07:25:16 +000012464 }
Ron Yorstonad88bde2015-05-18 09:56:16 +020012465 USTPUTC(CTLARI, out);
Eric Andersenc470f442003-07-28 09:56:35 +000012466 goto parsearith_return;
12467}
12468#endif
Eric Andersenc470f442003-07-28 09:56:35 +000012469} /* end of readtoken */
12470
Eric Andersencb57d552001-06-28 07:25:16 +000012471/*
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012472 * Read the next input token.
12473 * If the token is a word, we set backquotelist to the list of cmds in
12474 * backquotes. We set quoteflag to true if any part of the word was
12475 * quoted.
12476 * If the token is TREDIR, then we set redirnode to a structure containing
12477 * the redirection.
12478 * In all cases, the variable startlinno is set to the number of the line
12479 * on which the token starts.
12480 *
12481 * [Change comment: here documents and internal procedures]
12482 * [Readtoken shouldn't have any arguments. Perhaps we should make the
12483 * word parsing code into a separate routine. In this case, readtoken
12484 * doesn't need to have any internal procedures, but parseword does.
12485 * We could also make parseoperator in essence the main routine, and
12486 * have parseword (readtoken1?) handle both words and redirection.]
Eric Andersencb57d552001-06-28 07:25:16 +000012487 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012488#define NEW_xxreadtoken
12489#ifdef NEW_xxreadtoken
12490/* singles must be first! */
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000012491static const char xxreadtoken_chars[7] ALIGN1 = {
Denis Vlasenko834dee72008-10-07 09:18:30 +000012492 '\n', '(', ')', /* singles */
12493 '&', '|', ';', /* doubles */
12494 0
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000012495};
Eric Andersencb57d552001-06-28 07:25:16 +000012496
Denis Vlasenko834dee72008-10-07 09:18:30 +000012497#define xxreadtoken_singles 3
12498#define xxreadtoken_doubles 3
12499
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000012500static const char xxreadtoken_tokens[] ALIGN1 = {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012501 TNL, TLP, TRP, /* only single occurrence allowed */
12502 TBACKGND, TPIPE, TSEMI, /* if single occurrence */
12503 TEOF, /* corresponds to trailing nul */
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000012504 TAND, TOR, TENDCASE /* if double occurrence */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012505};
12506
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012507static int
12508xxreadtoken(void)
12509{
12510 int c;
12511
12512 if (tokpushback) {
12513 tokpushback = 0;
12514 return lasttoken;
Eric Andersencb57d552001-06-28 07:25:16 +000012515 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020012516 setprompt_if(needprompt, 2);
Denis Vlasenko41eb3002008-11-28 03:42:31 +000012517 startlinno = g_parsefile->linno;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012518 for (;;) { /* until token or start of word found */
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020012519 c = pgetc();
Denis Vlasenko5e34ff22009-04-21 11:09:40 +000012520 if (c == ' ' || c == '\t' IF_ASH_ALIAS( || c == PEOA))
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012521 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012522
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012523 if (c == '#') {
12524 while ((c = pgetc()) != '\n' && c != PEOF)
12525 continue;
12526 pungetc();
12527 } else if (c == '\\') {
12528 if (pgetc() != '\n') {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012529 pungetc();
Denis Vlasenko834dee72008-10-07 09:18:30 +000012530 break; /* return readtoken1(...) */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012531 }
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012532 nlprompt();
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012533 } else {
12534 const char *p;
12535
12536 p = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
12537 if (c != PEOF) {
12538 if (c == '\n') {
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012539 nlnoprompt();
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012540 }
12541
12542 p = strchr(xxreadtoken_chars, c);
Denis Vlasenko834dee72008-10-07 09:18:30 +000012543 if (p == NULL)
12544 break; /* return readtoken1(...) */
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012545
Denis Vlasenko834dee72008-10-07 09:18:30 +000012546 if ((int)(p - xxreadtoken_chars) >= xxreadtoken_singles) {
12547 int cc = pgetc();
12548 if (cc == c) { /* double occurrence? */
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012549 p += xxreadtoken_doubles + 1;
12550 } else {
12551 pungetc();
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010012552#if BASH_REDIR_OUTPUT
Denis Vlasenko834dee72008-10-07 09:18:30 +000012553 if (c == '&' && cc == '>') /* &> */
12554 break; /* return readtoken1(...) */
12555#endif
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012556 }
12557 }
12558 }
12559 lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
12560 return lasttoken;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012561 }
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012562 } /* for (;;) */
Denis Vlasenko834dee72008-10-07 09:18:30 +000012563
12564 return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012565}
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012566#else /* old xxreadtoken */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012567#define RETURN(token) return lasttoken = token
12568static int
12569xxreadtoken(void)
12570{
12571 int c;
12572
12573 if (tokpushback) {
12574 tokpushback = 0;
12575 return lasttoken;
12576 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020012577 setprompt_if(needprompt, 2);
Denis Vlasenko41eb3002008-11-28 03:42:31 +000012578 startlinno = g_parsefile->linno;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012579 for (;;) { /* until token or start of word found */
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020012580 c = pgetc();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012581 switch (c) {
12582 case ' ': case '\t':
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010012583 IF_ASH_ALIAS(case PEOA:)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012584 continue;
12585 case '#':
Denis Vlasenkof7d56652008-03-25 05:51:41 +000012586 while ((c = pgetc()) != '\n' && c != PEOF)
12587 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012588 pungetc();
12589 continue;
12590 case '\\':
12591 if (pgetc() == '\n') {
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012592 nlprompt();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012593 continue;
12594 }
12595 pungetc();
12596 goto breakloop;
12597 case '\n':
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012598 nlnoprompt();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012599 RETURN(TNL);
12600 case PEOF:
12601 RETURN(TEOF);
12602 case '&':
12603 if (pgetc() == '&')
12604 RETURN(TAND);
12605 pungetc();
12606 RETURN(TBACKGND);
12607 case '|':
12608 if (pgetc() == '|')
12609 RETURN(TOR);
12610 pungetc();
12611 RETURN(TPIPE);
12612 case ';':
12613 if (pgetc() == ';')
12614 RETURN(TENDCASE);
12615 pungetc();
12616 RETURN(TSEMI);
12617 case '(':
12618 RETURN(TLP);
12619 case ')':
12620 RETURN(TRP);
12621 default:
12622 goto breakloop;
12623 }
12624 }
12625 breakloop:
12626 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
12627#undef RETURN
12628}
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012629#endif /* old xxreadtoken */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012630
12631static int
12632readtoken(void)
12633{
12634 int t;
Ron Yorston713f07d2015-10-29 16:44:56 +000012635 int kwd = checkkwd;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012636#if DEBUG
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000012637 smallint alreadyseen = tokpushback;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012638#endif
12639
12640#if ENABLE_ASH_ALIAS
12641 top:
12642#endif
12643
12644 t = xxreadtoken();
12645
12646 /*
12647 * eat newlines
12648 */
Ron Yorston713f07d2015-10-29 16:44:56 +000012649 if (kwd & CHKNL) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012650 while (t == TNL) {
12651 parseheredoc();
12652 t = xxreadtoken();
12653 }
12654 }
12655
12656 if (t != TWORD || quoteflag) {
12657 goto out;
12658 }
12659
12660 /*
12661 * check for keywords
12662 */
Ron Yorston713f07d2015-10-29 16:44:56 +000012663 if (kwd & CHKKWD) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012664 const char *const *pp;
12665
12666 pp = findkwd(wordtext);
12667 if (pp) {
12668 lasttoken = t = pp - tokname_array;
Denys Vlasenko888527c2016-10-02 16:54:17 +020012669 TRACE(("keyword '%s' recognized\n", tokname_array[t]));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012670 goto out;
12671 }
12672 }
12673
12674 if (checkkwd & CHKALIAS) {
12675#if ENABLE_ASH_ALIAS
12676 struct alias *ap;
12677 ap = lookupalias(wordtext, 1);
12678 if (ap != NULL) {
12679 if (*ap->val) {
12680 pushstring(ap->val, ap);
12681 }
12682 goto top;
12683 }
12684#endif
12685 }
12686 out:
12687 checkkwd = 0;
12688#if DEBUG
12689 if (!alreadyseen)
Denys Vlasenko888527c2016-10-02 16:54:17 +020012690 TRACE(("token '%s' %s\n", tokname_array[t], t == TWORD ? wordtext : ""));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012691 else
Denys Vlasenko888527c2016-10-02 16:54:17 +020012692 TRACE(("reread token '%s' %s\n", tokname_array[t], t == TWORD ? wordtext : ""));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012693#endif
12694 return t;
Eric Andersencb57d552001-06-28 07:25:16 +000012695}
12696
Ron Yorstonc0e00762015-10-29 11:30:55 +000012697static int
Ron Yorston6bd2fab2015-10-29 11:30:22 +000012698peektoken(void)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012699{
12700 int t;
12701
12702 t = readtoken();
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000012703 tokpushback = 1;
Ron Yorstonc0e00762015-10-29 11:30:55 +000012704 return t;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012705}
Eric Andersencb57d552001-06-28 07:25:16 +000012706
12707/*
Denys Vlasenko86e83ec2009-07-23 22:07:07 +020012708 * Read and parse a command. Returns NODE_EOF on end of file.
12709 * (NULL is a valid parse tree indicating a blank line.)
Eric Andersencb57d552001-06-28 07:25:16 +000012710 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012711static union node *
12712parsecmd(int interact)
Eric Andersen90898442003-08-06 11:20:52 +000012713{
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012714 tokpushback = 0;
Ron Yorstonc0e00762015-10-29 11:30:55 +000012715 checkkwd = 0;
12716 heredoclist = 0;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012717 doprompt = interact;
Denys Vlasenko958581a2010-09-12 15:04:27 +020012718 setprompt_if(doprompt, doprompt);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012719 needprompt = 0;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012720 return list(1);
12721}
12722
12723/*
12724 * Input any here documents.
12725 */
12726static void
12727parseheredoc(void)
12728{
12729 struct heredoc *here;
12730 union node *n;
12731
12732 here = heredoclist;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000012733 heredoclist = NULL;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012734
12735 while (here) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020012736 setprompt_if(needprompt, 2);
12737 readtoken1(pgetc(), here->here->type == NHERE ? SQSYNTAX : DQSYNTAX,
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012738 here->eofmark, here->striptabs);
Denis Vlasenko597906c2008-02-20 16:38:54 +000012739 n = stzalloc(sizeof(struct narg));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012740 n->narg.type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000012741 /*n->narg.next = NULL; - stzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012742 n->narg.text = wordtext;
12743 n->narg.backquote = backquotelist;
12744 here->here->nhere.doc = n;
12745 here = here->next;
Eric Andersencb57d552001-06-28 07:25:16 +000012746 }
Eric Andersencb57d552001-06-28 07:25:16 +000012747}
12748
12749
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012750static const char *
Denys Vlasenko46999802017-07-29 21:12:29 +020012751expandstr(const char *ps, int syntax_type)
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012752{
12753 union node n;
Denys Vlasenko2a6d29a2016-10-25 21:17:52 +020012754 int saveprompt;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012755
Denys Vlasenko46999802017-07-29 21:12:29 +020012756 /* XXX Fix (char *) cast. */
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012757 setinputstring((char *)ps);
Denys Vlasenko2a6d29a2016-10-25 21:17:52 +020012758
12759 saveprompt = doprompt;
12760 doprompt = 0;
Denys Vlasenkoa2e32b32017-10-12 19:20:13 +020012761
12762 /* readtoken1() might die horribly.
Denys Vlasenko3c183a82017-10-12 19:35:42 +020012763 * Try a prompt with syntactically wrong command:
Denys Vlasenkoa2e32b32017-10-12 19:20:13 +020012764 * PS1='$(date "+%H:%M:%S) > '
12765 */
12766 {
12767 volatile int saveint;
12768 struct jmploc *volatile savehandler = exception_handler;
12769 struct jmploc jmploc;
12770 SAVE_INT(saveint);
12771 if (setjmp(jmploc.loc) == 0) {
12772 exception_handler = &jmploc;
12773 readtoken1(pgetc(), syntax_type, FAKEEOFMARK, 0);
12774 }
12775 exception_handler = savehandler;
12776 RESTORE_INT(saveint);
12777 }
12778
Denys Vlasenko2a6d29a2016-10-25 21:17:52 +020012779 doprompt = saveprompt;
12780
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012781 popfile();
12782
12783 n.narg.type = NARG;
12784 n.narg.next = NULL;
12785 n.narg.text = wordtext;
12786 n.narg.backquote = backquotelist;
12787
Ron Yorston549deab2015-05-18 09:57:51 +020012788 expandarg(&n, NULL, EXP_QUOTED);
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012789 return stackblock();
12790}
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012791
Denys Vlasenko1e3e2cc2017-07-25 20:31:14 +020012792static inline int
12793parser_eof(void)
12794{
12795 return tokpushback && lasttoken == TEOF;
12796}
12797
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012798/*
12799 * Execute a command or commands contained in a string.
12800 */
12801static int
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020012802evalstring(char *s, int flags)
Eric Andersenc470f442003-07-28 09:56:35 +000012803{
Denys Vlasenko493b9ca2016-10-30 18:27:14 +010012804 struct jmploc *volatile savehandler;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012805 struct jmploc jmploc;
12806 int ex;
12807
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012808 union node *n;
12809 struct stackmark smark;
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012810 int status;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012811
Denys Vlasenko8e2bc472016-09-28 23:02:57 +020012812 s = sstrdup(s);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012813 setinputstring(s);
12814 setstackmark(&smark);
12815
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012816 status = 0;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012817 /* On exception inside execution loop, we must popfile().
12818 * Try interactively:
12819 * readonly a=a
12820 * command eval "a=b" # throws "is read only" error
12821 * "command BLTIN" is not supposed to abort (even in non-interactive use).
12822 * But if we skip popfile(), we hit EOF in eval's string, and exit.
12823 */
12824 savehandler = exception_handler;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012825 ex = setjmp(jmploc.loc);
12826 if (ex)
12827 goto out;
Denys Vlasenko493b9ca2016-10-30 18:27:14 +010012828 exception_handler = &jmploc;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012829
Denys Vlasenko86e83ec2009-07-23 22:07:07 +020012830 while ((n = parsecmd(0)) != NODE_EOF) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020012831 int i;
12832
Denys Vlasenko1e3e2cc2017-07-25 20:31:14 +020012833 i = evaltree(n, flags & ~(parser_eof() ? 0 : EV_EXIT));
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012834 if (n)
12835 status = i;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012836 popstackmark(&smark);
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012837 if (evalskip)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012838 break;
12839 }
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012840 out:
Denys Vlasenko8e2bc472016-09-28 23:02:57 +020012841 popstackmark(&smark);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012842 popfile();
Denys Vlasenko8e2bc472016-09-28 23:02:57 +020012843 stunalloc(s);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012844
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012845 exception_handler = savehandler;
12846 if (ex)
Denys Vlasenko14c85eb2017-10-12 19:40:47 +020012847 longjmp(exception_handler->loc, ex);
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012848
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012849 return status;
Eric Andersenc470f442003-07-28 09:56:35 +000012850}
12851
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012852/*
12853 * The eval command.
12854 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012855static int FAST_FUNC
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020012856evalcmd(int argc UNUSED_PARAM, char **argv, int flags)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012857{
12858 char *p;
12859 char *concat;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012860
Denis Vlasenko68404f12008-03-17 09:00:54 +000012861 if (argv[1]) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012862 p = argv[1];
Denis Vlasenko68404f12008-03-17 09:00:54 +000012863 argv += 2;
12864 if (argv[0]) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012865 STARTSTACKSTR(concat);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012866 for (;;) {
12867 concat = stack_putstr(p, concat);
Denis Vlasenko68404f12008-03-17 09:00:54 +000012868 p = *argv++;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012869 if (p == NULL)
12870 break;
12871 STPUTC(' ', concat);
12872 }
12873 STPUTC('\0', concat);
12874 p = grabstackstr(concat);
12875 }
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020012876 return evalstring(p, flags & EV_TESTED);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012877 }
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012878 return 0;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012879}
12880
12881/*
Denys Vlasenko285ad152009-12-04 23:02:27 +010012882 * Read and execute commands.
12883 * "Top" is nonzero for the top level command loop;
12884 * it turns on prompting if the shell is interactive.
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012885 */
12886static int
12887cmdloop(int top)
12888{
12889 union node *n;
12890 struct stackmark smark;
12891 int inter;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020012892 int status = 0;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012893 int numeof = 0;
12894
12895 TRACE(("cmdloop(%d) called\n", top));
12896 for (;;) {
12897 int skip;
12898
12899 setstackmark(&smark);
12900#if JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +000012901 if (doing_jobctl)
Denys Vlasenko9c541002015-10-07 15:44:36 +020012902 showjobs(SHOW_CHANGED|SHOW_STDERR);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012903#endif
12904 inter = 0;
12905 if (iflag && top) {
12906 inter++;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012907 chkmail();
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012908 }
12909 n = parsecmd(inter);
Denys Vlasenko7cee00e2009-07-24 01:08:03 +020012910#if DEBUG
12911 if (DEBUG > 2 && debug && (n != NODE_EOF))
Denys Vlasenko883cea42009-07-11 15:31:59 +020012912 showtree(n);
Denis Vlasenko135cecb2009-04-12 00:00:57 +000012913#endif
Denys Vlasenko86e83ec2009-07-23 22:07:07 +020012914 if (n == NODE_EOF) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012915 if (!top || numeof >= 50)
12916 break;
12917 if (!stoppedjobs()) {
12918 if (!Iflag)
12919 break;
12920 out2str("\nUse \"exit\" to leave shell.\n");
12921 }
12922 numeof++;
12923 } else if (nflag == 0) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020012924 int i;
12925
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +000012926 /* job_warning can only be 2,1,0. Here 2->1, 1/0->0 */
12927 job_warning >>= 1;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012928 numeof = 0;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020012929 i = evaltree(n, 0);
12930 if (n)
12931 status = i;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012932 }
12933 popstackmark(&smark);
12934 skip = evalskip;
12935
12936 if (skip) {
Denys Vlasenko6a0710e2016-09-30 14:18:34 +020012937 evalskip &= ~SKIPFUNC;
Denys Vlasenko0840c912016-10-01 15:27:44 +020012938 break;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012939 }
12940 }
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020012941 return status;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012942}
12943
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000012944/*
12945 * Take commands from a file. To be compatible we should do a path
12946 * search for the file, which is necessary to find sub-commands.
12947 */
12948static char *
12949find_dot_file(char *name)
12950{
12951 char *fullname;
12952 const char *path = pathval();
12953 struct stat statb;
12954
12955 /* don't try this for absolute or relative paths */
12956 if (strchr(name, '/'))
12957 return name;
12958
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020012959 while ((fullname = path_advance(&path, name)) != NULL) {
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000012960 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
12961 /*
12962 * Don't bother freeing here, since it will
12963 * be freed by the caller.
12964 */
12965 return fullname;
12966 }
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020012967 if (fullname != name)
12968 stunalloc(fullname);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000012969 }
12970
12971 /* not found in the PATH */
12972 ash_msg_and_raise_error("%s: not found", name);
12973 /* NOTREACHED */
12974}
12975
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012976static int FAST_FUNC
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012977dotcmd(int argc_ UNUSED_PARAM, char **argv_ UNUSED_PARAM)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012978{
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012979 /* "false; . empty_file; echo $?" should print 0, not 1: */
12980 int status = 0;
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012981 char *fullname;
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012982 char **argv;
Denys Vlasenkofb87d932017-01-09 08:22:06 +010012983 char *args_need_save;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012984 volatile struct shparam saveparam;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012985
Denys Vlasenko981a0562017-07-26 19:53:11 +020012986//???
12987// struct strlist *sp;
12988// for (sp = cmdenviron; sp; sp = sp->next)
12989// setvareq(ckstrdup(sp->text), VSTRFIXED | VTEXTFIXED);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012990
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012991 nextopt(nullstr); /* handle possible "--" */
12992 argv = argptr;
12993
12994 if (!argv[0]) {
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012995 /* bash says: "bash: .: filename argument required" */
12996 return 2; /* bash compat */
12997 }
12998
Denys Vlasenko091f8312013-03-17 14:25:22 +010012999 /* This aborts if file isn't found, which is POSIXly correct.
13000 * bash returns exitcode 1 instead.
13001 */
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020013002 fullname = find_dot_file(argv[0]);
13003 argv++;
Denys Vlasenkofb87d932017-01-09 08:22:06 +010013004 args_need_save = argv[0];
Denys Vlasenko5f7c82b2017-02-03 13:00:06 +010013005 if (args_need_save) { /* ". FILE ARGS", and ARGS are not empty */
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020013006 int argc;
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020013007 saveparam = shellparam;
13008 shellparam.malloced = 0;
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020013009 argc = 1;
13010 while (argv[argc])
13011 argc++;
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020013012 shellparam.nparam = argc;
13013 shellparam.p = argv;
13014 };
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013015
Denys Vlasenko091f8312013-03-17 14:25:22 +010013016 /* This aborts if file can't be opened, which is POSIXly correct.
13017 * bash returns exitcode 1 instead.
13018 */
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020013019 setinputfile(fullname, INPUT_PUSH_FILE);
13020 commandname = fullname;
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020013021 status = cmdloop(0);
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020013022 popfile();
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013023
Denys Vlasenkofb87d932017-01-09 08:22:06 +010013024 if (args_need_save) {
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020013025 freeparam(&shellparam);
13026 shellparam = saveparam;
13027 };
13028
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020013029 return status;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013030}
13031
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013032static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013033exitcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013034{
13035 if (stoppedjobs())
13036 return 0;
Denis Vlasenko68404f12008-03-17 09:00:54 +000013037 if (argv[1])
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013038 exitstatus = number(argv[1]);
13039 raise_exception(EXEXIT);
13040 /* NOTREACHED */
13041}
13042
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013043/*
13044 * Read a file containing shell functions.
13045 */
13046static void
13047readcmdfile(char *name)
13048{
13049 setinputfile(name, INPUT_PUSH_FILE);
13050 cmdloop(0);
13051 popfile();
13052}
13053
13054
Denis Vlasenkocc571512007-02-23 21:10:35 +000013055/* ============ find_command inplementation */
13056
13057/*
13058 * Resolve a command name. If you change this routine, you may have to
13059 * change the shellexec routine as well.
13060 */
13061static void
13062find_command(char *name, struct cmdentry *entry, int act, const char *path)
13063{
13064 struct tblentry *cmdp;
13065 int idx;
13066 int prev;
13067 char *fullname;
13068 struct stat statb;
13069 int e;
13070 int updatetbl;
13071 struct builtincmd *bcmd;
13072
13073 /* If name contains a slash, don't use PATH or hash table */
13074 if (strchr(name, '/') != NULL) {
13075 entry->u.index = -1;
13076 if (act & DO_ABS) {
13077 while (stat(name, &statb) < 0) {
13078#ifdef SYSV
13079 if (errno == EINTR)
13080 continue;
13081#endif
13082 entry->cmdtype = CMDUNKNOWN;
13083 return;
13084 }
13085 }
13086 entry->cmdtype = CMDNORMAL;
13087 return;
13088 }
13089
Denis Vlasenkof20de5b2007-04-29 23:42:54 +000013090/* #if ENABLE_FEATURE_SH_STANDALONE... moved after builtin check */
Denis Vlasenkocc571512007-02-23 21:10:35 +000013091
13092 updatetbl = (path == pathval());
13093 if (!updatetbl) {
13094 act |= DO_ALTPATH;
13095 if (strstr(path, "%builtin") != NULL)
13096 act |= DO_ALTBLTIN;
13097 }
13098
13099 /* If name is in the table, check answer will be ok */
13100 cmdp = cmdlookup(name, 0);
13101 if (cmdp != NULL) {
13102 int bit;
13103
13104 switch (cmdp->cmdtype) {
13105 default:
13106#if DEBUG
13107 abort();
13108#endif
13109 case CMDNORMAL:
13110 bit = DO_ALTPATH;
13111 break;
13112 case CMDFUNCTION:
13113 bit = DO_NOFUNC;
13114 break;
13115 case CMDBUILTIN:
13116 bit = DO_ALTBLTIN;
13117 break;
13118 }
13119 if (act & bit) {
13120 updatetbl = 0;
13121 cmdp = NULL;
13122 } else if (cmdp->rehash == 0)
13123 /* if not invalidated by cd, we're done */
13124 goto success;
13125 }
13126
13127 /* If %builtin not in path, check for builtin next */
13128 bcmd = find_builtin(name);
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000013129 if (bcmd) {
13130 if (IS_BUILTIN_REGULAR(bcmd))
13131 goto builtin_success;
13132 if (act & DO_ALTPATH) {
13133 if (!(act & DO_ALTBLTIN))
13134 goto builtin_success;
13135 } else if (builtinloc <= 0) {
13136 goto builtin_success;
Denis Vlasenko8e858e22007-03-07 09:35:43 +000013137 }
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000013138 }
Denis Vlasenkocc571512007-02-23 21:10:35 +000013139
Denis Vlasenkof20de5b2007-04-29 23:42:54 +000013140#if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko7465dbc2008-04-13 02:25:53 +000013141 {
13142 int applet_no = find_applet_by_name(name);
13143 if (applet_no >= 0) {
13144 entry->cmdtype = CMDNORMAL;
13145 entry->u.index = -2 - applet_no;
13146 return;
13147 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +000013148 }
13149#endif
13150
Denis Vlasenkocc571512007-02-23 21:10:35 +000013151 /* We have to search path. */
13152 prev = -1; /* where to start */
13153 if (cmdp && cmdp->rehash) { /* doing a rehash */
13154 if (cmdp->cmdtype == CMDBUILTIN)
13155 prev = builtinloc;
13156 else
13157 prev = cmdp->param.index;
13158 }
13159
13160 e = ENOENT;
13161 idx = -1;
13162 loop:
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020013163 while ((fullname = path_advance(&path, name)) != NULL) {
Denis Vlasenkocc571512007-02-23 21:10:35 +000013164 stunalloc(fullname);
Denis Vlasenkodee82b62007-07-29 14:05:27 +000013165 /* NB: code below will still use fullname
13166 * despite it being "unallocated" */
Denis Vlasenkocc571512007-02-23 21:10:35 +000013167 idx++;
13168 if (pathopt) {
13169 if (prefix(pathopt, "builtin")) {
13170 if (bcmd)
13171 goto builtin_success;
13172 continue;
Denis Vlasenko4a9ca132008-04-12 20:07:08 +000013173 }
13174 if ((act & DO_NOFUNC)
13175 || !prefix(pathopt, "func")
Denys Vlasenkoe4dcba12010-10-28 18:57:19 +020013176 ) { /* ignore unimplemented options */
Denis Vlasenkocc571512007-02-23 21:10:35 +000013177 continue;
13178 }
13179 }
13180 /* if rehash, don't redo absolute path names */
13181 if (fullname[0] == '/' && idx <= prev) {
13182 if (idx < prev)
13183 continue;
13184 TRACE(("searchexec \"%s\": no change\n", name));
13185 goto success;
13186 }
13187 while (stat(fullname, &statb) < 0) {
13188#ifdef SYSV
13189 if (errno == EINTR)
13190 continue;
13191#endif
13192 if (errno != ENOENT && errno != ENOTDIR)
13193 e = errno;
13194 goto loop;
13195 }
13196 e = EACCES; /* if we fail, this will be the error */
13197 if (!S_ISREG(statb.st_mode))
13198 continue;
13199 if (pathopt) { /* this is a %func directory */
13200 stalloc(strlen(fullname) + 1);
Denis Vlasenkodee82b62007-07-29 14:05:27 +000013201 /* NB: stalloc will return space pointed by fullname
13202 * (because we don't have any intervening allocations
13203 * between stunalloc above and this stalloc) */
Denis Vlasenkocc571512007-02-23 21:10:35 +000013204 readcmdfile(fullname);
13205 cmdp = cmdlookup(name, 0);
13206 if (cmdp == NULL || cmdp->cmdtype != CMDFUNCTION)
13207 ash_msg_and_raise_error("%s not defined in %s", name, fullname);
13208 stunalloc(fullname);
13209 goto success;
13210 }
13211 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
13212 if (!updatetbl) {
13213 entry->cmdtype = CMDNORMAL;
13214 entry->u.index = idx;
13215 return;
13216 }
13217 INT_OFF;
13218 cmdp = cmdlookup(name, 1);
13219 cmdp->cmdtype = CMDNORMAL;
13220 cmdp->param.index = idx;
13221 INT_ON;
13222 goto success;
13223 }
13224
13225 /* We failed. If there was an entry for this command, delete it */
13226 if (cmdp && updatetbl)
13227 delete_cmd_entry();
13228 if (act & DO_ERR)
13229 ash_msg("%s: %s", name, errmsg(e, "not found"));
13230 entry->cmdtype = CMDUNKNOWN;
13231 return;
13232
13233 builtin_success:
13234 if (!updatetbl) {
13235 entry->cmdtype = CMDBUILTIN;
13236 entry->u.cmd = bcmd;
13237 return;
13238 }
13239 INT_OFF;
13240 cmdp = cmdlookup(name, 1);
13241 cmdp->cmdtype = CMDBUILTIN;
13242 cmdp->param.cmd = bcmd;
13243 INT_ON;
13244 success:
13245 cmdp->rehash = 0;
13246 entry->cmdtype = cmdp->cmdtype;
13247 entry->u = cmdp->param;
13248}
13249
13250
Eric Andersencb57d552001-06-28 07:25:16 +000013251/*
Eric Andersencb57d552001-06-28 07:25:16 +000013252 * The trap builtin.
13253 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013254static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013255trapcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +000013256{
13257 char *action;
13258 char **ap;
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010013259 int signo, exitcode;
Eric Andersencb57d552001-06-28 07:25:16 +000013260
Eric Andersenc470f442003-07-28 09:56:35 +000013261 nextopt(nullstr);
13262 ap = argptr;
13263 if (!*ap) {
Denis Vlasenko2da584f2007-02-19 22:44:05 +000013264 for (signo = 0; signo < NSIG; signo++) {
Denys Vlasenko21d87d42009-09-25 00:06:51 +020013265 char *tr = trap_ptr[signo];
13266 if (tr) {
Denys Vlasenkoe74aaf92009-09-27 02:05:45 +020013267 /* note: bash adds "SIG", but only if invoked
13268 * as "bash". If called as "sh", or if set -o posix,
13269 * then it prints short signal names.
13270 * We are printing short names: */
13271 out1fmt("trap -- %s %s\n",
Denys Vlasenko21d87d42009-09-25 00:06:51 +020013272 single_quote(tr),
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +000013273 get_signame(signo));
Denys Vlasenko726e1a02009-09-25 02:58:20 +020013274 /* trap_ptr != trap only if we are in special-cased `trap` code.
13275 * In this case, we will exit very soon, no need to free(). */
Denys Vlasenkoe74aaf92009-09-27 02:05:45 +020013276 /* if (trap_ptr != trap && tp[0]) */
Denys Vlasenko726e1a02009-09-25 02:58:20 +020013277 /* free(tr); */
Eric Andersencb57d552001-06-28 07:25:16 +000013278 }
13279 }
Denys Vlasenko726e1a02009-09-25 02:58:20 +020013280 /*
Denys Vlasenko21d87d42009-09-25 00:06:51 +020013281 if (trap_ptr != trap) {
13282 free(trap_ptr);
13283 trap_ptr = trap;
13284 }
Denys Vlasenko726e1a02009-09-25 02:58:20 +020013285 */
Eric Andersencb57d552001-06-28 07:25:16 +000013286 return 0;
13287 }
Denys Vlasenko21d87d42009-09-25 00:06:51 +020013288
Denys Vlasenko86981e32017-07-25 20:06:17 +020013289 /* Why the second check?
13290 * "trap NUM [sig2]..." is the same as "trap - NUM [sig2]..."
13291 * In this case, NUM is signal no, not an action.
13292 */
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +000013293 action = NULL;
Denys Vlasenko86981e32017-07-25 20:06:17 +020013294 if (ap[1] && !is_number(ap[0]))
Eric Andersencb57d552001-06-28 07:25:16 +000013295 action = *ap++;
Denys Vlasenko86981e32017-07-25 20:06:17 +020013296
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010013297 exitcode = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000013298 while (*ap) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000013299 signo = get_signum(*ap);
Denys Vlasenko86981e32017-07-25 20:06:17 +020013300 if (signo < 0) {
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010013301 /* Mimic bash message exactly */
13302 ash_msg("%s: invalid signal specification", *ap);
13303 exitcode = 1;
13304 goto next;
13305 }
Denis Vlasenkob012b102007-02-19 22:43:01 +000013306 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +000013307 if (action) {
Denis Vlasenko9f739442006-12-16 23:49:13 +000013308 if (LONE_DASH(action))
Eric Andersencb57d552001-06-28 07:25:16 +000013309 action = NULL;
Denys Vlasenkob4f51d32016-10-27 12:55:09 +020013310 else {
13311 if (action[0]) /* not NULL and not "" and not "-" */
13312 may_have_traps = 1;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013313 action = ckstrdup(action);
Denys Vlasenkob4f51d32016-10-27 12:55:09 +020013314 }
Eric Andersencb57d552001-06-28 07:25:16 +000013315 }
Denis Vlasenko60818682007-09-28 22:07:23 +000013316 free(trap[signo]);
Eric Andersencb57d552001-06-28 07:25:16 +000013317 trap[signo] = action;
13318 if (signo != 0)
13319 setsignal(signo);
Denis Vlasenkob012b102007-02-19 22:43:01 +000013320 INT_ON;
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010013321 next:
Eric Andersencb57d552001-06-28 07:25:16 +000013322 ap++;
13323 }
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010013324 return exitcode;
Eric Andersencb57d552001-06-28 07:25:16 +000013325}
13326
Eric Andersenc470f442003-07-28 09:56:35 +000013327
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013328/* ============ Builtins */
Eric Andersenc470f442003-07-28 09:56:35 +000013329
Denys Vlasenko2ec34962014-09-08 16:52:39 +020013330#if ENABLE_ASH_HELP
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013331static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013332helpcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000013333{
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000013334 unsigned col;
13335 unsigned i;
Eric Andersenc470f442003-07-28 09:56:35 +000013336
Denys Vlasenkod6b05eb2009-06-06 20:59:55 +020013337 out1fmt(
Denis Vlasenko34d4d892009-04-04 20:24:37 +000013338 "Built-in commands:\n"
13339 "------------------\n");
Denis Vlasenkob71c6682007-07-21 15:08:09 +000013340 for (col = 0, i = 0; i < ARRAY_SIZE(builtintab); i++) {
Eric Andersenc470f442003-07-28 09:56:35 +000013341 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
Denis Vlasenko52764022007-02-24 13:42:56 +000013342 builtintab[i].name + 1);
Eric Andersenc470f442003-07-28 09:56:35 +000013343 if (col > 60) {
13344 out1fmt("\n");
13345 col = 0;
13346 }
13347 }
Denys Vlasenko2ec34962014-09-08 16:52:39 +020013348# if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko1aa7e472007-11-28 06:49:03 +000013349 {
13350 const char *a = applet_names;
13351 while (*a) {
13352 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), a);
13353 if (col > 60) {
13354 out1fmt("\n");
13355 col = 0;
13356 }
Ron Yorston2b919582016-04-08 11:57:20 +010013357 while (*a++ != '\0')
13358 continue;
Eric Andersenc470f442003-07-28 09:56:35 +000013359 }
13360 }
Denys Vlasenko2ec34962014-09-08 16:52:39 +020013361# endif
Denys Vlasenkoebedb942016-10-02 18:45:09 +020013362 newline_and_flush(stdout);
Eric Andersenc470f442003-07-28 09:56:35 +000013363 return EXIT_SUCCESS;
13364}
Denys Vlasenko2ec34962014-09-08 16:52:39 +020013365#endif
Eric Andersenc470f442003-07-28 09:56:35 +000013366
Flemming Madsend96ffda2013-04-07 18:47:24 +020013367#if MAX_HISTORY
13368static int FAST_FUNC
13369historycmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
13370{
13371 show_history(line_input_state);
13372 return EXIT_SUCCESS;
13373}
13374#endif
13375
Eric Andersencb57d552001-06-28 07:25:16 +000013376/*
Eric Andersencb57d552001-06-28 07:25:16 +000013377 * The export and readonly commands.
13378 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013379static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013380exportcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000013381{
13382 struct var *vp;
13383 char *name;
13384 const char *p;
Eric Andersenc470f442003-07-28 09:56:35 +000013385 char **aptr;
Denys Vlasenkod5275882012-10-01 13:41:17 +020013386 char opt;
13387 int flag;
13388 int flag_off;
Eric Andersencb57d552001-06-28 07:25:16 +000013389
Denys Vlasenkod5275882012-10-01 13:41:17 +020013390 /* "readonly" in bash accepts, but ignores -n.
13391 * We do the same: it saves a conditional in nextopt's param.
13392 */
13393 flag_off = 0;
13394 while ((opt = nextopt("np")) != '\0') {
13395 if (opt == 'n')
13396 flag_off = VEXPORT;
13397 }
13398 flag = VEXPORT;
13399 if (argv[0][0] == 'r') {
13400 flag = VREADONLY;
13401 flag_off = 0; /* readonly ignores -n */
13402 }
13403 flag_off = ~flag_off;
13404
Denys Vlasenko10ad6222017-04-17 16:13:32 +020013405 /*if (opt_p_not_specified) - bash doesn't check this. Try "export -p NAME" */
Denys Vlasenkod5275882012-10-01 13:41:17 +020013406 {
Denis Vlasenko2da584f2007-02-19 22:44:05 +000013407 aptr = argptr;
13408 name = *aptr;
13409 if (name) {
13410 do {
13411 p = strchr(name, '=');
13412 if (p != NULL) {
13413 p++;
13414 } else {
13415 vp = *findvar(hashvar(name), name);
13416 if (vp) {
Denys Vlasenkod5275882012-10-01 13:41:17 +020013417 vp->flags = ((vp->flags | flag) & flag_off);
Denis Vlasenko2da584f2007-02-19 22:44:05 +000013418 continue;
13419 }
Eric Andersencb57d552001-06-28 07:25:16 +000013420 }
Denys Vlasenkod5275882012-10-01 13:41:17 +020013421 setvar(name, p, (flag & flag_off));
Denis Vlasenko2da584f2007-02-19 22:44:05 +000013422 } while ((name = *++aptr) != NULL);
13423 return 0;
13424 }
Eric Andersencb57d552001-06-28 07:25:16 +000013425 }
Denys Vlasenkod5275882012-10-01 13:41:17 +020013426
13427 /* No arguments. Show the list of exported or readonly vars.
13428 * -n is ignored.
13429 */
Denis Vlasenko2da584f2007-02-19 22:44:05 +000013430 showvars(argv[0], flag, 0);
Eric Andersencb57d552001-06-28 07:25:16 +000013431 return 0;
13432}
13433
Eric Andersencb57d552001-06-28 07:25:16 +000013434/*
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000013435 * Delete a function if it exists.
Eric Andersencb57d552001-06-28 07:25:16 +000013436 */
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +000013437static void
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000013438unsetfunc(const char *name)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000013439{
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000013440 struct tblentry *cmdp;
Eric Andersencb57d552001-06-28 07:25:16 +000013441
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000013442 cmdp = cmdlookup(name, 0);
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020013443 if (cmdp != NULL && cmdp->cmdtype == CMDFUNCTION)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000013444 delete_cmd_entry();
Eric Andersenc470f442003-07-28 09:56:35 +000013445}
13446
Eric Andersencb57d552001-06-28 07:25:16 +000013447/*
Eric Andersencb57d552001-06-28 07:25:16 +000013448 * The unset builtin command. We unset the function before we unset the
13449 * variable to allow a function to be unset when there is a readonly variable
13450 * with the same name.
13451 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013452static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013453unsetcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +000013454{
13455 char **ap;
13456 int i;
Eric Andersenc470f442003-07-28 09:56:35 +000013457 int flag = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000013458
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020013459 while ((i = nextopt("vf")) != 0) {
Eric Andersenc470f442003-07-28 09:56:35 +000013460 flag = i;
Eric Andersencb57d552001-06-28 07:25:16 +000013461 }
Eric Andersencb57d552001-06-28 07:25:16 +000013462
Denis Vlasenko2da584f2007-02-19 22:44:05 +000013463 for (ap = argptr; *ap; ap++) {
Eric Andersenc470f442003-07-28 09:56:35 +000013464 if (flag != 'f') {
Denys Vlasenkob28d4c32017-07-25 16:29:36 +020013465 unsetvar(*ap);
13466 continue;
Eric Andersenc470f442003-07-28 09:56:35 +000013467 }
13468 if (flag != 'v')
Eric Andersencb57d552001-06-28 07:25:16 +000013469 unsetfunc(*ap);
Eric Andersencb57d552001-06-28 07:25:16 +000013470 }
Denys Vlasenkob28d4c32017-07-25 16:29:36 +020013471 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +000013472}
13473
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000013474static const unsigned char timescmd_str[] ALIGN1 = {
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013475 ' ', offsetof(struct tms, tms_utime),
13476 '\n', offsetof(struct tms, tms_stime),
13477 ' ', offsetof(struct tms, tms_cutime),
13478 '\n', offsetof(struct tms, tms_cstime),
13479 0
13480};
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013481static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013482timescmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013483{
Denys Vlasenko11f2e992017-08-10 16:34:03 +020013484 unsigned clk_tck;
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013485 const unsigned char *p;
13486 struct tms buf;
13487
Bartosz Golaszewski5d2e4092014-06-22 14:01:13 +020013488 clk_tck = bb_clk_tck();
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013489
Denys Vlasenko11f2e992017-08-10 16:34:03 +020013490 times(&buf);
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013491 p = timescmd_str;
13492 do {
Denys Vlasenko11f2e992017-08-10 16:34:03 +020013493 unsigned sec, frac;
13494 unsigned long t;
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013495 t = *(clock_t *)(((char *) &buf) + p[1]);
Denys Vlasenko11f2e992017-08-10 16:34:03 +020013496 sec = t / clk_tck;
13497 frac = t % clk_tck;
13498 out1fmt("%um%u.%03us%c",
13499 sec / 60, sec % 60,
13500 (frac * 1000) / clk_tck,
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013501 p[0]);
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020013502 p += 2;
13503 } while (*p);
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013504
Eric Andersencb57d552001-06-28 07:25:16 +000013505 return 0;
13506}
13507
Denys Vlasenko0b883582016-12-23 16:49:07 +010013508#if ENABLE_FEATURE_SH_MATH
Eric Andersenc470f442003-07-28 09:56:35 +000013509/*
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020013510 * The let builtin. Partially stolen from GNU Bash, the Bourne Again SHell.
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +000013511 * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
Eric Andersen90898442003-08-06 11:20:52 +000013512 *
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +000013513 * Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
Eric Andersenc470f442003-07-28 09:56:35 +000013514 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013515static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013516letcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersenc470f442003-07-28 09:56:35 +000013517{
Denis Vlasenko68404f12008-03-17 09:00:54 +000013518 arith_t i;
Eric Andersenc470f442003-07-28 09:56:35 +000013519
Denis Vlasenko68404f12008-03-17 09:00:54 +000013520 argv++;
13521 if (!*argv)
Denis Vlasenkob012b102007-02-19 22:43:01 +000013522 ash_msg_and_raise_error("expression expected");
Denis Vlasenko68404f12008-03-17 09:00:54 +000013523 do {
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +000013524 i = ash_arith(*argv);
Denis Vlasenko68404f12008-03-17 09:00:54 +000013525 } while (*++argv);
Eric Andersenc470f442003-07-28 09:56:35 +000013526
Denis Vlasenkod9e15f22006-11-27 16:49:55 +000013527 return !i;
Eric Andersenc470f442003-07-28 09:56:35 +000013528}
Eric Andersenc470f442003-07-28 09:56:35 +000013529#endif
Eric Andersen74bcd162001-07-30 21:41:37 +000013530
Eric Andersenc470f442003-07-28 09:56:35 +000013531/*
Denis Vlasenko59f351c2008-03-25 00:07:12 +000013532 * The read builtin. Options:
13533 * -r Do not interpret '\' specially
13534 * -s Turn off echo (tty only)
13535 * -n NCHARS Read NCHARS max
13536 * -p PROMPT Display PROMPT on stderr (if input is from tty)
13537 * -t SECONDS Timeout after SECONDS (tty or pipe only)
13538 * -u FD Read from given FD instead of fd 0
Johannes Schindelin3bef5d82017-08-08 16:46:39 +020013539 * -d DELIM End on DELIM char, not newline
Eric Andersenc470f442003-07-28 09:56:35 +000013540 * This uses unbuffered input, which may be avoidable in some cases.
Denis Vlasenko59f351c2008-03-25 00:07:12 +000013541 * TODO: bash also has:
13542 * -a ARRAY Read into array[0],[1],etc
Denis Vlasenko59f351c2008-03-25 00:07:12 +000013543 * -e Use line editing (tty only)
Eric Andersenc470f442003-07-28 09:56:35 +000013544 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013545static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013546readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000013547{
Denys Vlasenko73067272010-01-12 22:11:24 +010013548 char *opt_n = NULL;
13549 char *opt_p = NULL;
13550 char *opt_t = NULL;
13551 char *opt_u = NULL;
Johannes Schindelin3bef5d82017-08-08 16:46:39 +020013552 char *opt_d = NULL; /* optimized out if !BASH */
Denys Vlasenko73067272010-01-12 22:11:24 +010013553 int read_flags = 0;
13554 const char *r;
Eric Andersenc470f442003-07-28 09:56:35 +000013555 int i;
13556
Johannes Schindelin3bef5d82017-08-08 16:46:39 +020013557 while ((i = nextopt("p:u:rt:n:sd:")) != '\0') {
Denis Vlasenkobf0a2012006-12-26 10:42:51 +000013558 switch (i) {
Paul Fox02eb9342005-09-07 16:56:02 +000013559 case 'p':
Denys Vlasenko73067272010-01-12 22:11:24 +010013560 opt_p = optionarg;
Paul Fox02eb9342005-09-07 16:56:02 +000013561 break;
Paul Fox02eb9342005-09-07 16:56:02 +000013562 case 'n':
Denys Vlasenko73067272010-01-12 22:11:24 +010013563 opt_n = optionarg;
Paul Fox02eb9342005-09-07 16:56:02 +000013564 break;
13565 case 's':
Denys Vlasenko73067272010-01-12 22:11:24 +010013566 read_flags |= BUILTIN_READ_SILENT;
Paul Fox02eb9342005-09-07 16:56:02 +000013567 break;
Paul Fox02eb9342005-09-07 16:56:02 +000013568 case 't':
Denys Vlasenko73067272010-01-12 22:11:24 +010013569 opt_t = optionarg;
Paul Fox02eb9342005-09-07 16:56:02 +000013570 break;
Paul Fox02eb9342005-09-07 16:56:02 +000013571 case 'r':
Denys Vlasenko73067272010-01-12 22:11:24 +010013572 read_flags |= BUILTIN_READ_RAW;
Paul Fox02eb9342005-09-07 16:56:02 +000013573 break;
Denis Vlasenko59f351c2008-03-25 00:07:12 +000013574 case 'u':
Denys Vlasenko73067272010-01-12 22:11:24 +010013575 opt_u = optionarg;
Denis Vlasenko59f351c2008-03-25 00:07:12 +000013576 break;
Johannes Schindelin3bef5d82017-08-08 16:46:39 +020013577#if BASH_READ_D
13578 case 'd':
13579 opt_d = optionarg;
13580 break;
13581#endif
Paul Fox02eb9342005-09-07 16:56:02 +000013582 default:
13583 break;
13584 }
Eric Andersenc470f442003-07-28 09:56:35 +000013585 }
Paul Fox02eb9342005-09-07 16:56:02 +000013586
Denys Vlasenko9e71e3c2012-09-06 13:28:10 +020013587 /* "read -s" needs to save/restore termios, can't allow ^C
13588 * to jump out of it.
13589 */
Denys Vlasenkof5470412017-05-22 19:34:45 +020013590 again:
Denys Vlasenko9e71e3c2012-09-06 13:28:10 +020013591 INT_OFF;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020013592 r = shell_builtin_read(setvar0,
Denys Vlasenko73067272010-01-12 22:11:24 +010013593 argptr,
13594 bltinlookup("IFS"), /* can be NULL */
13595 read_flags,
13596 opt_n,
13597 opt_p,
13598 opt_t,
Johannes Schindelin3bef5d82017-08-08 16:46:39 +020013599 opt_u,
13600 opt_d
Denys Vlasenko73067272010-01-12 22:11:24 +010013601 );
Denys Vlasenko9e71e3c2012-09-06 13:28:10 +020013602 INT_ON;
Denis Vlasenko46aeab92009-03-31 19:18:17 +000013603
Denys Vlasenkof5470412017-05-22 19:34:45 +020013604 if ((uintptr_t)r == 1 && errno == EINTR) {
Denys Vlasenko49e6bf22017-08-04 14:28:16 +020013605 /* To get SIGCHLD: sleep 1 & read x; echo $x
13606 * Correct behavior is to not exit "read"
13607 */
Denys Vlasenkof5470412017-05-22 19:34:45 +020013608 if (pending_sig == 0)
13609 goto again;
13610 }
13611
Denys Vlasenko73067272010-01-12 22:11:24 +010013612 if ((uintptr_t)r > 1)
13613 ash_msg_and_raise_error(r);
Denis Vlasenko037576d2007-10-20 18:30:38 +000013614
Denys Vlasenko73067272010-01-12 22:11:24 +010013615 return (uintptr_t)r;
Eric Andersenc470f442003-07-28 09:56:35 +000013616}
13617
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013618static int FAST_FUNC
Denys Vlasenko6283f982015-10-07 16:56:20 +020013619umaskcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000013620{
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013621 static const char permuser[3] ALIGN1 = "ogu";
Eric Andersenc470f442003-07-28 09:56:35 +000013622
Eric Andersenc470f442003-07-28 09:56:35 +000013623 mode_t mask;
Eric Andersenc470f442003-07-28 09:56:35 +000013624 int symbolic_mode = 0;
13625
13626 while (nextopt("S") != '\0') {
13627 symbolic_mode = 1;
13628 }
13629
Denis Vlasenkob012b102007-02-19 22:43:01 +000013630 INT_OFF;
Eric Andersenc470f442003-07-28 09:56:35 +000013631 mask = umask(0);
13632 umask(mask);
Denis Vlasenkob012b102007-02-19 22:43:01 +000013633 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +000013634
Denys Vlasenko6283f982015-10-07 16:56:20 +020013635 if (*argptr == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +000013636 if (symbolic_mode) {
Denys Vlasenko005c4922015-10-10 20:17:12 +020013637 char buf[sizeof(",u=rwx,g=rwx,o=rwx")];
Eric Andersenc470f442003-07-28 09:56:35 +000013638 char *p = buf;
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013639 int i;
Eric Andersenc470f442003-07-28 09:56:35 +000013640
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013641 i = 2;
13642 for (;;) {
Denys Vlasenko005c4922015-10-10 20:17:12 +020013643 *p++ = ',';
Eric Andersenc470f442003-07-28 09:56:35 +000013644 *p++ = permuser[i];
13645 *p++ = '=';
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013646 /* mask is 0..0uuugggooo. i=2 selects uuu bits */
Denys Vlasenko005c4922015-10-10 20:17:12 +020013647 if (!(mask & 0400)) *p++ = 'r';
13648 if (!(mask & 0200)) *p++ = 'w';
13649 if (!(mask & 0100)) *p++ = 'x';
13650 mask <<= 3;
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013651 if (--i < 0)
13652 break;
Eric Andersenc470f442003-07-28 09:56:35 +000013653 }
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013654 *p = '\0';
Denys Vlasenko005c4922015-10-10 20:17:12 +020013655 puts(buf + 1);
Eric Andersenc470f442003-07-28 09:56:35 +000013656 } else {
Denys Vlasenkoec046f72015-10-07 17:57:53 +020013657 out1fmt("%04o\n", mask);
Eric Andersenc470f442003-07-28 09:56:35 +000013658 }
13659 } else {
Denys Vlasenko6283f982015-10-07 16:56:20 +020013660 char *modestr = *argptr;
Denys Vlasenko14c85eb2017-10-12 19:40:47 +020013661 /* numeric umasks are taken as-is */
13662 /* symbolic umasks are inverted: "umask a=rx" calls umask(222) */
Denys Vlasenko6283f982015-10-07 16:56:20 +020013663 if (!isdigit(modestr[0]))
13664 mask ^= 0777;
Denys Vlasenko5711a2a2015-10-07 17:55:33 +020013665 mask = bb_parse_mode(modestr, mask);
13666 if ((unsigned)mask > 0777) {
Denys Vlasenko6283f982015-10-07 16:56:20 +020013667 ash_msg_and_raise_error("illegal mode: %s", modestr);
Eric Andersenc470f442003-07-28 09:56:35 +000013668 }
Denys Vlasenko6283f982015-10-07 16:56:20 +020013669 if (!isdigit(modestr[0]))
13670 mask ^= 0777;
13671 umask(mask);
Eric Andersenc470f442003-07-28 09:56:35 +000013672 }
13673 return 0;
13674}
13675
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013676static int FAST_FUNC
Denys Vlasenkof3c742f2010-03-06 20:12:00 +010013677ulimitcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersenc470f442003-07-28 09:56:35 +000013678{
Denys Vlasenkof3c742f2010-03-06 20:12:00 +010013679 return shell_builtin_ulimit(argv);
Eric Andersenc470f442003-07-28 09:56:35 +000013680}
13681
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013682/* ============ main() and helpers */
13683
13684/*
13685 * Called to exit the shell.
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013686 */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013687static void
13688exitshell(void)
13689{
13690 struct jmploc loc;
13691 char *p;
13692 int status;
13693
Denys Vlasenkobede2152011-09-04 16:12:33 +020013694#if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT
13695 save_history(line_input_state);
13696#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013697 status = exitstatus;
13698 TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
13699 if (setjmp(loc.loc)) {
Denis Vlasenko7f88e342009-03-19 03:36:18 +000013700 if (exception_type == EXEXIT)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013701 status = exitstatus;
13702 goto out;
13703 }
13704 exception_handler = &loc;
13705 p = trap[0];
13706 if (p) {
13707 trap[0] = NULL;
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020013708 evalskip = 0;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013709 evalstring(p, 0);
Denys Vlasenkof37e1152016-10-07 03:17:28 +020013710 /*free(p); - we'll exit soon */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013711 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013712 out:
Denys Vlasenkof37e1152016-10-07 03:17:28 +020013713 /* dash wraps setjobctl(0) in "if (setjmp(loc.loc) == 0) {...}".
13714 * our setjobctl(0) does not panic if tcsetpgrp fails inside it.
13715 */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013716 setjobctl(0);
Denys Vlasenkocaee80c2016-10-25 20:49:53 +020013717 flush_stdout_stderr();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013718 _exit(status);
13719 /* NOTREACHED */
13720}
13721
Denys Vlasenko49e6bf22017-08-04 14:28:16 +020013722/* Don't inline: conserve stack of caller from having our locals too */
13723static NOINLINE void
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +000013724init(void)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013725{
Denys Vlasenko82dd14a2010-05-17 10:10:01 +020013726 /* we will never free this */
13727 basepf.next_to_pgetc = basepf.buf = ckmalloc(IBUFSIZ);
Denys Vlasenko0485b672017-08-14 19:46:56 +020013728 basepf.linno = 1;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013729
Denys Vlasenko49e6bf22017-08-04 14:28:16 +020013730 sigmode[SIGCHLD - 1] = S_DFL; /* ensure we install handler even if it is SIG_IGNed */
Denys Vlasenko458c1f22016-10-27 23:51:19 +020013731 setsignal(SIGCHLD);
13732
Denys Vlasenko7a7b0342009-12-04 04:18:31 +010013733 /* bash re-enables SIGHUP which is SIG_IGNed on entry.
13734 * Try: "trap '' HUP; bash; echo RET" and type "kill -HUP $$"
13735 */
Denys Vlasenkocacb2cd2010-10-05 00:13:02 +020013736 signal(SIGHUP, SIG_DFL);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013737
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013738 {
13739 char **envp;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013740 const char *p;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013741
13742 initvar();
13743 for (envp = environ; envp && *envp; envp++) {
Denys Vlasenko9c143ce2017-11-02 12:56:24 +010013744/* Used to have
13745 * p = endofname(*envp);
13746 * if (p != *envp && *p == '=') {
13747 * here to weed out badly-named variables, but this breaks
13748 * scenarios where people do want them passed to children:
13749 * import os
13750 * os.environ["test-test"]="test"
13751 * if os.fork() == 0:
13752 * os.execv("ash", [ 'ash', '-c', 'eval $(export -p); echo OK' ]) # fixes this
13753 * os.execv("ash", [ 'ash', '-c', 'env | grep test-test' ]) # breaks this
13754 */
13755 if (strchr(*envp, '=')) {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013756 setvareq(*envp, VEXPORT|VTEXTFIXED);
13757 }
13758 }
13759
Denys Vlasenkoe627ac92016-09-30 14:36:59 +020013760 setvareq((char*)defoptindvar, VTEXTFIXED);
13761
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020013762 setvar0("PPID", utoa(getppid()));
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010013763#if BASH_SHLVL_VAR
Bernhard Reutner-Fischer80f8cdf2013-11-08 14:25:24 +010013764 p = lookupvar("SHLVL");
Denys Vlasenko5680e982014-01-07 16:12:48 +010013765 setvar("SHLVL", utoa((p ? atoi(p) : 0) + 1), VEXPORT);
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010013766#endif
13767#if BASH_HOSTNAME_VAR
Denys Vlasenko3fa97af2014-04-15 11:43:29 +020013768 if (!lookupvar("HOSTNAME")) {
13769 struct utsname uts;
13770 uname(&uts);
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020013771 setvar0("HOSTNAME", uts.nodename);
Denys Vlasenko3fa97af2014-04-15 11:43:29 +020013772 }
Bernhard Reutner-Fischer80f8cdf2013-11-08 14:25:24 +010013773#endif
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013774 p = lookupvar("PWD");
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013775 if (p) {
Denys Vlasenko49e6bf22017-08-04 14:28:16 +020013776 struct stat st1, st2;
Denys Vlasenkoef159702016-09-01 11:16:22 +020013777 if (p[0] != '/' || stat(p, &st1) || stat(".", &st2)
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013778 || st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino
13779 ) {
Denys Vlasenkoef159702016-09-01 11:16:22 +020013780 p = NULL;
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013781 }
13782 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013783 setpwd(p, 0);
13784 }
13785}
13786
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013787
13788//usage:#define ash_trivial_usage
Denys Vlasenko6b6af532011-03-08 10:24:17 +010013789//usage: "[-/+OPTIONS] [-/+o OPT]... [-c 'SCRIPT' [ARG0 [ARGS]] / FILE [ARGS]]"
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013790//usage:#define ash_full_usage "\n\n"
13791//usage: "Unix shell interpreter"
13792
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013793/*
13794 * Process the shell command line arguments.
13795 */
Denys Vlasenkoec05df12017-07-31 19:43:47 +020013796static int
Denis Vlasenko68404f12008-03-17 09:00:54 +000013797procargs(char **argv)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013798{
13799 int i;
13800 const char *xminusc;
13801 char **xargv;
Denys Vlasenkoec05df12017-07-31 19:43:47 +020013802 int login_sh;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013803
13804 xargv = argv;
Denys Vlasenkoec05df12017-07-31 19:43:47 +020013805 login_sh = xargv[0] && xargv[0][0] == '-';
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013806 arg0 = xargv[0];
Denis Vlasenko68404f12008-03-17 09:00:54 +000013807 /* if (xargv[0]) - mmm, this is always true! */
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013808 xargv++;
13809 for (i = 0; i < NOPTS; i++)
13810 optlist[i] = 2;
13811 argptr = xargv;
Denys Vlasenkoec05df12017-07-31 19:43:47 +020013812 if (options(/*cmdline:*/ 1, &login_sh)) {
Denis Vlasenko28bf6712008-02-14 15:01:47 +000013813 /* it already printed err message */
13814 raise_exception(EXERROR);
13815 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013816 xargv = argptr;
13817 xminusc = minusc;
13818 if (*xargv == NULL) {
13819 if (xminusc)
13820 ash_msg_and_raise_error(bb_msg_requires_arg, "-c");
13821 sflag = 1;
13822 }
13823 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
13824 iflag = 1;
13825 if (mflag == 2)
13826 mflag = iflag;
13827 for (i = 0; i < NOPTS; i++)
13828 if (optlist[i] == 2)
13829 optlist[i] = 0;
13830#if DEBUG == 2
13831 debug = 1;
13832#endif
Denys Vlasenko5f7c82b2017-02-03 13:00:06 +010013833 /* POSIX 1003.2: first arg after "-c CMD" is $0, remainder $1... */
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013834 if (xminusc) {
13835 minusc = *xargv++;
13836 if (*xargv)
13837 goto setarg0;
13838 } else if (!sflag) {
13839 setinputfile(*xargv, 0);
13840 setarg0:
13841 arg0 = *xargv++;
13842 commandname = arg0;
13843 }
13844
13845 shellparam.p = xargv;
13846#if ENABLE_ASH_GETOPTS
13847 shellparam.optind = 1;
13848 shellparam.optoff = -1;
13849#endif
Denis Vlasenko01631112007-12-16 17:20:38 +000013850 /* assert(shellparam.malloced == 0 && shellparam.nparam == 0); */
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013851 while (*xargv) {
13852 shellparam.nparam++;
13853 xargv++;
13854 }
13855 optschanged();
Denys Vlasenkoec05df12017-07-31 19:43:47 +020013856
13857 return login_sh;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013858}
13859
13860/*
Denys Vlasenko2eb0a7e2016-10-27 11:28:59 +020013861 * Read /etc/profile, ~/.profile, $ENV.
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013862 */
13863static void
13864read_profile(const char *name)
13865{
Denys Vlasenko46999802017-07-29 21:12:29 +020013866 name = expandstr(name, DQSYNTAX);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013867 if (setinputfile(name, INPUT_PUSH_FILE | INPUT_NOFILE_OK) < 0)
13868 return;
Denys Vlasenko0840c912016-10-01 15:27:44 +020013869 cmdloop(0);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013870 popfile();
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013871}
13872
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013873/*
13874 * This routine is called when an error or an interrupt occurs in an
13875 * interactive shell and control is returned to the main command loop.
Denys Vlasenko5ac04f22016-10-27 14:46:50 +020013876 * (In dash, this function is auto-generated by build machinery).
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013877 */
13878static void
13879reset(void)
13880{
13881 /* from eval.c: */
13882 evalskip = 0;
13883 loopnest = 0;
Denys Vlasenko5ac04f22016-10-27 14:46:50 +020013884
13885 /* from expand.c: */
13886 ifsfree();
13887
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013888 /* from input.c: */
Denis Vlasenko41eb3002008-11-28 03:42:31 +000013889 g_parsefile->left_in_buffer = 0;
13890 g_parsefile->left_in_line = 0; /* clear input buffer */
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013891 popallfiles();
Denys Vlasenko5ac04f22016-10-27 14:46:50 +020013892
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013893 /* from redir.c: */
Denys Vlasenko1c79aeb2017-07-29 22:51:52 +020013894 unwindredir(NULL);
Denys Vlasenkob8ab27b2017-07-26 19:22:34 +020013895
13896 /* from var.c: */
Denys Vlasenko484fc202017-07-26 19:55:31 +020013897 unwindlocalvars(NULL);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013898}
13899
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013900#if PROFILE
13901static short profile_buf[16384];
13902extern int etext();
13903#endif
13904
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013905/*
13906 * Main routine. We initialize things, parse the arguments, execute
13907 * profiles if we're a login shell, and then call cmdloop to execute
13908 * commands. The setjmp call sets up the location to jump to when an
13909 * exception occurs. When an exception occurs the variable "state"
13910 * is used to figure out how far we had gotten.
13911 */
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +000013912int ash_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013913int ash_main(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013914{
Denis Vlasenko4e12b1a2008-12-23 23:36:47 +000013915 volatile smallint state;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013916 struct jmploc jmploc;
13917 struct stackmark smark;
Denys Vlasenkoec05df12017-07-31 19:43:47 +020013918 int login_sh;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013919
Denis Vlasenko01631112007-12-16 17:20:38 +000013920 /* Initialize global data */
13921 INIT_G_misc();
13922 INIT_G_memstack();
13923 INIT_G_var();
Denis Vlasenkoee87ebf2007-12-21 22:18:16 +000013924#if ENABLE_ASH_ALIAS
Denis Vlasenko01631112007-12-16 17:20:38 +000013925 INIT_G_alias();
Denis Vlasenkoee87ebf2007-12-21 22:18:16 +000013926#endif
Denis Vlasenko01631112007-12-16 17:20:38 +000013927 INIT_G_cmdtable();
13928
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013929#if PROFILE
13930 monitor(4, etext, profile_buf, sizeof(profile_buf), 50);
13931#endif
13932
13933#if ENABLE_FEATURE_EDITING
13934 line_input_state = new_line_input_t(FOR_SHELL | WITH_PATH_LOOKUP);
13935#endif
13936 state = 0;
13937 if (setjmp(jmploc.loc)) {
Denis Vlasenko7f88e342009-03-19 03:36:18 +000013938 smallint e;
Denis Vlasenko4e12b1a2008-12-23 23:36:47 +000013939 smallint s;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013940
13941 reset();
13942
Denis Vlasenko7f88e342009-03-19 03:36:18 +000013943 e = exception_type;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013944 s = state;
Denys Vlasenkob563f622010-09-25 17:15:13 +020013945 if (e == EXEXIT || s == 0 || iflag == 0 || shlvl) {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013946 exitshell();
Denys Vlasenkob563f622010-09-25 17:15:13 +020013947 }
13948 if (e == EXINT) {
Denys Vlasenko9c541002015-10-07 15:44:36 +020013949 newline_and_flush(stderr);
Denys Vlasenkob563f622010-09-25 17:15:13 +020013950 }
Denis Vlasenko7f88e342009-03-19 03:36:18 +000013951
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013952 popstackmark(&smark);
13953 FORCE_INT_ON; /* enable interrupts */
13954 if (s == 1)
13955 goto state1;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000013956 if (s == 2)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013957 goto state2;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000013958 if (s == 3)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013959 goto state3;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000013960 goto state4;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013961 }
13962 exception_handler = &jmploc;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013963 rootpid = getpid();
13964
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013965 init();
13966 setstackmark(&smark);
Denys Vlasenkoec05df12017-07-31 19:43:47 +020013967 login_sh = procargs(argv);
Denys Vlasenko474ed062016-10-30 18:30:29 +010013968#if DEBUG
13969 TRACE(("Shell args: "));
13970 trace_puts_args(argv);
13971#endif
Denis Vlasenko68404f12008-03-17 09:00:54 +000013972
Denys Vlasenkoec05df12017-07-31 19:43:47 +020013973 if (login_sh) {
Stefan Hellermann4ef14392013-03-15 02:45:50 +010013974 const char *hp;
13975
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013976 state = 1;
13977 read_profile("/etc/profile");
13978 state1:
13979 state = 2;
Stefan Hellermann4ef14392013-03-15 02:45:50 +010013980 hp = lookupvar("HOME");
Denys Vlasenko2eb0a7e2016-10-27 11:28:59 +020013981 if (hp)
13982 read_profile("$HOME/.profile");
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013983 }
13984 state2:
13985 state = 3;
13986 if (
13987#ifndef linux
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013988 getuid() == geteuid() && getgid() == getegid() &&
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013989#endif
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013990 iflag
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013991 ) {
Denys Vlasenko2eb0a7e2016-10-27 11:28:59 +020013992 const char *shinit = lookupvar("ENV");
13993 if (shinit != NULL && *shinit != '\0')
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013994 read_profile(shinit);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013995 }
Denys Vlasenko2eb0a7e2016-10-27 11:28:59 +020013996 popstackmark(&smark);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013997 state3:
13998 state = 4;
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000013999 if (minusc) {
14000 /* evalstring pushes parsefile stack.
14001 * Ensure we don't falsely claim that 0 (stdin)
Denis Vlasenko5368ad52009-03-20 10:20:08 +000014002 * is one of stacked source fds.
14003 * Testcase: ash -c 'exec 1>&0' must not complain. */
Denys Vlasenko79b3d422010-06-03 04:29:08 +020014004 // if (!sflag) g_parsefile->pf_fd = -1;
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +020014005 // ^^ not necessary since now we special-case fd 0
Denys Vlasenko035486c2017-07-31 04:09:19 +020014006 // in save_fd_on_redirect()
Denys Vlasenko1e3e2cc2017-07-25 20:31:14 +020014007 evalstring(minusc, sflag ? 0 : EV_EXIT);
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000014008 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014009
14010 if (sflag || minusc == NULL) {
Denys Vlasenko4840ae82011-09-04 15:28:03 +020014011#if MAX_HISTORY > 0 && ENABLE_FEATURE_EDITING_SAVEHISTORY
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +000014012 if (iflag) {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014013 const char *hp = lookupvar("HISTFILE");
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010014014 if (!hp) {
14015 hp = lookupvar("HOME");
Stefan Hellermann4ef14392013-03-15 02:45:50 +010014016 if (hp) {
Denys Vlasenko5f7c82b2017-02-03 13:00:06 +010014017 INT_OFF;
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010014018 hp = concat_path_file(hp, ".ash_history");
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020014019 setvar0("HISTFILE", hp);
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010014020 free((char*)hp);
Denys Vlasenko5f7c82b2017-02-03 13:00:06 +010014021 INT_ON;
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010014022 hp = lookupvar("HISTFILE");
14023 }
14024 }
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000014025 if (hp)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014026 line_input_state->hist_file = hp;
Denys Vlasenko2c4de5b2011-03-31 13:16:52 +020014027# if ENABLE_FEATURE_SH_HISTFILESIZE
14028 hp = lookupvar("HISTFILESIZE");
14029 line_input_state->max_history = size_from_HISTFILESIZE(hp);
14030# endif
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014031 }
14032#endif
14033 state4: /* XXX ??? - why isn't this before the "if" statement */
14034 cmdloop(1);
14035 }
14036#if PROFILE
14037 monitor(0);
14038#endif
14039#ifdef GPROF
14040 {
14041 extern void _mcleanup(void);
14042 _mcleanup();
14043 }
14044#endif
Denys Vlasenkob563f622010-09-25 17:15:13 +020014045 TRACE(("End of main reached\n"));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014046 exitshell();
14047 /* NOTREACHED */
14048}
14049
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014050
Eric Andersendf82f612001-06-28 07:46:40 +000014051/*-
14052 * Copyright (c) 1989, 1991, 1993, 1994
Eric Andersen2870d962001-07-02 17:27:21 +000014053 * The Regents of the University of California. All rights reserved.
Eric Andersendf82f612001-06-28 07:46:40 +000014054 *
14055 * This code is derived from software contributed to Berkeley by
14056 * Kenneth Almquist.
14057 *
14058 * Redistribution and use in source and binary forms, with or without
14059 * modification, are permitted provided that the following conditions
14060 * are met:
14061 * 1. Redistributions of source code must retain the above copyright
14062 * notice, this list of conditions and the following disclaimer.
14063 * 2. Redistributions in binary form must reproduce the above copyright
14064 * notice, this list of conditions and the following disclaimer in the
14065 * documentation and/or other materials provided with the distribution.
"Vladimir N. Oleynik"ddc280e2005-12-15 12:01:49 +000014066 * 3. Neither the name of the University nor the names of its contributors
Eric Andersendf82f612001-06-28 07:46:40 +000014067 * may be used to endorse or promote products derived from this software
14068 * without specific prior written permission.
14069 *
Denys Vlasenko95f79532017-08-02 14:26:33 +020014070 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND
Eric Andersendf82f612001-06-28 07:46:40 +000014071 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
14072 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
14073 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
14074 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
14075 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
14076 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
14077 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
14078 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
14079 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
14080 * SUCH DAMAGE.
14081 */