blob: 20ed9652c28ea8a562fa8ae8527796dc65ebc739 [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
19//config: bool "ash"
20//config: default y
21//config: depends on !NOMMU
22//config: help
23//config: Tha 'ash' shell adds about 60k in the default configuration and is
24//config: the most complete and most pedantically correct shell included with
25//config: busybox. This shell is actually a derivative of the Debian 'dash'
26//config: shell (by Herbert Xu), which was created by porting the 'ash' shell
27//config: (written by Kenneth Almquist) from NetBSD.
28//config:
Kang-Che Sung6cd02942017-01-06 17:02:03 +010029//config:# ash options
30//config:# note: Don't remove !NOMMU part in the next line; it would break
31//config:# menuconfig's indenting.
32//config:if !NOMMU && (ASH || SH_IS_ASH || BASH_IS_ASH)
33//config:
Denys Vlasenko514b51d2016-10-01 14:33:08 +020034//config:config ASH_OPTIMIZE_FOR_SIZE
35//config: bool "Optimize for size instead of speed"
36//config: default y
Denys Vlasenko0b883582016-12-23 16:49:07 +010037//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
Denys Vlasenko514b51d2016-10-01 14:33:08 +020038//config:
39//config:config ASH_INTERNAL_GLOB
40//config: bool "Use internal glob() implementation"
Denys Vlasenko326edc32016-12-22 14:36:49 +010041//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 +010042//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
Denys Vlasenko514b51d2016-10-01 14:33:08 +020043//config: help
44//config: Do not use glob() function from libc, use internal implementation.
45//config: Use this if you are getting "glob.h: No such file or directory"
46//config: or similar build errors.
Denys Vlasenkof5604222017-01-10 14:58:54 +010047//config: Note that as of now (2017-01), uclibc and musl glob() both have bugs
48//config: which would break ash if you select N here.
49//config:
50//config:config ASH_BASH_COMPAT
51//config: bool "bash-compatible extensions"
52//config: default y
53//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
54//config:
55//config:config ASH_JOB_CONTROL
56//config: bool "Job control"
57//config: default y
58//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
59//config:
60//config:config ASH_ALIAS
61//config: bool "Alias support"
62//config: default y
63//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
Denys Vlasenko514b51d2016-10-01 14:33:08 +020064//config:
65//config:config ASH_RANDOM_SUPPORT
66//config: bool "Pseudorandom generator and $RANDOM variable"
67//config: default y
Denys Vlasenko0b883582016-12-23 16:49:07 +010068//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
Denys Vlasenko514b51d2016-10-01 14:33:08 +020069//config: help
70//config: Enable pseudorandom generator and dynamic variable "$RANDOM".
71//config: Each read of "$RANDOM" will generate a new pseudorandom value.
72//config: You can reset the generator by using a specified start value.
73//config: After "unset RANDOM" the generator will switch off and this
74//config: variable will no longer have special treatment.
75//config:
76//config:config ASH_EXPAND_PRMT
77//config: bool "Expand prompt string"
78//config: default y
Denys Vlasenko0b883582016-12-23 16:49:07 +010079//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
Denys Vlasenko514b51d2016-10-01 14:33:08 +020080//config: help
Denys Vlasenkof5604222017-01-10 14:58:54 +010081//config: $PS# may contain volatile content, such as backquote commands.
Denys Vlasenko514b51d2016-10-01 14:33:08 +020082//config: This option recreates the prompt string from the environment
83//config: variable each time it is displayed.
84//config:
Denys Vlasenko046341e2011-02-04 17:53:59 +010085//config:config ASH_IDLE_TIMEOUT
Denys Vlasenkof5604222017-01-10 14:58:54 +010086//config: bool "Idle timeout variable $TMOUT"
Denys Vlasenko771f1992010-07-16 14:31:34 +020087//config: default y
Denys Vlasenko0b883582016-12-23 16:49:07 +010088//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
Denys Vlasenko771f1992010-07-16 14:31:34 +020089//config: help
Denys Vlasenkof5604222017-01-10 14:58:54 +010090//config: Enable bash-like auto-logout after $TMOUT seconds of idle time.
Denys Vlasenko771f1992010-07-16 14:31:34 +020091//config:
Denys Vlasenkof5604222017-01-10 14:58:54 +010092//config:config ASH_MAIL
93//config: bool "Check for new mail in interactive shell"
Denys Vlasenko771f1992010-07-16 14:31:34 +020094//config: default y
Denys Vlasenko0b883582016-12-23 16:49:07 +010095//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
Denys Vlasenko771f1992010-07-16 14:31:34 +020096//config: help
Denys Vlasenkof5604222017-01-10 14:58:54 +010097//config: Enable "check for new mail" function:
98//config: if set, $MAIL file and $MAILPATH list of files
99//config: are checked for mtime changes, and "you have mail"
100//config: message is printed if change is detected.
Denys Vlasenko771f1992010-07-16 14:31:34 +0200101//config:
102//config:config ASH_BUILTIN_ECHO
Denys Vlasenkof5604222017-01-10 14:58:54 +0100103//config: bool "echo builtin"
Denys Vlasenko771f1992010-07-16 14:31:34 +0200104//config: default y
Denys Vlasenko0b883582016-12-23 16:49:07 +0100105//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
Denys Vlasenko771f1992010-07-16 14:31:34 +0200106//config:
107//config:config ASH_BUILTIN_PRINTF
Denys Vlasenkof5604222017-01-10 14:58:54 +0100108//config: bool "printf builtin"
Denys Vlasenko771f1992010-07-16 14:31:34 +0200109//config: default y
Denys Vlasenko0b883582016-12-23 16:49:07 +0100110//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
Denys Vlasenko771f1992010-07-16 14:31:34 +0200111//config:
112//config:config ASH_BUILTIN_TEST
Denys Vlasenkof5604222017-01-10 14:58:54 +0100113//config: bool "test builtin"
Denys Vlasenko771f1992010-07-16 14:31:34 +0200114//config: default y
Denys Vlasenko0b883582016-12-23 16:49:07 +0100115//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
Denys Vlasenko771f1992010-07-16 14:31:34 +0200116//config:
Denys Vlasenko2ec34962014-09-08 16:52:39 +0200117//config:config ASH_HELP
118//config: bool "help builtin"
119//config: default y
Denys Vlasenko0b883582016-12-23 16:49:07 +0100120//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
Denys Vlasenkof5604222017-01-10 14:58:54 +0100121//config:
122//config:config ASH_GETOPTS
123//config: bool "getopts builtin"
124//config: default y
125//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
Denys Vlasenko2ec34962014-09-08 16:52:39 +0200126//config:
Denys Vlasenko771f1992010-07-16 14:31:34 +0200127//config:config ASH_CMDCMD
Denys Vlasenkof5604222017-01-10 14:58:54 +0100128//config: bool "command builtin"
Denys Vlasenko771f1992010-07-16 14:31:34 +0200129//config: default y
Denys Vlasenko0b883582016-12-23 16:49:07 +0100130//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
Denys Vlasenko771f1992010-07-16 14:31:34 +0200131//config: help
Denys Vlasenkof5604222017-01-10 14:58:54 +0100132//config: Enable support for the 'command' builtin, which allows
133//config: you to run the specified command or builtin,
134//config: even when there is a function with the same name.
Kang-Che Sung6cd02942017-01-06 17:02:03 +0100135//config:
136//config:endif # ash options
Denys Vlasenko771f1992010-07-16 14:31:34 +0200137
Denys Vlasenko20704f02011-03-23 17:59:27 +0100138//applet:IF_ASH(APPLET(ash, BB_DIR_BIN, BB_SUID_DROP))
Denys Vlasenko0b883582016-12-23 16:49:07 +0100139//applet:IF_SH_IS_ASH(APPLET_ODDNAME(sh, ash, BB_DIR_BIN, BB_SUID_DROP, ash))
140//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/*
148 * The following should be set to reflect the type of system you have:
149 * JOBS -> 1 if you have Berkeley job control, 0 otherwise.
150 * define SYSV if you are running under System V.
151 * define DEBUG=1 to compile in debugging ('set -o debug' to turn on)
152 * define DEBUG=2 to compile in and turn on debugging.
153 *
154 * When debugging is on (DEBUG is 1 and "set -o debug" was executed),
155 * debugging info will be written to ./trace and a quit signal
156 * will generate a core dump.
157 */
158#define DEBUG 0
159/* Tweak debug output verbosity here */
160#define DEBUG_TIME 0
161#define DEBUG_PID 1
162#define DEBUG_SIG 1
163#define DEBUG_INTONOFF 0
164
165#define PROFILE 0
166
167#define JOBS ENABLE_ASH_JOB_CONTROL
168
169#include <setjmp.h>
170#include <fnmatch.h>
171#include <sys/times.h>
172#include <sys/utsname.h> /* for setting $HOSTNAME */
173
174#include "busybox.h" /* for applet_names */
175
176#if defined(__ANDROID_API__) && __ANDROID_API__ <= 24
177/* Bionic at least up to version 24 has no glob() */
178# undef ENABLE_ASH_INTERNAL_GLOB
179# define ENABLE_ASH_INTERNAL_GLOB 1
180#endif
181
182#if !ENABLE_ASH_INTERNAL_GLOB && defined(__UCLIBC__)
183# error uClibc glob() is buggy, use ASH_INTERNAL_GLOB.
184# error The bug is: for "$PWD"/<pattern> ash will escape e.g. dashes in "$PWD"
185# error with backslash, even ones which do not need to be: "/a-b" -> "/a\-b"
186# error glob() should unbackslash them and match. uClibc does not unbackslash,
187# error fails to match dirname, subsequently not expanding <pattern> in it.
188// Testcase:
189// if (glob("/etc/polkit\\-1", 0, NULL, &pglob)) - this returns 0 on uclibc, no bug
190// if (glob("/etc/polkit\\-1/*", 0, NULL, &pglob)) printf("uclibc bug!\n");
191#endif
192
193#if !ENABLE_ASH_INTERNAL_GLOB
194# include <glob.h>
195#endif
196
197#include "unicode.h"
198#include "shell_common.h"
Denys Vlasenko0b883582016-12-23 16:49:07 +0100199#if ENABLE_FEATURE_SH_MATH
Denys Vlasenko67047462016-12-22 15:21:58 +0100200# include "math.h"
201#endif
202#if ENABLE_ASH_RANDOM_SUPPORT
203# include "random.h"
204#else
205# define CLEAR_RANDOM_T(rnd) ((void)0)
206#endif
207
208#include "NUM_APPLETS.h"
209#if NUM_APPLETS == 1
210/* STANDALONE does not make sense, and won't compile */
211# undef CONFIG_FEATURE_SH_STANDALONE
212# undef ENABLE_FEATURE_SH_STANDALONE
213# undef IF_FEATURE_SH_STANDALONE
214# undef IF_NOT_FEATURE_SH_STANDALONE
215# define ENABLE_FEATURE_SH_STANDALONE 0
216# define IF_FEATURE_SH_STANDALONE(...)
217# define IF_NOT_FEATURE_SH_STANDALONE(...) __VA_ARGS__
218#endif
219
220#ifndef PIPE_BUF
221# define PIPE_BUF 4096 /* amount of buffering in a pipe */
222#endif
223
224#if !BB_MMU
225# error "Do not even bother, ash will not run on NOMMU machine"
226#endif
227
Denis Vlasenkob012b102007-02-19 22:43:01 +0000228
Denis Vlasenko01631112007-12-16 17:20:38 +0000229/* ============ Hash table sizes. Configurable. */
230
231#define VTABSIZE 39
232#define ATABSIZE 39
233#define CMDTABLESIZE 31 /* should be prime */
234
235
Denis Vlasenkob012b102007-02-19 22:43:01 +0000236/* ============ Shell options */
237
238static const char *const optletters_optnames[] = {
239 "e" "errexit",
240 "f" "noglob",
241 "I" "ignoreeof",
242 "i" "interactive",
243 "m" "monitor",
244 "n" "noexec",
245 "s" "stdin",
246 "x" "xtrace",
247 "v" "verbose",
248 "C" "noclobber",
249 "a" "allexport",
250 "b" "notify",
251 "u" "nounset",
Denys Vlasenkoe9ac32a2009-12-05 02:01:25 +0100252 "\0" "vi"
Michael Abbott359da5e2009-12-04 23:03:29 +0100253#if ENABLE_ASH_BASH_COMPAT
Denys Vlasenkoe9ac32a2009-12-05 02:01:25 +0100254 ,"\0" "pipefail"
Michael Abbott359da5e2009-12-04 23:03:29 +0100255#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +0000256#if DEBUG
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000257 ,"\0" "nolog"
258 ,"\0" "debug"
Denis Vlasenkob012b102007-02-19 22:43:01 +0000259#endif
260};
261
Denys Vlasenko285ad152009-12-04 23:02:27 +0100262#define optletters(n) optletters_optnames[n][0]
263#define optnames(n) (optletters_optnames[n] + 1)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000264
Denis Vlasenko80b8b392007-06-25 10:55:35 +0000265enum { NOPTS = ARRAY_SIZE(optletters_optnames) };
Denis Vlasenkob012b102007-02-19 22:43:01 +0000266
Eric Andersenc470f442003-07-28 09:56:35 +0000267
Denis Vlasenkob012b102007-02-19 22:43:01 +0000268/* ============ Misc data */
Eric Andersenc470f442003-07-28 09:56:35 +0000269
Denys Vlasenkoea8b2522010-06-02 12:57:26 +0200270#define msg_illnum "Illegal number: %s"
Denis Vlasenkoaa744452007-02-23 01:04:22 +0000271
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +0000272/*
Eric Andersenc470f442003-07-28 09:56:35 +0000273 * We enclose jmp_buf in a structure so that we can declare pointers to
274 * jump locations. The global variable handler contains the location to
Denis Vlasenkof1733952009-03-19 23:21:55 +0000275 * jump to when an exception occurs, and the global variable exception_type
Eric Andersenaff114c2004-04-14 17:51:38 +0000276 * contains a code identifying the exception. To implement nested
Eric Andersenc470f442003-07-28 09:56:35 +0000277 * exception handlers, the user should save the value of handler on entry
278 * to an inner scope, set handler to point to a jmploc structure for the
279 * inner scope, and restore handler on exit from the scope.
280 */
Eric Andersenc470f442003-07-28 09:56:35 +0000281struct jmploc {
282 jmp_buf loc;
283};
Denis Vlasenko01631112007-12-16 17:20:38 +0000284
285struct globals_misc {
Denys Vlasenko4d12e942016-10-01 16:03:11 +0200286 uint8_t exitstatus; /* exit status of last command */
287 uint8_t back_exitstatus;/* exit status of backquoted command */
288 smallint job_warning; /* user was warned about stopped jobs (can be 2, 1 or 0). */
289 int rootpid; /* pid of main shell */
Denis Vlasenko01631112007-12-16 17:20:38 +0000290 /* shell level: 0 for the main shell, 1 for its children, and so on */
291 int shlvl;
292#define rootshell (!shlvl)
293 char *minusc; /* argument to -c option */
294
295 char *curdir; // = nullstr; /* current working directory */
296 char *physdir; // = nullstr; /* physical working directory */
297
298 char *arg0; /* value of $0 */
299
300 struct jmploc *exception_handler;
Denis Vlasenko991a1da2008-02-10 19:02:53 +0000301
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200302 volatile int suppress_int; /* counter */
303 volatile /*sig_atomic_t*/ smallint pending_int; /* 1 = got SIGINT */
Denys Vlasenko458c1f22016-10-27 23:51:19 +0200304 volatile /*sig_atomic_t*/ smallint got_sigchld; /* 1 = got SIGCHLD */
Denys Vlasenko8f7b0242016-10-28 17:16:11 +0200305 volatile /*sig_atomic_t*/ smallint pending_sig; /* last pending signal */
Denis Vlasenko7f88e342009-03-19 03:36:18 +0000306 smallint exception_type; /* kind of exception (0..5) */
Denis Vlasenko01631112007-12-16 17:20:38 +0000307 /* exceptions */
Eric Andersenc470f442003-07-28 09:56:35 +0000308#define EXINT 0 /* SIGINT received */
309#define EXERROR 1 /* a generic error */
Eric Andersenc470f442003-07-28 09:56:35 +0000310#define EXEXIT 4 /* exit the shell */
Eric Andersen2870d962001-07-02 17:27:21 +0000311
Denis Vlasenko01631112007-12-16 17:20:38 +0000312 smallint isloginsh;
Denis Vlasenkob07a4962008-06-22 13:16:23 +0000313 char nullstr[1]; /* zero length string */
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000314
315 char optlist[NOPTS];
316#define eflag optlist[0]
317#define fflag optlist[1]
318#define Iflag optlist[2]
319#define iflag optlist[3]
320#define mflag optlist[4]
321#define nflag optlist[5]
322#define sflag optlist[6]
323#define xflag optlist[7]
324#define vflag optlist[8]
325#define Cflag optlist[9]
326#define aflag optlist[10]
327#define bflag optlist[11]
328#define uflag optlist[12]
329#define viflag optlist[13]
Michael Abbott359da5e2009-12-04 23:03:29 +0100330#if ENABLE_ASH_BASH_COMPAT
331# define pipefail optlist[14]
332#else
333# define pipefail 0
334#endif
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000335#if DEBUG
Michael Abbott359da5e2009-12-04 23:03:29 +0100336# define nolog optlist[14 + ENABLE_ASH_BASH_COMPAT]
337# define debug optlist[15 + ENABLE_ASH_BASH_COMPAT]
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000338#endif
339
340 /* trap handler commands */
Denis Vlasenko01631112007-12-16 17:20:38 +0000341 /*
342 * Sigmode records the current value of the signal handlers for the various
343 * modes. A value of zero means that the current handler is not known.
Denis Vlasenkof8535cc2008-12-03 10:36:26 +0000344 * S_HARD_IGN indicates that the signal was ignored on entry to the shell.
Denis Vlasenko01631112007-12-16 17:20:38 +0000345 */
346 char sigmode[NSIG - 1];
Denis Vlasenkof8535cc2008-12-03 10:36:26 +0000347#define S_DFL 1 /* default signal handling (SIG_DFL) */
348#define S_CATCH 2 /* signal is caught */
349#define S_IGN 3 /* signal is ignored (SIG_IGN) */
Denys Vlasenkoe5814a52016-07-16 18:33:55 +0200350#define S_HARD_IGN 4 /* signal is ignored permanently */
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +0000351
Denis Vlasenko01631112007-12-16 17:20:38 +0000352 /* indicates specified signal received */
Denis Vlasenko4b875702009-03-19 13:30:04 +0000353 uint8_t gotsig[NSIG - 1]; /* offset by 1: "signal" 0 is meaningless */
Denys Vlasenko238bf182010-05-18 15:49:07 +0200354 uint8_t may_have_traps; /* 0: definitely no traps are set, 1: some traps may be set */
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000355 char *trap[NSIG];
Denys Vlasenko21d87d42009-09-25 00:06:51 +0200356 char **trap_ptr; /* used only by "trap hack" */
Denis Vlasenko448d30e2008-06-27 00:24:11 +0000357
358 /* Rarely referenced stuff */
359#if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenko3ea2e822009-10-09 20:59:04 +0200360 random_t random_gen;
Denis Vlasenko448d30e2008-06-27 00:24:11 +0000361#endif
362 pid_t backgndpid; /* pid of last background process */
Denis Vlasenko01631112007-12-16 17:20:38 +0000363};
Denis Vlasenko574f2f42008-02-27 18:41:59 +0000364extern struct globals_misc *const ash_ptr_to_globals_misc;
365#define G_misc (*ash_ptr_to_globals_misc)
Denys Vlasenko4d12e942016-10-01 16:03:11 +0200366#define exitstatus (G_misc.exitstatus )
367#define back_exitstatus (G_misc.back_exitstatus )
368#define job_warning (G_misc.job_warning)
Denis Vlasenko26bc57d2008-06-27 00:29:34 +0000369#define rootpid (G_misc.rootpid )
370#define shlvl (G_misc.shlvl )
371#define minusc (G_misc.minusc )
372#define curdir (G_misc.curdir )
373#define physdir (G_misc.physdir )
374#define arg0 (G_misc.arg0 )
Denis Vlasenko01631112007-12-16 17:20:38 +0000375#define exception_handler (G_misc.exception_handler)
Denis Vlasenko7f88e342009-03-19 03:36:18 +0000376#define exception_type (G_misc.exception_type )
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200377#define suppress_int (G_misc.suppress_int )
378#define pending_int (G_misc.pending_int )
Denys Vlasenko458c1f22016-10-27 23:51:19 +0200379#define got_sigchld (G_misc.got_sigchld )
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200380#define pending_sig (G_misc.pending_sig )
Denis Vlasenko26bc57d2008-06-27 00:29:34 +0000381#define isloginsh (G_misc.isloginsh )
382#define nullstr (G_misc.nullstr )
383#define optlist (G_misc.optlist )
384#define sigmode (G_misc.sigmode )
385#define gotsig (G_misc.gotsig )
Denys Vlasenko238bf182010-05-18 15:49:07 +0200386#define may_have_traps (G_misc.may_have_traps )
Denis Vlasenko26bc57d2008-06-27 00:29:34 +0000387#define trap (G_misc.trap )
Denys Vlasenko21d87d42009-09-25 00:06:51 +0200388#define trap_ptr (G_misc.trap_ptr )
Denys Vlasenko3ea2e822009-10-09 20:59:04 +0200389#define random_gen (G_misc.random_gen )
Denis Vlasenko448d30e2008-06-27 00:24:11 +0000390#define backgndpid (G_misc.backgndpid )
Denis Vlasenko01631112007-12-16 17:20:38 +0000391#define INIT_G_misc() do { \
Denis Vlasenko574f2f42008-02-27 18:41:59 +0000392 (*(struct globals_misc**)&ash_ptr_to_globals_misc) = xzalloc(sizeof(G_misc)); \
393 barrier(); \
Denis Vlasenko01631112007-12-16 17:20:38 +0000394 curdir = nullstr; \
395 physdir = nullstr; \
Denys Vlasenko21d87d42009-09-25 00:06:51 +0200396 trap_ptr = trap; \
Denis Vlasenko01631112007-12-16 17:20:38 +0000397} while (0)
398
399
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000400/* ============ DEBUG */
401#if DEBUG
402static void trace_printf(const char *fmt, ...);
403static void trace_vprintf(const char *fmt, va_list va);
404# define TRACE(param) trace_printf param
405# define TRACEV(param) trace_vprintf param
Denis Vlasenko1bb3d7e2009-03-20 07:45:36 +0000406# define close(fd) do { \
407 int dfd = (fd); \
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +0000408 if (close(dfd) < 0) \
Denys Vlasenko883cea42009-07-11 15:31:59 +0200409 bb_error_msg("bug on %d: closing %d(0x%x)", \
Denis Vlasenko1bb3d7e2009-03-20 07:45:36 +0000410 __LINE__, dfd, dfd); \
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +0000411} while (0)
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000412#else
413# define TRACE(param)
414# define TRACEV(param)
415#endif
416
417
Denis Vlasenko559691a2008-10-05 18:39:31 +0000418/* ============ Utility functions */
Denys Vlasenko1961aea2013-02-26 00:36:53 +0100419#define is_name(c) ((c) == '_' || isalpha((unsigned char)(c)))
420#define is_in_name(c) ((c) == '_' || isalnum((unsigned char)(c)))
421
Denys Vlasenko37dc08b2016-10-02 04:38:07 +0200422static int
423isdigit_str9(const char *str)
Denis Vlasenko559691a2008-10-05 18:39:31 +0000424{
425 int maxlen = 9 + 1; /* max 9 digits: 999999999 */
426 while (--maxlen && isdigit(*str))
427 str++;
428 return (*str == '\0');
429}
Denis Vlasenko01631112007-12-16 17:20:38 +0000430
Denys Vlasenko37dc08b2016-10-02 04:38:07 +0200431static const char *
432var_end(const char *var)
Denys Vlasenko8837c5d2010-06-02 12:56:18 +0200433{
434 while (*var)
435 if (*var++ == '=')
436 break;
437 return var;
438}
439
Denis Vlasenko559691a2008-10-05 18:39:31 +0000440
441/* ============ Interrupts / exceptions */
Denys Vlasenko66c5b122011-02-08 05:07:02 +0100442
443static void exitshell(void) NORETURN;
444
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +0000445/*
Eric Andersen2870d962001-07-02 17:27:21 +0000446 * These macros allow the user to suspend the handling of interrupt signals
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +0000447 * over a period of time. This is similar to SIGHOLD or to sigblock, but
Eric Andersen2870d962001-07-02 17:27:21 +0000448 * much more efficient and portable. (But hacking the kernel is so much
449 * more fun than worrying about efficiency and portability. :-))
450 */
Denys Vlasenko06b11492016-11-04 16:43:18 +0100451#if DEBUG_INTONOFF
452# define INT_OFF do { \
453 TRACE(("%s:%d INT_OFF(%d)\n", __func__, __LINE__, suppress_int)); \
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200454 suppress_int++; \
Denys Vlasenkode892052016-10-02 01:49:13 +0200455 barrier(); \
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000456} while (0)
Denys Vlasenko06b11492016-11-04 16:43:18 +0100457#else
458# define INT_OFF do { \
459 suppress_int++; \
460 barrier(); \
461} while (0)
462#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +0000463
464/*
465 * Called to raise an exception. Since C doesn't include exceptions, we
466 * just do a longjmp to the exception handler. The type of exception is
Denis Vlasenko4b875702009-03-19 13:30:04 +0000467 * stored in the global variable "exception_type".
Denis Vlasenkob012b102007-02-19 22:43:01 +0000468 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000469static void raise_exception(int) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +0000470static void
471raise_exception(int e)
472{
473#if DEBUG
Denis Vlasenko2da584f2007-02-19 22:44:05 +0000474 if (exception_handler == NULL)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000475 abort();
476#endif
477 INT_OFF;
Denis Vlasenko7f88e342009-03-19 03:36:18 +0000478 exception_type = e;
Denis Vlasenko2da584f2007-02-19 22:44:05 +0000479 longjmp(exception_handler->loc, 1);
Denis Vlasenkob012b102007-02-19 22:43:01 +0000480}
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000481#if DEBUG
482#define raise_exception(e) do { \
483 TRACE(("raising exception %d on line %d\n", (e), __LINE__)); \
484 raise_exception(e); \
485} while (0)
486#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +0000487
488/*
Denys Vlasenkof37e1152016-10-07 03:17:28 +0200489 * Called when a SIGINT is received. (If the user specifies
Denis Vlasenkob012b102007-02-19 22:43:01 +0000490 * that SIGINT is to be trapped or ignored using the trap builtin, then
491 * this routine is not called.) Suppressint is nonzero when interrupts
492 * are held using the INT_OFF macro. (The test for iflag is just
493 * defensive programming.)
494 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000495static void raise_interrupt(void) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +0000496static void
497raise_interrupt(void)
498{
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200499 pending_int = 0;
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +0000500 /* Signal is not automatically unmasked after it is raised,
501 * do it ourself - unmask all signals */
Denis Vlasenko3f165fa2008-03-17 08:29:08 +0000502 sigprocmask_allsigs(SIG_UNBLOCK);
Denys Vlasenko238bf182010-05-18 15:49:07 +0200503 /* pending_sig = 0; - now done in signal_handler() */
Denis Vlasenko7c139b42007-03-21 20:17:27 +0000504
Denys Vlasenkoc0663c72016-10-27 21:09:01 +0200505 if (!(rootshell && iflag)) {
506 /* Kill ourself with SIGINT */
507 signal(SIGINT, SIG_DFL);
508 raise(SIGINT);
Denis Vlasenkob012b102007-02-19 22:43:01 +0000509 }
Denys Vlasenko4d12e942016-10-01 16:03:11 +0200510 /* bash: ^C even on empty command line sets $? */
511 exitstatus = SIGINT + 128;
Denys Vlasenkoc0663c72016-10-27 21:09:01 +0200512 raise_exception(EXINT);
Denis Vlasenkob012b102007-02-19 22:43:01 +0000513 /* NOTREACHED */
514}
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000515#if DEBUG
516#define raise_interrupt() do { \
517 TRACE(("raising interrupt on line %d\n", __LINE__)); \
518 raise_interrupt(); \
519} while (0)
520#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +0000521
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000522static IF_ASH_OPTIMIZE_FOR_SIZE(inline) void
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000523int_on(void)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000524{
Denys Vlasenkode892052016-10-02 01:49:13 +0200525 barrier();
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200526 if (--suppress_int == 0 && pending_int) {
Denis Vlasenkob012b102007-02-19 22:43:01 +0000527 raise_interrupt();
528 }
529}
Denys Vlasenko06b11492016-11-04 16:43:18 +0100530#if DEBUG_INTONOFF
531# define INT_ON do { \
532 TRACE(("%s:%d INT_ON(%d)\n", __func__, __LINE__, suppress_int-1)); \
533 int_on(); \
534} while (0)
535#else
536# define INT_ON int_on()
537#endif
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000538static IF_ASH_OPTIMIZE_FOR_SIZE(inline) void
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000539force_int_on(void)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000540{
Denys Vlasenkode892052016-10-02 01:49:13 +0200541 barrier();
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200542 suppress_int = 0;
543 if (pending_int)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000544 raise_interrupt();
545}
546#define FORCE_INT_ON force_int_on()
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000547
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200548#define SAVE_INT(v) ((v) = suppress_int)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000549
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000550#define RESTORE_INT(v) do { \
Denys Vlasenkode892052016-10-02 01:49:13 +0200551 barrier(); \
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200552 suppress_int = (v); \
553 if (suppress_int == 0 && pending_int) \
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000554 raise_interrupt(); \
555} while (0)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000556
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000557
Denis Vlasenkobc54cff2007-02-23 01:05:52 +0000558/* ============ Stdout/stderr output */
Eric Andersenc470f442003-07-28 09:56:35 +0000559
Eric Andersenc470f442003-07-28 09:56:35 +0000560static void
Denis Vlasenkob012b102007-02-19 22:43:01 +0000561outstr(const char *p, FILE *file)
Denis Vlasenkoe5570da2007-02-19 22:41:55 +0000562{
Denis Vlasenkob012b102007-02-19 22:43:01 +0000563 INT_OFF;
564 fputs(p, file);
565 INT_ON;
566}
567
568static void
569flush_stdout_stderr(void)
570{
571 INT_OFF;
Denys Vlasenko8131eea2009-11-02 14:19:51 +0100572 fflush_all();
Denis Vlasenkob012b102007-02-19 22:43:01 +0000573 INT_ON;
574}
575
Denys Vlasenko9c541002015-10-07 15:44:36 +0200576/* Was called outcslow(c,FILE*), but c was always '\n' */
Denis Vlasenkob012b102007-02-19 22:43:01 +0000577static void
Denys Vlasenko9c541002015-10-07 15:44:36 +0200578newline_and_flush(FILE *dest)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000579{
580 INT_OFF;
Denys Vlasenko9c541002015-10-07 15:44:36 +0200581 putc('\n', dest);
Denis Vlasenkob012b102007-02-19 22:43:01 +0000582 fflush(dest);
583 INT_ON;
584}
585
586static int out1fmt(const char *, ...) __attribute__((__format__(__printf__,1,2)));
587static int
588out1fmt(const char *fmt, ...)
589{
590 va_list ap;
591 int r;
592
593 INT_OFF;
594 va_start(ap, fmt);
595 r = vprintf(fmt, ap);
596 va_end(ap);
597 INT_ON;
598 return r;
599}
600
601static int fmtstr(char *, size_t, const char *, ...) __attribute__((__format__(__printf__,3,4)));
602static int
603fmtstr(char *outbuf, size_t length, const char *fmt, ...)
604{
605 va_list ap;
606 int ret;
607
608 va_start(ap, fmt);
609 INT_OFF;
610 ret = vsnprintf(outbuf, length, fmt, ap);
611 va_end(ap);
612 INT_ON;
613 return ret;
614}
615
616static void
617out1str(const char *p)
618{
619 outstr(p, stdout);
620}
621
622static void
623out2str(const char *p)
624{
625 outstr(p, stderr);
Denys Vlasenko8131eea2009-11-02 14:19:51 +0100626 flush_stdout_stderr();
Denis Vlasenkob012b102007-02-19 22:43:01 +0000627}
628
629
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +0000630/* ============ Parser structures */
Denis Vlasenko4d2183b2007-02-23 01:05:38 +0000631
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000632/* control characters in argument strings */
Denys Vlasenko2ce42e92009-11-29 02:18:13 +0100633#define CTL_FIRST CTLESC
Denys Vlasenkob6c84342009-08-29 20:23:20 +0200634#define CTLESC ((unsigned char)'\201') /* escape next character */
635#define CTLVAR ((unsigned char)'\202') /* variable defn */
636#define CTLENDVAR ((unsigned char)'\203')
637#define CTLBACKQ ((unsigned char)'\204')
Denys Vlasenkob6c84342009-08-29 20:23:20 +0200638#define CTLARI ((unsigned char)'\206') /* arithmetic expression */
639#define CTLENDARI ((unsigned char)'\207')
640#define CTLQUOTEMARK ((unsigned char)'\210')
Denys Vlasenko2ce42e92009-11-29 02:18:13 +0100641#define CTL_LAST CTLQUOTEMARK
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000642
643/* variable substitution byte (follows CTLVAR) */
644#define VSTYPE 0x0f /* type of variable substitution */
645#define VSNUL 0x10 /* colon--treat the empty string as unset */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000646
647/* values of VSTYPE field */
Denis Vlasenko92e13c22008-03-25 01:17:40 +0000648#define VSNORMAL 0x1 /* normal variable: $var or ${var} */
649#define VSMINUS 0x2 /* ${var-text} */
650#define VSPLUS 0x3 /* ${var+text} */
651#define VSQUESTION 0x4 /* ${var?message} */
652#define VSASSIGN 0x5 /* ${var=text} */
653#define VSTRIMRIGHT 0x6 /* ${var%pattern} */
654#define VSTRIMRIGHTMAX 0x7 /* ${var%%pattern} */
655#define VSTRIMLEFT 0x8 /* ${var#pattern} */
656#define VSTRIMLEFTMAX 0x9 /* ${var##pattern} */
657#define VSLENGTH 0xa /* ${#var} */
658#if ENABLE_ASH_BASH_COMPAT
659#define VSSUBSTR 0xc /* ${var:position:length} */
660#define VSREPLACE 0xd /* ${var/pattern/replacement} */
661#define VSREPLACEALL 0xe /* ${var//pattern/replacement} */
662#endif
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000663
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000664static const char dolatstr[] ALIGN1 = {
Ron Yorston549deab2015-05-18 09:57:51 +0200665 CTLQUOTEMARK, CTLVAR, VSNORMAL, '@', '=', CTLQUOTEMARK, '\0'
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000666};
Ron Yorston549deab2015-05-18 09:57:51 +0200667#define DOLATSTRLEN 6
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +0000668
Denis Vlasenko559691a2008-10-05 18:39:31 +0000669#define NCMD 0
670#define NPIPE 1
671#define NREDIR 2
672#define NBACKGND 3
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000673#define NSUBSHELL 4
Denis Vlasenko559691a2008-10-05 18:39:31 +0000674#define NAND 5
675#define NOR 6
676#define NSEMI 7
677#define NIF 8
678#define NWHILE 9
679#define NUNTIL 10
680#define NFOR 11
681#define NCASE 12
682#define NCLIST 13
683#define NDEFUN 14
684#define NARG 15
685#define NTO 16
686#if ENABLE_ASH_BASH_COMPAT
687#define NTO2 17
688#endif
689#define NCLOBBER 18
690#define NFROM 19
691#define NFROMTO 20
692#define NAPPEND 21
693#define NTOFD 22
694#define NFROMFD 23
695#define NHERE 24
696#define NXHERE 25
697#define NNOT 26
Denis Vlasenko340299a2008-11-21 10:36:36 +0000698#define N_NUMBER 27
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000699
700union node;
701
702struct ncmd {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000703 smallint type; /* Nxxxx */
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000704 union node *assign;
705 union node *args;
706 union node *redirect;
707};
708
709struct npipe {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000710 smallint type;
711 smallint pipe_backgnd;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000712 struct nodelist *cmdlist;
713};
714
715struct nredir {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000716 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000717 union node *n;
718 union node *redirect;
719};
720
721struct nbinary {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000722 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000723 union node *ch1;
724 union node *ch2;
725};
726
727struct nif {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000728 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000729 union node *test;
730 union node *ifpart;
731 union node *elsepart;
732};
733
734struct nfor {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000735 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000736 union node *args;
737 union node *body;
738 char *var;
739};
740
741struct ncase {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000742 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000743 union node *expr;
744 union node *cases;
745};
746
747struct nclist {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000748 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000749 union node *next;
750 union node *pattern;
751 union node *body;
752};
753
754struct narg {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000755 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000756 union node *next;
757 char *text;
758 struct nodelist *backquote;
759};
760
Denis Vlasenko559691a2008-10-05 18:39:31 +0000761/* nfile and ndup layout must match!
762 * NTOFD (>&fdnum) uses ndup structure, but we may discover mid-flight
763 * that it is actually NTO2 (>&file), and change its type.
764 */
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000765struct nfile {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000766 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000767 union node *next;
768 int fd;
Denis Vlasenko559691a2008-10-05 18:39:31 +0000769 int _unused_dupfd;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000770 union node *fname;
771 char *expfname;
772};
773
774struct ndup {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000775 smallint type;
Denis Vlasenko559691a2008-10-05 18:39:31 +0000776 union node *next;
777 int fd;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000778 int dupfd;
779 union node *vname;
Denis Vlasenko559691a2008-10-05 18:39:31 +0000780 char *_unused_expfname;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000781};
782
783struct nhere {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000784 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000785 union node *next;
786 int fd;
787 union node *doc;
788};
789
790struct nnot {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000791 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000792 union node *com;
793};
794
795union node {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000796 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000797 struct ncmd ncmd;
798 struct npipe npipe;
799 struct nredir nredir;
800 struct nbinary nbinary;
801 struct nif nif;
802 struct nfor nfor;
803 struct ncase ncase;
804 struct nclist nclist;
805 struct narg narg;
806 struct nfile nfile;
807 struct ndup ndup;
808 struct nhere nhere;
809 struct nnot nnot;
810};
811
Denys Vlasenko86e83ec2009-07-23 22:07:07 +0200812/*
813 * NODE_EOF is returned by parsecmd when it encounters an end of file.
814 * It must be distinct from NULL.
815 */
816#define NODE_EOF ((union node *) -1L)
817
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000818struct nodelist {
819 struct nodelist *next;
820 union node *n;
821};
822
823struct funcnode {
824 int count;
825 union node n;
826};
827
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000828/*
829 * Free a parse tree.
830 */
831static void
832freefunc(struct funcnode *f)
833{
834 if (f && --f->count < 0)
835 free(f);
836}
837
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000838
839/* ============ Debugging output */
840
841#if DEBUG
842
843static FILE *tracefile;
844
845static void
846trace_printf(const char *fmt, ...)
847{
848 va_list va;
849
850 if (debug != 1)
851 return;
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000852 if (DEBUG_TIME)
853 fprintf(tracefile, "%u ", (int) time(NULL));
854 if (DEBUG_PID)
855 fprintf(tracefile, "[%u] ", (int) getpid());
856 if (DEBUG_SIG)
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200857 fprintf(tracefile, "pending s:%d i:%d(supp:%d) ", pending_sig, pending_int, suppress_int);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000858 va_start(va, fmt);
859 vfprintf(tracefile, fmt, va);
860 va_end(va);
861}
862
863static void
864trace_vprintf(const char *fmt, va_list va)
865{
866 if (debug != 1)
867 return;
868 vfprintf(tracefile, fmt, va);
Denys Vlasenko474ed062016-10-30 18:30:29 +0100869 fprintf(tracefile, "\n");
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000870}
871
872static void
873trace_puts(const char *s)
874{
875 if (debug != 1)
876 return;
877 fputs(s, tracefile);
878}
879
880static void
881trace_puts_quoted(char *s)
882{
883 char *p;
884 char c;
885
886 if (debug != 1)
887 return;
888 putc('"', tracefile);
889 for (p = s; *p; p++) {
Denys Vlasenkocd716832009-11-28 22:14:02 +0100890 switch ((unsigned char)*p) {
891 case '\n': c = 'n'; goto backslash;
892 case '\t': c = 't'; goto backslash;
893 case '\r': c = 'r'; goto backslash;
894 case '\"': c = '\"'; goto backslash;
895 case '\\': c = '\\'; goto backslash;
896 case CTLESC: c = 'e'; goto backslash;
897 case CTLVAR: c = 'v'; goto backslash;
Denys Vlasenkocd716832009-11-28 22:14:02 +0100898 case CTLBACKQ: c = 'q'; goto backslash;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000899 backslash:
900 putc('\\', tracefile);
901 putc(c, tracefile);
902 break;
903 default:
904 if (*p >= ' ' && *p <= '~')
905 putc(*p, tracefile);
906 else {
907 putc('\\', tracefile);
Denys Vlasenkocd716832009-11-28 22:14:02 +0100908 putc((*p >> 6) & 03, tracefile);
909 putc((*p >> 3) & 07, tracefile);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000910 putc(*p & 07, tracefile);
911 }
912 break;
913 }
914 }
915 putc('"', tracefile);
916}
917
918static void
919trace_puts_args(char **ap)
920{
921 if (debug != 1)
922 return;
923 if (!*ap)
924 return;
925 while (1) {
926 trace_puts_quoted(*ap);
927 if (!*++ap) {
928 putc('\n', tracefile);
929 break;
930 }
931 putc(' ', tracefile);
932 }
933}
934
935static void
936opentrace(void)
937{
938 char s[100];
939#ifdef O_APPEND
940 int flags;
941#endif
942
943 if (debug != 1) {
944 if (tracefile)
945 fflush(tracefile);
946 /* leave open because libedit might be using it */
947 return;
948 }
949 strcpy(s, "./trace");
950 if (tracefile) {
951 if (!freopen(s, "a", tracefile)) {
952 fprintf(stderr, "Can't re-open %s\n", s);
953 debug = 0;
954 return;
955 }
956 } else {
957 tracefile = fopen(s, "a");
958 if (tracefile == NULL) {
959 fprintf(stderr, "Can't open %s\n", s);
960 debug = 0;
961 return;
962 }
963 }
964#ifdef O_APPEND
Denis Vlasenkod37f2222007-08-19 13:42:08 +0000965 flags = fcntl(fileno(tracefile), F_GETFL);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000966 if (flags >= 0)
967 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
968#endif
969 setlinebuf(tracefile);
970 fputs("\nTracing started.\n", tracefile);
971}
972
973static void
974indent(int amount, char *pfx, FILE *fp)
975{
976 int i;
977
978 for (i = 0; i < amount; i++) {
979 if (pfx && i == amount - 1)
980 fputs(pfx, fp);
981 putc('\t', fp);
982 }
983}
984
985/* little circular references here... */
986static void shtree(union node *n, int ind, char *pfx, FILE *fp);
987
988static void
989sharg(union node *arg, FILE *fp)
990{
991 char *p;
992 struct nodelist *bqlist;
Denys Vlasenkocd716832009-11-28 22:14:02 +0100993 unsigned char subtype;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000994
995 if (arg->type != NARG) {
996 out1fmt("<node type %d>\n", arg->type);
997 abort();
998 }
999 bqlist = arg->narg.backquote;
1000 for (p = arg->narg.text; *p; p++) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01001001 switch ((unsigned char)*p) {
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001002 case CTLESC:
Dan Fandrich77d48722010-09-07 23:38:28 -07001003 p++;
1004 putc(*p, fp);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001005 break;
1006 case CTLVAR:
1007 putc('$', fp);
1008 putc('{', fp);
1009 subtype = *++p;
1010 if (subtype == VSLENGTH)
1011 putc('#', fp);
1012
Dan Fandrich77d48722010-09-07 23:38:28 -07001013 while (*p != '=') {
1014 putc(*p, fp);
1015 p++;
1016 }
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001017
1018 if (subtype & VSNUL)
1019 putc(':', fp);
1020
1021 switch (subtype & VSTYPE) {
1022 case VSNORMAL:
1023 putc('}', fp);
1024 break;
1025 case VSMINUS:
1026 putc('-', fp);
1027 break;
1028 case VSPLUS:
1029 putc('+', fp);
1030 break;
1031 case VSQUESTION:
1032 putc('?', fp);
1033 break;
1034 case VSASSIGN:
1035 putc('=', fp);
1036 break;
1037 case VSTRIMLEFT:
1038 putc('#', fp);
1039 break;
1040 case VSTRIMLEFTMAX:
1041 putc('#', fp);
1042 putc('#', fp);
1043 break;
1044 case VSTRIMRIGHT:
1045 putc('%', fp);
1046 break;
1047 case VSTRIMRIGHTMAX:
1048 putc('%', fp);
1049 putc('%', fp);
1050 break;
1051 case VSLENGTH:
1052 break;
1053 default:
1054 out1fmt("<subtype %d>", subtype);
1055 }
1056 break;
1057 case CTLENDVAR:
1058 putc('}', fp);
1059 break;
1060 case CTLBACKQ:
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001061 putc('$', fp);
1062 putc('(', fp);
1063 shtree(bqlist->n, -1, NULL, fp);
1064 putc(')', fp);
1065 break;
1066 default:
1067 putc(*p, fp);
1068 break;
1069 }
1070 }
1071}
1072
Denys Vlasenko641dd7b2009-06-11 19:30:19 +02001073static void
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001074shcmd(union node *cmd, FILE *fp)
1075{
1076 union node *np;
1077 int first;
1078 const char *s;
1079 int dftfd;
1080
1081 first = 1;
1082 for (np = cmd->ncmd.args; np; np = np->narg.next) {
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001083 if (!first)
1084 putc(' ', fp);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001085 sharg(np, fp);
1086 first = 0;
1087 }
1088 for (np = cmd->ncmd.redirect; np; np = np->nfile.next) {
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001089 if (!first)
1090 putc(' ', fp);
1091 dftfd = 0;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001092 switch (np->nfile.type) {
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001093 case NTO: s = ">>"+1; dftfd = 1; break;
1094 case NCLOBBER: s = ">|"; dftfd = 1; break;
1095 case NAPPEND: s = ">>"; dftfd = 1; break;
Denis Vlasenko559691a2008-10-05 18:39:31 +00001096#if ENABLE_ASH_BASH_COMPAT
1097 case NTO2:
1098#endif
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001099 case NTOFD: s = ">&"; dftfd = 1; break;
Denis Vlasenko559691a2008-10-05 18:39:31 +00001100 case NFROM: s = "<"; break;
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001101 case NFROMFD: s = "<&"; break;
1102 case NFROMTO: s = "<>"; break;
1103 default: s = "*error*"; break;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001104 }
1105 if (np->nfile.fd != dftfd)
1106 fprintf(fp, "%d", np->nfile.fd);
1107 fputs(s, fp);
1108 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
1109 fprintf(fp, "%d", np->ndup.dupfd);
1110 } else {
1111 sharg(np->nfile.fname, fp);
1112 }
1113 first = 0;
1114 }
1115}
1116
1117static void
1118shtree(union node *n, int ind, char *pfx, FILE *fp)
1119{
1120 struct nodelist *lp;
1121 const char *s;
1122
1123 if (n == NULL)
1124 return;
1125
1126 indent(ind, pfx, fp);
Denys Vlasenko86e83ec2009-07-23 22:07:07 +02001127
1128 if (n == NODE_EOF) {
1129 fputs("<EOF>", fp);
1130 return;
1131 }
1132
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001133 switch (n->type) {
1134 case NSEMI:
1135 s = "; ";
1136 goto binop;
1137 case NAND:
1138 s = " && ";
1139 goto binop;
1140 case NOR:
1141 s = " || ";
1142 binop:
1143 shtree(n->nbinary.ch1, ind, NULL, fp);
1144 /* if (ind < 0) */
1145 fputs(s, fp);
1146 shtree(n->nbinary.ch2, ind, NULL, fp);
1147 break;
1148 case NCMD:
1149 shcmd(n, fp);
1150 if (ind >= 0)
1151 putc('\n', fp);
1152 break;
1153 case NPIPE:
1154 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
Denys Vlasenko7cee00e2009-07-24 01:08:03 +02001155 shtree(lp->n, 0, NULL, fp);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001156 if (lp->next)
1157 fputs(" | ", fp);
1158 }
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00001159 if (n->npipe.pipe_backgnd)
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001160 fputs(" &", fp);
1161 if (ind >= 0)
1162 putc('\n', fp);
1163 break;
1164 default:
1165 fprintf(fp, "<node type %d>", n->type);
1166 if (ind >= 0)
1167 putc('\n', fp);
1168 break;
1169 }
1170}
1171
1172static void
1173showtree(union node *n)
1174{
1175 trace_puts("showtree called\n");
Denys Vlasenko883cea42009-07-11 15:31:59 +02001176 shtree(n, 1, NULL, stderr);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001177}
1178
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001179#endif /* DEBUG */
1180
1181
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00001182/* ============ Parser data */
1183
1184/*
Denis Vlasenkob012b102007-02-19 22:43:01 +00001185 * ash_vmsg() needs parsefile->fd, hence parsefile definition is moved up.
1186 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001187struct strlist {
1188 struct strlist *next;
1189 char *text;
1190};
1191
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001192struct alias;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001193
Denis Vlasenkob012b102007-02-19 22:43:01 +00001194struct strpush {
1195 struct strpush *prev; /* preceding string on stack */
Denis Vlasenko41eb3002008-11-28 03:42:31 +00001196 char *prev_string;
1197 int prev_left_in_line;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001198#if ENABLE_ASH_ALIAS
1199 struct alias *ap; /* if push was associated with an alias */
1200#endif
1201 char *string; /* remember the string since it may change */
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02001202
1203 /* Remember last two characters for pungetc. */
1204 int lastc[2];
1205
1206 /* Number of outstanding calls to pungetc. */
1207 int unget;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001208};
1209
1210struct parsefile {
1211 struct parsefile *prev; /* preceding file on stack */
1212 int linno; /* current line */
Denys Vlasenko79b3d422010-06-03 04:29:08 +02001213 int pf_fd; /* file descriptor (or -1 if string) */
Denis Vlasenko41eb3002008-11-28 03:42:31 +00001214 int left_in_line; /* number of chars left in this line */
1215 int left_in_buffer; /* number of chars left in this buffer past the line */
1216 char *next_to_pgetc; /* next char in buffer */
Denis Vlasenkob012b102007-02-19 22:43:01 +00001217 char *buf; /* input buffer */
1218 struct strpush *strpush; /* for pushing strings at this level */
1219 struct strpush basestrpush; /* so pushing one is fast */
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02001220
1221 /* Remember last two characters for pungetc. */
1222 int lastc[2];
1223
1224 /* Number of outstanding calls to pungetc. */
1225 int unget;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001226};
1227
Denis Vlasenko448d30e2008-06-27 00:24:11 +00001228static struct parsefile basepf; /* top level input file */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00001229static struct parsefile *g_parsefile = &basepf; /* current input file */
Denis Vlasenkob012b102007-02-19 22:43:01 +00001230static int startlinno; /* line # where last token started */
1231static char *commandname; /* currently executing command */
1232static struct strlist *cmdenviron; /* environment for builtin command */
Denis Vlasenkob012b102007-02-19 22:43:01 +00001233
1234
1235/* ============ Message printing */
1236
1237static void
1238ash_vmsg(const char *msg, va_list ap)
1239{
1240 fprintf(stderr, "%s: ", arg0);
1241 if (commandname) {
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00001242 if (strcmp(arg0, commandname))
1243 fprintf(stderr, "%s: ", commandname);
Denys Vlasenko79b3d422010-06-03 04:29:08 +02001244 if (!iflag || g_parsefile->pf_fd > 0)
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00001245 fprintf(stderr, "line %d: ", startlinno);
Eric Andersenc470f442003-07-28 09:56:35 +00001246 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00001247 vfprintf(stderr, msg, ap);
Denys Vlasenko9c541002015-10-07 15:44:36 +02001248 newline_and_flush(stderr);
Eric Andersenc470f442003-07-28 09:56:35 +00001249}
Denis Vlasenkob012b102007-02-19 22:43:01 +00001250
1251/*
1252 * Exverror is called to raise the error exception. If the second argument
1253 * is not NULL then error prints an error message using printf style
1254 * formatting. It then raises the error exception.
1255 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00001256static void ash_vmsg_and_raise(int, const char *, va_list) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001257static void
1258ash_vmsg_and_raise(int cond, const char *msg, va_list ap)
Eric Andersenc470f442003-07-28 09:56:35 +00001259{
Denis Vlasenkob012b102007-02-19 22:43:01 +00001260#if DEBUG
1261 if (msg) {
Denys Vlasenko474ed062016-10-30 18:30:29 +01001262 TRACE(("ash_vmsg_and_raise(%d):", cond));
Denis Vlasenkob012b102007-02-19 22:43:01 +00001263 TRACEV((msg, ap));
Denis Vlasenkob012b102007-02-19 22:43:01 +00001264 } else
Denys Vlasenko474ed062016-10-30 18:30:29 +01001265 TRACE(("ash_vmsg_and_raise(%d):NULL\n", cond));
Denis Vlasenkob012b102007-02-19 22:43:01 +00001266 if (msg)
1267#endif
1268 ash_vmsg(msg, ap);
1269
1270 flush_stdout_stderr();
1271 raise_exception(cond);
1272 /* NOTREACHED */
Eric Andersenc470f442003-07-28 09:56:35 +00001273}
Denis Vlasenkob012b102007-02-19 22:43:01 +00001274
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00001275static void ash_msg_and_raise_error(const char *, ...) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001276static void
1277ash_msg_and_raise_error(const char *msg, ...)
1278{
1279 va_list ap;
1280
Ron Yorstonea7d2f62017-01-03 11:18:23 +01001281 exitstatus = 2;
1282
Denis Vlasenkob012b102007-02-19 22:43:01 +00001283 va_start(ap, msg);
1284 ash_vmsg_and_raise(EXERROR, msg, ap);
1285 /* NOTREACHED */
1286 va_end(ap);
1287}
1288
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00001289static void raise_error_syntax(const char *) NORETURN;
1290static void
1291raise_error_syntax(const char *msg)
1292{
1293 ash_msg_and_raise_error("syntax error: %s", msg);
1294 /* NOTREACHED */
1295}
1296
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00001297static void ash_msg_and_raise(int, const char *, ...) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001298static void
1299ash_msg_and_raise(int cond, const char *msg, ...)
1300{
1301 va_list ap;
1302
1303 va_start(ap, msg);
1304 ash_vmsg_and_raise(cond, msg, ap);
1305 /* NOTREACHED */
1306 va_end(ap);
1307}
1308
1309/*
1310 * error/warning routines for external builtins
1311 */
1312static void
1313ash_msg(const char *fmt, ...)
1314{
1315 va_list ap;
1316
1317 va_start(ap, fmt);
1318 ash_vmsg(fmt, ap);
1319 va_end(ap);
1320}
1321
1322/*
1323 * Return a string describing an error. The returned string may be a
1324 * pointer to a static buffer that will be overwritten on the next call.
1325 * Action describes the operation that got the error.
1326 */
1327static const char *
1328errmsg(int e, const char *em)
1329{
1330 if (e == ENOENT || e == ENOTDIR) {
1331 return em;
1332 }
1333 return strerror(e);
1334}
1335
1336
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001337/* ============ Memory allocation */
1338
Denys Vlasenkoe7670ff2009-10-11 00:45:25 +02001339#if 0
1340/* I consider these wrappers nearly useless:
1341 * ok, they return you to nearest exception handler, but
1342 * how much memory do you leak in the process, making
1343 * memory starvation worse?
1344 */
1345static void *
1346ckrealloc(void * p, size_t nbytes)
1347{
1348 p = realloc(p, nbytes);
1349 if (!p)
1350 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1351 return p;
1352}
1353
1354static void *
1355ckmalloc(size_t nbytes)
1356{
1357 return ckrealloc(NULL, nbytes);
1358}
1359
1360static void *
1361ckzalloc(size_t nbytes)
1362{
1363 return memset(ckmalloc(nbytes), 0, nbytes);
1364}
1365
1366static char *
1367ckstrdup(const char *s)
1368{
1369 char *p = strdup(s);
1370 if (!p)
1371 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1372 return p;
1373}
1374#else
1375/* Using bbox equivalents. They exit if out of memory */
1376# define ckrealloc xrealloc
1377# define ckmalloc xmalloc
1378# define ckzalloc xzalloc
1379# define ckstrdup xstrdup
1380#endif
1381
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001382/*
1383 * It appears that grabstackstr() will barf with such alignments
1384 * because stalloc() will return a string allocated in a new stackblock.
1385 */
1386#define SHELL_ALIGN(nbytes) (((nbytes) + SHELL_SIZE) & ~SHELL_SIZE)
1387enum {
1388 /* Most machines require the value returned from malloc to be aligned
1389 * in some way. The following macro will get this right
1390 * on many machines. */
Denys Vlasenko0e5e4ea2009-10-11 00:36:20 +02001391 SHELL_SIZE = sizeof(union { int i; char *cp; double d; }) - 1,
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001392 /* Minimum size of a block */
Denis Vlasenko01631112007-12-16 17:20:38 +00001393 MINSIZE = SHELL_ALIGN(504),
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001394};
1395
1396struct stack_block {
1397 struct stack_block *prev;
1398 char space[MINSIZE];
1399};
1400
1401struct stackmark {
1402 struct stack_block *stackp;
1403 char *stacknxt;
1404 size_t stacknleft;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001405};
1406
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001407
Denis Vlasenko01631112007-12-16 17:20:38 +00001408struct globals_memstack {
1409 struct stack_block *g_stackp; // = &stackbase;
Denis Vlasenko01631112007-12-16 17:20:38 +00001410 char *g_stacknxt; // = stackbase.space;
1411 char *sstrend; // = stackbase.space + MINSIZE;
1412 size_t g_stacknleft; // = MINSIZE;
Denis Vlasenko01631112007-12-16 17:20:38 +00001413 struct stack_block stackbase;
1414};
Denis Vlasenko574f2f42008-02-27 18:41:59 +00001415extern struct globals_memstack *const ash_ptr_to_globals_memstack;
1416#define G_memstack (*ash_ptr_to_globals_memstack)
Denis Vlasenko01631112007-12-16 17:20:38 +00001417#define g_stackp (G_memstack.g_stackp )
Denis Vlasenko01631112007-12-16 17:20:38 +00001418#define g_stacknxt (G_memstack.g_stacknxt )
1419#define sstrend (G_memstack.sstrend )
1420#define g_stacknleft (G_memstack.g_stacknleft)
Denis Vlasenko01631112007-12-16 17:20:38 +00001421#define stackbase (G_memstack.stackbase )
1422#define INIT_G_memstack() do { \
Denis Vlasenko574f2f42008-02-27 18:41:59 +00001423 (*(struct globals_memstack**)&ash_ptr_to_globals_memstack) = xzalloc(sizeof(G_memstack)); \
1424 barrier(); \
Denis Vlasenko01631112007-12-16 17:20:38 +00001425 g_stackp = &stackbase; \
1426 g_stacknxt = stackbase.space; \
1427 g_stacknleft = MINSIZE; \
1428 sstrend = stackbase.space + MINSIZE; \
Denis Vlasenko01631112007-12-16 17:20:38 +00001429} while (0)
1430
Denys Vlasenkoe7670ff2009-10-11 00:45:25 +02001431
Denis Vlasenko01631112007-12-16 17:20:38 +00001432#define stackblock() ((void *)g_stacknxt)
1433#define stackblocksize() g_stacknleft
1434
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001435/*
1436 * Parse trees for commands are allocated in lifo order, so we use a stack
1437 * to make this more efficient, and also to avoid all sorts of exception
1438 * handling code to handle interrupts in the middle of a parse.
1439 *
1440 * The size 504 was chosen because the Ultrix malloc handles that size
1441 * well.
1442 */
1443static void *
1444stalloc(size_t nbytes)
1445{
1446 char *p;
1447 size_t aligned;
1448
1449 aligned = SHELL_ALIGN(nbytes);
Denis Vlasenko01631112007-12-16 17:20:38 +00001450 if (aligned > g_stacknleft) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001451 size_t len;
1452 size_t blocksize;
1453 struct stack_block *sp;
1454
1455 blocksize = aligned;
1456 if (blocksize < MINSIZE)
1457 blocksize = MINSIZE;
1458 len = sizeof(struct stack_block) - MINSIZE + blocksize;
1459 if (len < blocksize)
1460 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1461 INT_OFF;
1462 sp = ckmalloc(len);
Denis Vlasenko01631112007-12-16 17:20:38 +00001463 sp->prev = g_stackp;
1464 g_stacknxt = sp->space;
1465 g_stacknleft = blocksize;
1466 sstrend = g_stacknxt + blocksize;
1467 g_stackp = sp;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001468 INT_ON;
1469 }
Denis Vlasenko01631112007-12-16 17:20:38 +00001470 p = g_stacknxt;
1471 g_stacknxt += aligned;
1472 g_stacknleft -= aligned;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001473 return p;
1474}
1475
Denis Vlasenko597906c2008-02-20 16:38:54 +00001476static void *
1477stzalloc(size_t nbytes)
1478{
1479 return memset(stalloc(nbytes), 0, nbytes);
1480}
1481
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001482static void
1483stunalloc(void *p)
1484{
1485#if DEBUG
Denis Vlasenko01631112007-12-16 17:20:38 +00001486 if (!p || (g_stacknxt < (char *)p) || ((char *)p < g_stackp->space)) {
Bernhard Reutner-Fischer5e25ddb2008-05-19 09:48:17 +00001487 write(STDERR_FILENO, "stunalloc\n", 10);
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001488 abort();
1489 }
1490#endif
Denis Vlasenko01631112007-12-16 17:20:38 +00001491 g_stacknleft += g_stacknxt - (char *)p;
1492 g_stacknxt = p;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001493}
1494
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001495/*
1496 * Like strdup but works with the ash stack.
1497 */
1498static char *
Denys Vlasenko8e2bc472016-09-28 23:02:57 +02001499sstrdup(const char *p)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001500{
1501 size_t len = strlen(p) + 1;
1502 return memcpy(stalloc(len), p, len);
1503}
1504
Denys Vlasenkoa318bba2016-10-26 18:26:27 +02001505static inline void
Denys Vlasenko60ca8342016-09-30 11:21:21 +02001506grabstackblock(size_t len)
1507{
Denys Vlasenkoa318bba2016-10-26 18:26:27 +02001508 stalloc(len);
Denys Vlasenko60ca8342016-09-30 11:21:21 +02001509}
1510
1511static void
1512pushstackmark(struct stackmark *mark, size_t len)
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001513{
Denis Vlasenko01631112007-12-16 17:20:38 +00001514 mark->stackp = g_stackp;
1515 mark->stacknxt = g_stacknxt;
1516 mark->stacknleft = g_stacknleft;
Denys Vlasenko60ca8342016-09-30 11:21:21 +02001517 grabstackblock(len);
1518}
1519
1520static void
1521setstackmark(struct stackmark *mark)
1522{
1523 pushstackmark(mark, g_stacknxt == g_stackp->space && g_stackp != &stackbase);
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001524}
1525
1526static void
1527popstackmark(struct stackmark *mark)
1528{
1529 struct stack_block *sp;
1530
Denis Vlasenko93ebd4f2007-03-13 20:55:36 +00001531 if (!mark->stackp)
1532 return;
1533
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001534 INT_OFF;
Denis Vlasenko01631112007-12-16 17:20:38 +00001535 while (g_stackp != mark->stackp) {
1536 sp = g_stackp;
1537 g_stackp = sp->prev;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001538 free(sp);
1539 }
Denis Vlasenko01631112007-12-16 17:20:38 +00001540 g_stacknxt = mark->stacknxt;
1541 g_stacknleft = mark->stacknleft;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001542 sstrend = mark->stacknxt + mark->stacknleft;
1543 INT_ON;
1544}
1545
1546/*
1547 * When the parser reads in a string, it wants to stick the string on the
1548 * stack and only adjust the stack pointer when it knows how big the
1549 * string is. Stackblock (defined in stack.h) returns a pointer to a block
1550 * of space on top of the stack and stackblocklen returns the length of
1551 * this block. Growstackblock will grow this space by at least one byte,
1552 * possibly moving it (like realloc). Grabstackblock actually allocates the
1553 * part of the block that has been used.
1554 */
1555static void
1556growstackblock(void)
1557{
1558 size_t newlen;
1559
Denis Vlasenko01631112007-12-16 17:20:38 +00001560 newlen = g_stacknleft * 2;
1561 if (newlen < g_stacknleft)
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001562 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1563 if (newlen < 128)
1564 newlen += 128;
1565
Denis Vlasenko01631112007-12-16 17:20:38 +00001566 if (g_stacknxt == g_stackp->space && g_stackp != &stackbase) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001567 struct stack_block *sp;
1568 struct stack_block *prevstackp;
1569 size_t grosslen;
1570
1571 INT_OFF;
Denis Vlasenko01631112007-12-16 17:20:38 +00001572 sp = g_stackp;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001573 prevstackp = sp->prev;
1574 grosslen = newlen + sizeof(struct stack_block) - MINSIZE;
1575 sp = ckrealloc(sp, grosslen);
1576 sp->prev = prevstackp;
Denis Vlasenko01631112007-12-16 17:20:38 +00001577 g_stackp = sp;
1578 g_stacknxt = sp->space;
1579 g_stacknleft = newlen;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001580 sstrend = sp->space + newlen;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001581 INT_ON;
1582 } else {
Denis Vlasenko01631112007-12-16 17:20:38 +00001583 char *oldspace = g_stacknxt;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001584 size_t oldlen = g_stacknleft;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001585 char *p = stalloc(newlen);
1586
1587 /* free the space we just allocated */
Denis Vlasenko01631112007-12-16 17:20:38 +00001588 g_stacknxt = memcpy(p, oldspace, oldlen);
1589 g_stacknleft += newlen;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001590 }
1591}
1592
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001593/*
1594 * The following routines are somewhat easier to use than the above.
1595 * The user declares a variable of type STACKSTR, which may be declared
1596 * to be a register. The macro STARTSTACKSTR initializes things. Then
1597 * the user uses the macro STPUTC to add characters to the string. In
1598 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
1599 * grown as necessary. When the user is done, she can just leave the
1600 * string there and refer to it using stackblock(). Or she can allocate
1601 * the space for it using grabstackstr(). If it is necessary to allow
1602 * someone else to use the stack temporarily and then continue to grow
1603 * the string, the user should use grabstack to allocate the space, and
1604 * then call ungrabstr(p) to return to the previous mode of operation.
1605 *
1606 * USTPUTC is like STPUTC except that it doesn't check for overflow.
1607 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
1608 * is space for at least one character.
1609 */
1610static void *
1611growstackstr(void)
1612{
1613 size_t len = stackblocksize();
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001614 growstackblock();
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001615 return (char *)stackblock() + len;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001616}
1617
1618/*
1619 * Called from CHECKSTRSPACE.
1620 */
1621static char *
1622makestrspace(size_t newlen, char *p)
1623{
Denis Vlasenko01631112007-12-16 17:20:38 +00001624 size_t len = p - g_stacknxt;
Denys Vlasenko53d6e032016-09-30 11:24:12 +02001625 size_t size;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001626
1627 for (;;) {
1628 size_t nleft;
1629
1630 size = stackblocksize();
1631 nleft = size - len;
1632 if (nleft >= newlen)
1633 break;
1634 growstackblock();
1635 }
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001636 return (char *)stackblock() + len;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001637}
1638
1639static char *
1640stack_nputstr(const char *s, size_t n, char *p)
1641{
1642 p = makestrspace(n, p);
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001643 p = (char *)memcpy(p, s, n) + n;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001644 return p;
1645}
1646
1647static char *
1648stack_putstr(const char *s, char *p)
1649{
1650 return stack_nputstr(s, strlen(s), p);
1651}
1652
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001653static char *
1654_STPUTC(int c, char *p)
1655{
1656 if (p == sstrend)
1657 p = growstackstr();
1658 *p++ = c;
1659 return p;
1660}
1661
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00001662#define STARTSTACKSTR(p) ((p) = stackblock())
1663#define STPUTC(c, p) ((p) = _STPUTC((c), (p)))
Denis Vlasenko843cbd52008-06-27 00:23:18 +00001664#define CHECKSTRSPACE(n, p) do { \
1665 char *q = (p); \
1666 size_t l = (n); \
1667 size_t m = sstrend - q; \
1668 if (l > m) \
1669 (p) = makestrspace(l, q); \
1670} while (0)
Denis Vlasenkoef527f52008-06-23 01:52:30 +00001671#define USTPUTC(c, p) (*(p)++ = (c))
Denis Vlasenko843cbd52008-06-27 00:23:18 +00001672#define STACKSTRNUL(p) do { \
1673 if ((p) == sstrend) \
1674 (p) = growstackstr(); \
1675 *(p) = '\0'; \
1676} while (0)
Denis Vlasenkoef527f52008-06-23 01:52:30 +00001677#define STUNPUTC(p) (--(p))
1678#define STTOPC(p) ((p)[-1])
1679#define STADJUST(amount, p) ((p) += (amount))
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001680
1681#define grabstackstr(p) stalloc((char *)(p) - (char *)stackblock())
Denis Vlasenkoef527f52008-06-23 01:52:30 +00001682#define ungrabstackstr(s, p) stunalloc(s)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001683#define stackstrend() ((void *)sstrend)
1684
1685
1686/* ============ String helpers */
1687
1688/*
1689 * prefix -- see if pfx is a prefix of string.
1690 */
1691static char *
1692prefix(const char *string, const char *pfx)
1693{
1694 while (*pfx) {
1695 if (*pfx++ != *string++)
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00001696 return NULL;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001697 }
1698 return (char *) string;
1699}
1700
1701/*
1702 * Check for a valid number. This should be elsewhere.
1703 */
1704static int
1705is_number(const char *p)
1706{
1707 do {
1708 if (!isdigit(*p))
1709 return 0;
1710 } while (*++p != '\0');
1711 return 1;
1712}
1713
1714/*
1715 * Convert a string of digits to an integer, printing an error message on
1716 * failure.
1717 */
1718static int
1719number(const char *s)
1720{
1721 if (!is_number(s))
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02001722 ash_msg_and_raise_error(msg_illnum, s);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001723 return atoi(s);
1724}
1725
1726/*
1727 * Produce a possibly single quoted string suitable as input to the shell.
1728 * The return string is allocated on the stack.
1729 */
1730static char *
1731single_quote(const char *s)
1732{
1733 char *p;
1734
1735 STARTSTACKSTR(p);
1736
1737 do {
1738 char *q;
1739 size_t len;
1740
1741 len = strchrnul(s, '\'') - s;
1742
1743 q = p = makestrspace(len + 3, p);
1744
1745 *q++ = '\'';
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001746 q = (char *)memcpy(q, s, len) + len;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001747 *q++ = '\'';
1748 s += len;
1749
1750 STADJUST(q - p, p);
1751
Denys Vlasenkocd716832009-11-28 22:14:02 +01001752 if (*s != '\'')
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001753 break;
Denys Vlasenkocd716832009-11-28 22:14:02 +01001754 len = 0;
1755 do len++; while (*++s == '\'');
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001756
1757 q = p = makestrspace(len + 3, p);
1758
1759 *q++ = '"';
Denys Vlasenkocd716832009-11-28 22:14:02 +01001760 q = (char *)memcpy(q, s - len, len) + len;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001761 *q++ = '"';
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001762
1763 STADJUST(q - p, p);
1764 } while (*s);
1765
Denys Vlasenkocd716832009-11-28 22:14:02 +01001766 USTPUTC('\0', p);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001767
1768 return stackblock();
1769}
1770
1771
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00001772/* ============ nextopt */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001773
1774static char **argptr; /* argument list for builtin commands */
1775static char *optionarg; /* set by nextopt (like getopt) */
1776static char *optptr; /* used by nextopt */
1777
1778/*
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001779 * XXX - should get rid of. Have all builtins use getopt(3).
1780 * The library getopt must have the BSD extension static variable
1781 * "optreset", otherwise it can't be used within the shell safely.
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001782 *
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001783 * Standard option processing (a la getopt) for builtin routines.
1784 * The only argument that is passed to nextopt is the option string;
1785 * the other arguments are unnecessary. It returns the character,
1786 * or '\0' on end of input.
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001787 */
1788static int
1789nextopt(const char *optstring)
1790{
1791 char *p;
1792 const char *q;
1793 char c;
1794
1795 p = optptr;
1796 if (p == NULL || *p == '\0') {
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001797 /* We ate entire "-param", take next one */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001798 p = *argptr;
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001799 if (p == NULL)
1800 return '\0';
1801 if (*p != '-')
1802 return '\0';
1803 if (*++p == '\0') /* just "-" ? */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001804 return '\0';
1805 argptr++;
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001806 if (LONE_DASH(p)) /* "--" ? */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001807 return '\0';
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001808 /* p => next "-param" */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001809 }
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001810 /* p => some option char in the middle of a "-param" */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001811 c = *p++;
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +00001812 for (q = optstring; *q != c;) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001813 if (*q == '\0')
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00001814 ash_msg_and_raise_error("illegal option -%c", c);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001815 if (*++q == ':')
1816 q++;
1817 }
1818 if (*++q == ':') {
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001819 if (*p == '\0') {
1820 p = *argptr++;
1821 if (p == NULL)
1822 ash_msg_and_raise_error("no arg for -%c option", c);
1823 }
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001824 optionarg = p;
1825 p = NULL;
1826 }
1827 optptr = p;
1828 return c;
1829}
1830
1831
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00001832/* ============ Shell variables */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001833
Denis Vlasenko01631112007-12-16 17:20:38 +00001834/*
1835 * The parsefile structure pointed to by the global variable parsefile
1836 * contains information about the current file being read.
1837 */
Denis Vlasenko01631112007-12-16 17:20:38 +00001838struct shparam {
1839 int nparam; /* # of positional parameters (without $0) */
1840#if ENABLE_ASH_GETOPTS
1841 int optind; /* next parameter to be processed by getopts */
1842 int optoff; /* used by getopts */
1843#endif
1844 unsigned char malloced; /* if parameter list dynamically allocated */
1845 char **p; /* parameter list */
1846};
1847
1848/*
1849 * Free the list of positional parameters.
1850 */
1851static void
1852freeparam(volatile struct shparam *param)
1853{
Denis Vlasenko01631112007-12-16 17:20:38 +00001854 if (param->malloced) {
Denis Vlasenko3177ba02008-07-13 20:39:23 +00001855 char **ap, **ap1;
1856 ap = ap1 = param->p;
1857 while (*ap)
1858 free(*ap++);
1859 free(ap1);
Denis Vlasenko01631112007-12-16 17:20:38 +00001860 }
1861}
1862
1863#if ENABLE_ASH_GETOPTS
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02001864static void FAST_FUNC getoptsreset(const char *value);
Denis Vlasenko01631112007-12-16 17:20:38 +00001865#endif
1866
1867struct var {
1868 struct var *next; /* next entry in hash list */
1869 int flags; /* flags are defined above */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001870 const char *var_text; /* name=value */
1871 void (*var_func)(const char *) FAST_FUNC; /* function to be called when */
Denis Vlasenko01631112007-12-16 17:20:38 +00001872 /* the variable gets set/unset */
1873};
1874
1875struct localvar {
1876 struct localvar *next; /* next local variable in list */
1877 struct var *vp; /* the variable that was made local */
1878 int flags; /* saved flags */
1879 const char *text; /* saved text */
1880};
1881
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001882/* flags */
1883#define VEXPORT 0x01 /* variable is exported */
1884#define VREADONLY 0x02 /* variable cannot be modified */
1885#define VSTRFIXED 0x04 /* variable struct is statically allocated */
1886#define VTEXTFIXED 0x08 /* text is statically allocated */
1887#define VSTACK 0x10 /* text is allocated on the stack */
1888#define VUNSET 0x20 /* the variable is not set */
1889#define VNOFUNC 0x40 /* don't call the callback function */
1890#define VNOSET 0x80 /* do not set variable - just readonly test */
1891#define VNOSAVE 0x100 /* when text is on the heap before setvareq */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00001892#if ENABLE_ASH_RANDOM_SUPPORT
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00001893# define VDYNAMIC 0x200 /* dynamic variable */
1894#else
1895# define VDYNAMIC 0
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001896#endif
1897
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00001898
Denis Vlasenko01631112007-12-16 17:20:38 +00001899/* Need to be before varinit_data[] */
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00001900#if ENABLE_LOCALE_SUPPORT
Denys Vlasenko2634bf32009-06-09 18:40:07 +02001901static void FAST_FUNC
Denis Vlasenkoa8915072007-02-23 21:10:06 +00001902change_lc_all(const char *value)
1903{
1904 if (value && *value != '\0')
1905 setlocale(LC_ALL, value);
1906}
Denys Vlasenko2634bf32009-06-09 18:40:07 +02001907static void FAST_FUNC
Denis Vlasenkoa8915072007-02-23 21:10:06 +00001908change_lc_ctype(const char *value)
1909{
1910 if (value && *value != '\0')
1911 setlocale(LC_CTYPE, value);
1912}
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00001913#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001914#if ENABLE_ASH_MAIL
1915static void chkmail(void);
Denys Vlasenko8c52f802011-02-04 17:36:21 +01001916static void changemail(const char *var_value) FAST_FUNC;
1917#else
1918# define chkmail() ((void)0)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001919#endif
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02001920static void changepath(const char *) FAST_FUNC;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001921#if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02001922static void change_random(const char *) FAST_FUNC;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001923#endif
1924
Denis Vlasenko01631112007-12-16 17:20:38 +00001925static const struct {
1926 int flags;
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001927 const char *var_text;
1928 void (*var_func)(const char *) FAST_FUNC;
Denis Vlasenko01631112007-12-16 17:20:38 +00001929} varinit_data[] = {
Denys Vlasenko566a3132012-07-07 21:40:35 +02001930 /*
1931 * Note: VEXPORT would not work correctly here for NOFORK applets:
1932 * some environment strings may be constant.
1933 */
Denis Vlasenko01631112007-12-16 17:20:38 +00001934 { VSTRFIXED|VTEXTFIXED , defifsvar , NULL },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001935#if ENABLE_ASH_MAIL
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001936 { VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL" , changemail },
1937 { VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH" , changemail },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001938#endif
Denis Vlasenko01631112007-12-16 17:20:38 +00001939 { VSTRFIXED|VTEXTFIXED , bb_PATH_root_path, changepath },
1940 { VSTRFIXED|VTEXTFIXED , "PS1=$ " , NULL },
1941 { VSTRFIXED|VTEXTFIXED , "PS2=> " , NULL },
1942 { VSTRFIXED|VTEXTFIXED , "PS4=+ " , NULL },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001943#if ENABLE_ASH_GETOPTS
Denys Vlasenkoe627ac92016-09-30 14:36:59 +02001944 { VSTRFIXED|VTEXTFIXED , defoptindvar, getoptsreset },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001945#endif
1946#if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001947 { VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM", change_random },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001948#endif
1949#if ENABLE_LOCALE_SUPPORT
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001950 { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_ALL" , change_lc_all },
1951 { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_CTYPE" , change_lc_ctype },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001952#endif
1953#if ENABLE_FEATURE_EDITING_SAVEHISTORY
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001954 { VSTRFIXED|VTEXTFIXED|VUNSET, "HISTFILE" , NULL },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001955#endif
1956};
1957
Denis Vlasenko0b769642008-07-24 07:54:57 +00001958struct redirtab;
Denis Vlasenko01631112007-12-16 17:20:38 +00001959
1960struct globals_var {
1961 struct shparam shellparam; /* $@ current positional parameters */
1962 struct redirtab *redirlist;
Denis Vlasenko01631112007-12-16 17:20:38 +00001963 int preverrout_fd; /* save fd2 before print debug if xflag is set. */
1964 struct var *vartab[VTABSIZE];
1965 struct var varinit[ARRAY_SIZE(varinit_data)];
1966};
Denis Vlasenko574f2f42008-02-27 18:41:59 +00001967extern struct globals_var *const ash_ptr_to_globals_var;
1968#define G_var (*ash_ptr_to_globals_var)
Denis Vlasenko01631112007-12-16 17:20:38 +00001969#define shellparam (G_var.shellparam )
Denis Vlasenko0b769642008-07-24 07:54:57 +00001970//#define redirlist (G_var.redirlist )
Denis Vlasenko01631112007-12-16 17:20:38 +00001971#define preverrout_fd (G_var.preverrout_fd)
1972#define vartab (G_var.vartab )
1973#define varinit (G_var.varinit )
1974#define INIT_G_var() do { \
Denis Vlasenko6b06cb82008-05-15 21:30:45 +00001975 unsigned i; \
Denis Vlasenko574f2f42008-02-27 18:41:59 +00001976 (*(struct globals_var**)&ash_ptr_to_globals_var) = xzalloc(sizeof(G_var)); \
1977 barrier(); \
Denis Vlasenko01631112007-12-16 17:20:38 +00001978 for (i = 0; i < ARRAY_SIZE(varinit_data); i++) { \
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001979 varinit[i].flags = varinit_data[i].flags; \
1980 varinit[i].var_text = varinit_data[i].var_text; \
1981 varinit[i].var_func = varinit_data[i].var_func; \
Denis Vlasenko01631112007-12-16 17:20:38 +00001982 } \
1983} while (0)
1984
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00001985#define vifs varinit[0]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001986#if ENABLE_ASH_MAIL
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00001987# define vmail (&vifs)[1]
1988# define vmpath (&vmail)[1]
1989# define vpath (&vmpath)[1]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001990#else
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00001991# define vpath (&vifs)[1]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001992#endif
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00001993#define vps1 (&vpath)[1]
1994#define vps2 (&vps1)[1]
1995#define vps4 (&vps2)[1]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001996#if ENABLE_ASH_GETOPTS
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00001997# define voptind (&vps4)[1]
1998# if ENABLE_ASH_RANDOM_SUPPORT
1999# define vrandom (&voptind)[1]
2000# endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002001#else
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002002# if ENABLE_ASH_RANDOM_SUPPORT
2003# define vrandom (&vps4)[1]
2004# endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002005#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002006
2007/*
2008 * The following macros access the values of the above variables.
2009 * They have to skip over the name. They return the null string
2010 * for unset variables.
2011 */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002012#define ifsval() (vifs.var_text + 4)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002013#define ifsset() ((vifs.flags & VUNSET) == 0)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002014#if ENABLE_ASH_MAIL
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002015# define mailval() (vmail.var_text + 5)
2016# define mpathval() (vmpath.var_text + 9)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002017# define mpathset() ((vmpath.flags & VUNSET) == 0)
2018#endif
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002019#define pathval() (vpath.var_text + 5)
2020#define ps1val() (vps1.var_text + 4)
2021#define ps2val() (vps2.var_text + 4)
2022#define ps4val() (vps4.var_text + 4)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002023#if ENABLE_ASH_GETOPTS
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002024# define optindval() (voptind.var_text + 7)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002025#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002026
Denis Vlasenko01631112007-12-16 17:20:38 +00002027#if ENABLE_ASH_GETOPTS
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02002028static void FAST_FUNC
Denis Vlasenko01631112007-12-16 17:20:38 +00002029getoptsreset(const char *value)
2030{
Denys Vlasenkoa513bf32016-10-26 02:03:37 +02002031 shellparam.optind = number(value) ?: 1;
Denis Vlasenko01631112007-12-16 17:20:38 +00002032 shellparam.optoff = -1;
2033}
2034#endif
2035
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002036/*
2037 * Compares two strings up to the first = or '\0'. The first
2038 * string must be terminated by '='; the second may be terminated by
2039 * either '=' or '\0'.
2040 */
2041static int
2042varcmp(const char *p, const char *q)
2043{
2044 int c, d;
2045
2046 while ((c = *p) == (d = *q)) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02002047 if (c == '\0' || c == '=')
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002048 goto out;
2049 p++;
2050 q++;
2051 }
2052 if (c == '=')
Denis Vlasenko9650f362007-02-23 01:04:37 +00002053 c = '\0';
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002054 if (d == '=')
Denis Vlasenko9650f362007-02-23 01:04:37 +00002055 d = '\0';
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002056 out:
2057 return c - d;
2058}
2059
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002060/*
2061 * Find the appropriate entry in the hash table from the name.
2062 */
2063static struct var **
2064hashvar(const char *p)
2065{
2066 unsigned hashval;
2067
2068 hashval = ((unsigned char) *p) << 4;
2069 while (*p && *p != '=')
2070 hashval += (unsigned char) *p++;
2071 return &vartab[hashval % VTABSIZE];
2072}
2073
2074static int
2075vpcmp(const void *a, const void *b)
2076{
2077 return varcmp(*(const char **)a, *(const char **)b);
2078}
2079
2080/*
2081 * This routine initializes the builtin variables.
2082 */
2083static void
2084initvar(void)
2085{
2086 struct var *vp;
2087 struct var *end;
2088 struct var **vpp;
2089
2090 /*
2091 * PS1 depends on uid
2092 */
2093#if ENABLE_FEATURE_EDITING && ENABLE_FEATURE_EDITING_FANCY_PROMPT
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002094 vps1.var_text = "PS1=\\w \\$ ";
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002095#else
2096 if (!geteuid())
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002097 vps1.var_text = "PS1=# ";
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002098#endif
2099 vp = varinit;
Denis Vlasenko80b8b392007-06-25 10:55:35 +00002100 end = vp + ARRAY_SIZE(varinit);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002101 do {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002102 vpp = hashvar(vp->var_text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002103 vp->next = *vpp;
2104 *vpp = vp;
2105 } while (++vp < end);
2106}
2107
2108static struct var **
2109findvar(struct var **vpp, const char *name)
2110{
2111 for (; *vpp; vpp = &(*vpp)->next) {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002112 if (varcmp((*vpp)->var_text, name) == 0) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002113 break;
2114 }
2115 }
2116 return vpp;
2117}
2118
2119/*
2120 * Find the value of a variable. Returns NULL if not set.
2121 */
Denys Vlasenko03dad222010-01-12 23:29:57 +01002122static const char* FAST_FUNC
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002123lookupvar(const char *name)
2124{
2125 struct var *v;
2126
2127 v = *findvar(hashvar(name), name);
2128 if (v) {
Denis Vlasenko448d30e2008-06-27 00:24:11 +00002129#if ENABLE_ASH_RANDOM_SUPPORT
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002130 /*
2131 * Dynamic variables are implemented roughly the same way they are
2132 * in bash. Namely, they're "special" so long as they aren't unset.
2133 * As soon as they're unset, they're no longer dynamic, and dynamic
2134 * lookup will no longer happen at that point. -- PFM.
2135 */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002136 if (v->flags & VDYNAMIC)
2137 v->var_func(NULL);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002138#endif
2139 if (!(v->flags & VUNSET))
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002140 return var_end(v->var_text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002141 }
2142 return NULL;
2143}
2144
Denys Vlasenko0b883582016-12-23 16:49:07 +01002145#if ENABLE_UNICODE_SUPPORT
Denys Vlasenko37dc08b2016-10-02 04:38:07 +02002146static void
2147reinit_unicode_for_ash(void)
Denys Vlasenkoe9ab07c2014-08-13 18:00:08 +02002148{
2149 /* Unicode support should be activated even if LANG is set
2150 * _during_ shell execution, not only if it was set when
2151 * shell was started. Therefore, re-check LANG every time:
2152 */
2153 if (ENABLE_FEATURE_CHECK_UNICODE_IN_ENV
2154 || ENABLE_UNICODE_USING_LOCALE
2155 ) {
2156 const char *s = lookupvar("LC_ALL");
2157 if (!s) s = lookupvar("LC_CTYPE");
2158 if (!s) s = lookupvar("LANG");
2159 reinit_unicode(s);
2160 }
2161}
Denys Vlasenko0b883582016-12-23 16:49:07 +01002162#else
2163# define reinit_unicode_for_ash() ((void)0)
2164#endif
Denys Vlasenkoe9ab07c2014-08-13 18:00:08 +02002165
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002166/*
2167 * Search the environment of a builtin command.
2168 */
Mike Frysinger98c52642009-04-02 10:02:37 +00002169static const char *
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002170bltinlookup(const char *name)
2171{
2172 struct strlist *sp;
2173
2174 for (sp = cmdenviron; sp; sp = sp->next) {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002175 if (varcmp(sp->text, name) == 0)
2176 return var_end(sp->text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002177 }
2178 return lookupvar(name);
2179}
2180
2181/*
2182 * Same as setvar except that the variable and value are passed in
2183 * the first argument as name=value. Since the first argument will
2184 * be actually stored in the table, it should not be a string that
2185 * will go away.
2186 * Called with interrupts off.
2187 */
2188static void
2189setvareq(char *s, int flags)
2190{
2191 struct var *vp, **vpp;
2192
2193 vpp = hashvar(s);
2194 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
2195 vp = *findvar(vpp, s);
2196 if (vp) {
2197 if ((vp->flags & (VREADONLY|VDYNAMIC)) == VREADONLY) {
2198 const char *n;
2199
2200 if (flags & VNOSAVE)
2201 free(s);
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002202 n = vp->var_text;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +02002203 exitstatus = 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002204 ash_msg_and_raise_error("%.*s: is read only", strchrnul(n, '=') - n, n);
2205 }
2206
2207 if (flags & VNOSET)
2208 return;
2209
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002210 if (vp->var_func && !(flags & VNOFUNC))
2211 vp->var_func(var_end(s));
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002212
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002213 if (!(vp->flags & (VTEXTFIXED|VSTACK)))
2214 free((char*)vp->var_text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002215
2216 flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
2217 } else {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002218 /* variable s is not found */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002219 if (flags & VNOSET)
2220 return;
Denis Vlasenko597906c2008-02-20 16:38:54 +00002221 vp = ckzalloc(sizeof(*vp));
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002222 vp->next = *vpp;
Denis Vlasenko597906c2008-02-20 16:38:54 +00002223 /*vp->func = NULL; - ckzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002224 *vpp = vp;
2225 }
2226 if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE)))
2227 s = ckstrdup(s);
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002228 vp->var_text = s;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002229 vp->flags = flags;
2230}
2231
2232/*
2233 * Set the value of a variable. The flags argument is ored with the
2234 * flags of the variable. If val is NULL, the variable is unset.
2235 */
2236static void
2237setvar(const char *name, const char *val, int flags)
2238{
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002239 const char *q;
2240 char *p;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002241 char *nameeq;
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002242 size_t namelen;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002243 size_t vallen;
2244
2245 q = endofname(name);
2246 p = strchrnul(q, '=');
2247 namelen = p - name;
2248 if (!namelen || p != q)
2249 ash_msg_and_raise_error("%.*s: bad variable name", namelen, name);
2250 vallen = 0;
2251 if (val == NULL) {
2252 flags |= VUNSET;
2253 } else {
2254 vallen = strlen(val);
2255 }
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002256
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002257 INT_OFF;
2258 nameeq = ckmalloc(namelen + vallen + 2);
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002259 p = memcpy(nameeq, name, namelen) + namelen;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002260 if (val) {
2261 *p++ = '=';
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002262 p = memcpy(p, val, vallen) + vallen;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002263 }
2264 *p = '\0';
2265 setvareq(nameeq, flags | VNOSAVE);
2266 INT_ON;
2267}
2268
Denys Vlasenko03dad222010-01-12 23:29:57 +01002269static void FAST_FUNC
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02002270setvar0(const char *name, const char *val)
Denys Vlasenko03dad222010-01-12 23:29:57 +01002271{
2272 setvar(name, val, 0);
2273}
2274
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002275/*
2276 * Unset the specified variable.
2277 */
2278static int
2279unsetvar(const char *s)
2280{
2281 struct var **vpp;
2282 struct var *vp;
2283 int retval;
2284
2285 vpp = findvar(hashvar(s), s);
2286 vp = *vpp;
2287 retval = 2;
2288 if (vp) {
2289 int flags = vp->flags;
2290
2291 retval = 1;
2292 if (flags & VREADONLY)
2293 goto out;
Denis Vlasenko448d30e2008-06-27 00:24:11 +00002294#if ENABLE_ASH_RANDOM_SUPPORT
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002295 vp->flags &= ~VDYNAMIC;
2296#endif
2297 if (flags & VUNSET)
2298 goto ok;
2299 if ((flags & VSTRFIXED) == 0) {
2300 INT_OFF;
2301 if ((flags & (VTEXTFIXED|VSTACK)) == 0)
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002302 free((char*)vp->var_text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002303 *vpp = vp->next;
2304 free(vp);
2305 INT_ON;
2306 } else {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02002307 setvar0(s, NULL);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002308 vp->flags &= ~VEXPORT;
2309 }
2310 ok:
2311 retval = 0;
2312 }
2313 out:
2314 return retval;
2315}
2316
2317/*
2318 * Process a linked list of variable assignments.
2319 */
2320static void
2321listsetvar(struct strlist *list_set_var, int flags)
2322{
2323 struct strlist *lp = list_set_var;
2324
2325 if (!lp)
2326 return;
2327 INT_OFF;
2328 do {
2329 setvareq(lp->text, flags);
Denis Vlasenko9650f362007-02-23 01:04:37 +00002330 lp = lp->next;
2331 } while (lp);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002332 INT_ON;
2333}
2334
2335/*
2336 * Generate a list of variables satisfying the given conditions.
2337 */
2338static char **
2339listvars(int on, int off, char ***end)
2340{
2341 struct var **vpp;
2342 struct var *vp;
2343 char **ep;
2344 int mask;
2345
2346 STARTSTACKSTR(ep);
2347 vpp = vartab;
2348 mask = on | off;
2349 do {
2350 for (vp = *vpp; vp; vp = vp->next) {
2351 if ((vp->flags & mask) == on) {
2352 if (ep == stackstrend())
2353 ep = growstackstr();
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002354 *ep++ = (char*)vp->var_text;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002355 }
2356 }
2357 } while (++vpp < vartab + VTABSIZE);
2358 if (ep == stackstrend())
2359 ep = growstackstr();
2360 if (end)
2361 *end = ep;
2362 *ep++ = NULL;
2363 return grabstackstr(ep);
2364}
2365
2366
2367/* ============ Path search helper
2368 *
2369 * The variable path (passed by reference) should be set to the start
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002370 * of the path before the first call; path_advance will update
2371 * this value as it proceeds. Successive calls to path_advance will return
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002372 * the possible path expansions in sequence. If an option (indicated by
2373 * a percent sign) appears in the path entry then the global variable
2374 * pathopt will be set to point to it; otherwise pathopt will be set to
2375 * NULL.
2376 */
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002377static const char *pathopt; /* set by path_advance */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002378
2379static char *
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002380path_advance(const char **path, const char *name)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002381{
2382 const char *p;
2383 char *q;
2384 const char *start;
2385 size_t len;
2386
2387 if (*path == NULL)
2388 return NULL;
2389 start = *path;
Denis Vlasenkof7d56652008-03-25 05:51:41 +00002390 for (p = start; *p && *p != ':' && *p != '%'; p++)
2391 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002392 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
2393 while (stackblocksize() < len)
2394 growstackblock();
2395 q = stackblock();
2396 if (p != start) {
2397 memcpy(q, start, p - start);
2398 q += p - start;
2399 *q++ = '/';
2400 }
2401 strcpy(q, name);
2402 pathopt = NULL;
2403 if (*p == '%') {
2404 pathopt = ++p;
Denis Vlasenkof7d56652008-03-25 05:51:41 +00002405 while (*p && *p != ':')
2406 p++;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002407 }
2408 if (*p == ':')
2409 *path = p + 1;
2410 else
2411 *path = NULL;
2412 return stalloc(len);
2413}
2414
2415
2416/* ============ Prompt */
2417
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +00002418static smallint doprompt; /* if set, prompt the user */
2419static smallint needprompt; /* true if interactive and at start of line */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002420
2421#if ENABLE_FEATURE_EDITING
2422static line_input_t *line_input_state;
2423static const char *cmdedit_prompt;
2424static void
2425putprompt(const char *s)
2426{
2427 if (ENABLE_ASH_EXPAND_PRMT) {
2428 free((char*)cmdedit_prompt);
Denis Vlasenko4222ae42007-02-25 02:37:49 +00002429 cmdedit_prompt = ckstrdup(s);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002430 return;
2431 }
2432 cmdedit_prompt = s;
2433}
2434#else
2435static void
2436putprompt(const char *s)
2437{
2438 out2str(s);
2439}
2440#endif
2441
2442#if ENABLE_ASH_EXPAND_PRMT
2443/* expandstr() needs parsing machinery, so it is far away ahead... */
2444static const char *expandstr(const char *ps);
2445#else
2446#define expandstr(s) s
2447#endif
2448
2449static void
Denys Vlasenko958581a2010-09-12 15:04:27 +02002450setprompt_if(smallint do_set, int whichprompt)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002451{
2452 const char *prompt;
Denys Vlasenko958581a2010-09-12 15:04:27 +02002453 IF_ASH_EXPAND_PRMT(struct stackmark smark;)
2454
2455 if (!do_set)
2456 return;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002457
2458 needprompt = 0;
2459
2460 switch (whichprompt) {
2461 case 1:
2462 prompt = ps1val();
2463 break;
2464 case 2:
2465 prompt = ps2val();
2466 break;
2467 default: /* 0 */
2468 prompt = nullstr;
2469 }
2470#if ENABLE_ASH_EXPAND_PRMT
Denys Vlasenko60ca8342016-09-30 11:21:21 +02002471 pushstackmark(&smark, stackblocksize());
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002472#endif
2473 putprompt(expandstr(prompt));
2474#if ENABLE_ASH_EXPAND_PRMT
2475 popstackmark(&smark);
2476#endif
2477}
2478
2479
2480/* ============ The cd and pwd commands */
2481
2482#define CD_PHYSICAL 1
2483#define CD_PRINT 2
2484
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002485static int
2486cdopt(void)
2487{
2488 int flags = 0;
2489 int i, j;
2490
2491 j = 'L';
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02002492 while ((i = nextopt("LP")) != '\0') {
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002493 if (i != j) {
2494 flags ^= CD_PHYSICAL;
2495 j = i;
2496 }
2497 }
2498
2499 return flags;
2500}
2501
2502/*
2503 * Update curdir (the name of the current directory) in response to a
2504 * cd command.
2505 */
2506static const char *
2507updatepwd(const char *dir)
2508{
2509 char *new;
2510 char *p;
2511 char *cdcomppath;
2512 const char *lim;
2513
Denys Vlasenko8e2bc472016-09-28 23:02:57 +02002514 cdcomppath = sstrdup(dir);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002515 STARTSTACKSTR(new);
2516 if (*dir != '/') {
2517 if (curdir == nullstr)
2518 return 0;
2519 new = stack_putstr(curdir, new);
2520 }
2521 new = makestrspace(strlen(dir) + 2, new);
Denis Vlasenko29eb3592008-05-18 14:06:08 +00002522 lim = (char *)stackblock() + 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002523 if (*dir != '/') {
2524 if (new[-1] != '/')
2525 USTPUTC('/', new);
2526 if (new > lim && *lim == '/')
2527 lim++;
2528 } else {
2529 USTPUTC('/', new);
2530 cdcomppath++;
2531 if (dir[1] == '/' && dir[2] != '/') {
2532 USTPUTC('/', new);
2533 cdcomppath++;
2534 lim++;
2535 }
2536 }
2537 p = strtok(cdcomppath, "/");
2538 while (p) {
2539 switch (*p) {
2540 case '.':
2541 if (p[1] == '.' && p[2] == '\0') {
2542 while (new > lim) {
2543 STUNPUTC(new);
2544 if (new[-1] == '/')
2545 break;
2546 }
2547 break;
Denis Vlasenko16abcd92007-04-13 23:59:52 +00002548 }
2549 if (p[1] == '\0')
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002550 break;
2551 /* fall through */
2552 default:
2553 new = stack_putstr(p, new);
2554 USTPUTC('/', new);
2555 }
Denys Vlasenko00da72b2015-10-23 18:43:16 +02002556 p = strtok(NULL, "/");
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002557 }
2558 if (new > lim)
2559 STUNPUTC(new);
2560 *new = 0;
2561 return stackblock();
2562}
2563
2564/*
2565 * Find out what the current directory is. If we already know the current
2566 * directory, this routine returns immediately.
2567 */
2568static char *
2569getpwd(void)
2570{
Denis Vlasenko01631112007-12-16 17:20:38 +00002571 char *dir = getcwd(NULL, 0); /* huh, using glibc extension? */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002572 return dir ? dir : nullstr;
2573}
2574
2575static void
2576setpwd(const char *val, int setold)
2577{
2578 char *oldcur, *dir;
2579
2580 oldcur = dir = curdir;
2581
2582 if (setold) {
2583 setvar("OLDPWD", oldcur, VEXPORT);
2584 }
2585 INT_OFF;
2586 if (physdir != nullstr) {
2587 if (physdir != oldcur)
2588 free(physdir);
2589 physdir = nullstr;
2590 }
2591 if (oldcur == val || !val) {
2592 char *s = getpwd();
2593 physdir = s;
2594 if (!val)
2595 dir = s;
2596 } else
2597 dir = ckstrdup(val);
2598 if (oldcur != dir && oldcur != nullstr) {
2599 free(oldcur);
2600 }
2601 curdir = dir;
2602 INT_ON;
2603 setvar("PWD", dir, VEXPORT);
2604}
2605
2606static void hashcd(void);
2607
2608/*
Denys Vlasenko70392332016-10-27 02:31:55 +02002609 * Actually do the chdir. We also call hashcd to let other routines
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002610 * know that the current directory has changed.
2611 */
2612static int
2613docd(const char *dest, int flags)
2614{
Denys Vlasenko4b1100e2010-03-05 14:10:54 +01002615 const char *dir = NULL;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002616 int err;
2617
2618 TRACE(("docd(\"%s\", %d) called\n", dest, flags));
2619
2620 INT_OFF;
2621 if (!(flags & CD_PHYSICAL)) {
2622 dir = updatepwd(dest);
2623 if (dir)
2624 dest = dir;
2625 }
2626 err = chdir(dest);
2627 if (err)
2628 goto out;
2629 setpwd(dir, 1);
2630 hashcd();
2631 out:
2632 INT_ON;
2633 return err;
2634}
2635
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02002636static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00002637cdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002638{
2639 const char *dest;
2640 const char *path;
2641 const char *p;
2642 char c;
2643 struct stat statb;
2644 int flags;
2645
2646 flags = cdopt();
2647 dest = *argptr;
2648 if (!dest)
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02002649 dest = bltinlookup("HOME");
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002650 else if (LONE_DASH(dest)) {
2651 dest = bltinlookup("OLDPWD");
2652 flags |= CD_PRINT;
2653 }
2654 if (!dest)
2655 dest = nullstr;
2656 if (*dest == '/')
Denys Vlasenko0e081d02016-10-26 19:56:05 +02002657 goto step6;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002658 if (*dest == '.') {
2659 c = dest[1];
2660 dotdot:
2661 switch (c) {
2662 case '\0':
2663 case '/':
2664 goto step6;
2665 case '.':
2666 c = dest[2];
2667 if (c != '.')
2668 goto dotdot;
2669 }
2670 }
2671 if (!*dest)
2672 dest = ".";
2673 path = bltinlookup("CDPATH");
Denys Vlasenko0e081d02016-10-26 19:56:05 +02002674 while (path) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002675 c = *path;
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002676 p = path_advance(&path, dest);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002677 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
2678 if (c && c != ':')
2679 flags |= CD_PRINT;
2680 docd:
2681 if (!docd(p, flags))
2682 goto out;
Denys Vlasenko0e081d02016-10-26 19:56:05 +02002683 goto err;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002684 }
Denys Vlasenko0e081d02016-10-26 19:56:05 +02002685 }
2686
2687 step6:
2688 p = dest;
2689 goto docd;
2690
2691 err:
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002692 ash_msg_and_raise_error("can't cd to %s", dest);
2693 /* NOTREACHED */
2694 out:
2695 if (flags & CD_PRINT)
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02002696 out1fmt("%s\n", curdir);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002697 return 0;
2698}
2699
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02002700static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00002701pwdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002702{
2703 int flags;
2704 const char *dir = curdir;
2705
2706 flags = cdopt();
2707 if (flags) {
2708 if (physdir == nullstr)
2709 setpwd(dir, 0);
2710 dir = physdir;
2711 }
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02002712 out1fmt("%s\n", dir);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002713 return 0;
2714}
2715
Denis Vlasenko0c032a42007-02-23 01:03:40 +00002716
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00002717/* ============ ... */
Eric Andersenc470f442003-07-28 09:56:35 +00002718
Denis Vlasenko834dee72008-10-07 09:18:30 +00002719
Denys Vlasenko82dd14a2010-05-17 10:10:01 +02002720#define IBUFSIZ (ENABLE_FEATURE_EDITING ? CONFIG_FEATURE_EDITING_MAX_LEN : 1024)
Eric Andersenc470f442003-07-28 09:56:35 +00002721
Eric Andersenc470f442003-07-28 09:56:35 +00002722/* Syntax classes */
Denis Vlasenko834dee72008-10-07 09:18:30 +00002723#define CWORD 0 /* character is nothing special */
2724#define CNL 1 /* newline character */
2725#define CBACK 2 /* a backslash character */
2726#define CSQUOTE 3 /* single quote */
2727#define CDQUOTE 4 /* double quote */
Eric Andersenc470f442003-07-28 09:56:35 +00002728#define CENDQUOTE 5 /* a terminating quote */
Denis Vlasenko834dee72008-10-07 09:18:30 +00002729#define CBQUOTE 6 /* backwards single quote */
2730#define CVAR 7 /* a dollar sign */
2731#define CENDVAR 8 /* a '}' character */
2732#define CLP 9 /* a left paren in arithmetic */
2733#define CRP 10 /* a right paren in arithmetic */
Eric Andersenc470f442003-07-28 09:56:35 +00002734#define CENDFILE 11 /* end of file */
Denis Vlasenko834dee72008-10-07 09:18:30 +00002735#define CCTL 12 /* like CWORD, except it must be escaped */
2736#define CSPCL 13 /* these terminate a word */
2737#define CIGN 14 /* character should be ignored */
Eric Andersenc470f442003-07-28 09:56:35 +00002738
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002739#define PEOF 256
Denis Vlasenko131ae172007-02-18 13:00:19 +00002740#if ENABLE_ASH_ALIAS
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002741# define PEOA 257
Eric Andersenc470f442003-07-28 09:56:35 +00002742#endif
2743
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002744#define USE_SIT_FUNCTION ENABLE_ASH_OPTIMIZE_FOR_SIZE
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002745
Denys Vlasenko0b883582016-12-23 16:49:07 +01002746#if ENABLE_FEATURE_SH_MATH
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002747# define SIT_ITEM(a,b,c,d) (a | (b << 4) | (c << 8) | (d << 12))
Eric Andersenc470f442003-07-28 09:56:35 +00002748#else
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002749# define SIT_ITEM(a,b,c,d) (a | (b << 4) | (c << 8))
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002750#endif
Denys Vlasenko3e134eb2016-04-22 18:09:21 +02002751static const uint16_t S_I_T[] ALIGN2 = {
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002752#if ENABLE_ASH_ALIAS
2753 SIT_ITEM(CSPCL , CIGN , CIGN , CIGN ), /* 0, PEOA */
2754#endif
2755 SIT_ITEM(CSPCL , CWORD , CWORD, CWORD ), /* 1, ' ' */
2756 SIT_ITEM(CNL , CNL , CNL , CNL ), /* 2, \n */
2757 SIT_ITEM(CWORD , CCTL , CCTL , CWORD ), /* 3, !*-/:=?[]~ */
2758 SIT_ITEM(CDQUOTE , CENDQUOTE, CWORD, CWORD ), /* 4, '"' */
2759 SIT_ITEM(CVAR , CVAR , CWORD, CVAR ), /* 5, $ */
2760 SIT_ITEM(CSQUOTE , CWORD , CENDQUOTE, CWORD), /* 6, "'" */
2761 SIT_ITEM(CSPCL , CWORD , CWORD, CLP ), /* 7, ( */
2762 SIT_ITEM(CSPCL , CWORD , CWORD, CRP ), /* 8, ) */
2763 SIT_ITEM(CBACK , CBACK , CCTL , CBACK ), /* 9, \ */
2764 SIT_ITEM(CBQUOTE , CBQUOTE , CWORD, CBQUOTE), /* 10, ` */
2765 SIT_ITEM(CENDVAR , CENDVAR , CWORD, CENDVAR), /* 11, } */
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002766#if !USE_SIT_FUNCTION
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002767 SIT_ITEM(CENDFILE, CENDFILE , CENDFILE, CENDFILE),/* 12, PEOF */
2768 SIT_ITEM(CWORD , CWORD , CWORD, CWORD ), /* 13, 0-9A-Za-z */
2769 SIT_ITEM(CCTL , CCTL , CCTL , CCTL ) /* 14, CTLESC ... */
2770#endif
2771#undef SIT_ITEM
Eric Andersenc470f442003-07-28 09:56:35 +00002772};
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002773/* Constants below must match table above */
2774enum {
2775#if ENABLE_ASH_ALIAS
2776 CSPCL_CIGN_CIGN_CIGN , /* 0 */
2777#endif
2778 CSPCL_CWORD_CWORD_CWORD , /* 1 */
2779 CNL_CNL_CNL_CNL , /* 2 */
2780 CWORD_CCTL_CCTL_CWORD , /* 3 */
2781 CDQUOTE_CENDQUOTE_CWORD_CWORD , /* 4 */
2782 CVAR_CVAR_CWORD_CVAR , /* 5 */
2783 CSQUOTE_CWORD_CENDQUOTE_CWORD , /* 6 */
2784 CSPCL_CWORD_CWORD_CLP , /* 7 */
2785 CSPCL_CWORD_CWORD_CRP , /* 8 */
2786 CBACK_CBACK_CCTL_CBACK , /* 9 */
2787 CBQUOTE_CBQUOTE_CWORD_CBQUOTE , /* 10 */
2788 CENDVAR_CENDVAR_CWORD_CENDVAR , /* 11 */
2789 CENDFILE_CENDFILE_CENDFILE_CENDFILE, /* 12 */
2790 CWORD_CWORD_CWORD_CWORD , /* 13 */
2791 CCTL_CCTL_CCTL_CCTL , /* 14 */
2792};
Eric Andersen2870d962001-07-02 17:27:21 +00002793
Denys Vlasenkocd716832009-11-28 22:14:02 +01002794/* c in SIT(c, syntax) must be an *unsigned char* or PEOA or PEOF,
2795 * caller must ensure proper cast on it if c is *char_ptr!
2796 */
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002797/* Values for syntax param */
2798#define BASESYNTAX 0 /* not in quotes */
2799#define DQSYNTAX 1 /* in double quotes */
2800#define SQSYNTAX 2 /* in single quotes */
2801#define ARISYNTAX 3 /* in arithmetic */
2802#define PSSYNTAX 4 /* prompt. never passed to SIT() */
Denys Vlasenkocd716832009-11-28 22:14:02 +01002803
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002804#if USE_SIT_FUNCTION
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002805
Denis Vlasenko0c032a42007-02-23 01:03:40 +00002806static int
2807SIT(int c, int syntax)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002808{
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02002809 /* Used to also have '/' in this string: "\t\n !\"$&'()*-/:;<=>?[\\]`|}~" */
2810 static const char spec_symbls[] ALIGN1 = "\t\n !\"$&'()*-:;<=>?[\\]`|}~";
2811 /*
2812 * This causes '/' to be prepended with CTLESC in dquoted string,
2813 * making "./file"* treated incorrectly because we feed
2814 * ".\/file*" string to glob(), confusing it (see expandmeta func).
2815 * The "homegrown" glob implementation is okay with that,
2816 * but glibc one isn't. With '/' always treated as CWORD,
2817 * both work fine.
2818 */
Denys Vlasenkocd716832009-11-28 22:14:02 +01002819# if ENABLE_ASH_ALIAS
2820 static const uint8_t syntax_index_table[] ALIGN1 = {
Eric Andersenc470f442003-07-28 09:56:35 +00002821 1, 2, 1, 3, 4, 5, 1, 6, /* "\t\n !\"$&'" */
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02002822 7, 8, 3, 3,/*3,*/3, 1, 1, /* "()*-/:;<" */
Eric Andersenc470f442003-07-28 09:56:35 +00002823 3, 1, 3, 3, 9, 3, 10, 1, /* "=>?[\\]`|" */
2824 11, 3 /* "}~" */
2825 };
Denys Vlasenkocd716832009-11-28 22:14:02 +01002826# else
2827 static const uint8_t syntax_index_table[] ALIGN1 = {
Eric Andersenc470f442003-07-28 09:56:35 +00002828 0, 1, 0, 2, 3, 4, 0, 5, /* "\t\n !\"$&'" */
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02002829 6, 7, 2, 2,/*2,*/2, 0, 0, /* "()*-/:;<" */
Eric Andersenc470f442003-07-28 09:56:35 +00002830 2, 0, 2, 2, 8, 2, 9, 0, /* "=>?[\\]`|" */
2831 10, 2 /* "}~" */
2832 };
Denys Vlasenkocd716832009-11-28 22:14:02 +01002833# endif
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002834 const char *s;
2835 int indx;
2836
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002837 if (c == PEOF)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002838 return CENDFILE;
Denys Vlasenkocd716832009-11-28 22:14:02 +01002839# if ENABLE_ASH_ALIAS
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002840 if (c == PEOA)
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002841 indx = 0;
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002842 else
Denys Vlasenkocd716832009-11-28 22:14:02 +01002843# endif
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002844 {
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002845 /* Cast is purely for paranoia here,
2846 * just in case someone passed signed char to us */
2847 if ((unsigned char)c >= CTL_FIRST
2848 && (unsigned char)c <= CTL_LAST
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002849 ) {
2850 return CCTL;
2851 }
2852 s = strchrnul(spec_symbls, c);
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002853 if (*s == '\0')
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002854 return CWORD;
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002855 indx = syntax_index_table[s - spec_symbls];
2856 }
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002857 return (S_I_T[indx] >> (syntax*4)) & 0xf;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002858}
2859
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00002860#else /* !USE_SIT_FUNCTION */
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002861
Denys Vlasenko3e134eb2016-04-22 18:09:21 +02002862static const uint8_t syntax_index_table[] ALIGN1 = {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002863 /* BASESYNTAX_DQSYNTAX_SQSYNTAX_ARISYNTAX */
Denys Vlasenkocd716832009-11-28 22:14:02 +01002864 /* 0 */ CWORD_CWORD_CWORD_CWORD,
2865 /* 1 */ CWORD_CWORD_CWORD_CWORD,
2866 /* 2 */ CWORD_CWORD_CWORD_CWORD,
2867 /* 3 */ CWORD_CWORD_CWORD_CWORD,
2868 /* 4 */ CWORD_CWORD_CWORD_CWORD,
2869 /* 5 */ CWORD_CWORD_CWORD_CWORD,
2870 /* 6 */ CWORD_CWORD_CWORD_CWORD,
2871 /* 7 */ CWORD_CWORD_CWORD_CWORD,
2872 /* 8 */ CWORD_CWORD_CWORD_CWORD,
2873 /* 9 "\t" */ CSPCL_CWORD_CWORD_CWORD,
2874 /* 10 "\n" */ CNL_CNL_CNL_CNL,
2875 /* 11 */ CWORD_CWORD_CWORD_CWORD,
2876 /* 12 */ CWORD_CWORD_CWORD_CWORD,
2877 /* 13 */ CWORD_CWORD_CWORD_CWORD,
2878 /* 14 */ CWORD_CWORD_CWORD_CWORD,
2879 /* 15 */ CWORD_CWORD_CWORD_CWORD,
2880 /* 16 */ CWORD_CWORD_CWORD_CWORD,
2881 /* 17 */ CWORD_CWORD_CWORD_CWORD,
2882 /* 18 */ CWORD_CWORD_CWORD_CWORD,
2883 /* 19 */ CWORD_CWORD_CWORD_CWORD,
2884 /* 20 */ CWORD_CWORD_CWORD_CWORD,
2885 /* 21 */ CWORD_CWORD_CWORD_CWORD,
2886 /* 22 */ CWORD_CWORD_CWORD_CWORD,
2887 /* 23 */ CWORD_CWORD_CWORD_CWORD,
2888 /* 24 */ CWORD_CWORD_CWORD_CWORD,
2889 /* 25 */ CWORD_CWORD_CWORD_CWORD,
2890 /* 26 */ CWORD_CWORD_CWORD_CWORD,
2891 /* 27 */ CWORD_CWORD_CWORD_CWORD,
2892 /* 28 */ CWORD_CWORD_CWORD_CWORD,
2893 /* 29 */ CWORD_CWORD_CWORD_CWORD,
2894 /* 30 */ CWORD_CWORD_CWORD_CWORD,
2895 /* 31 */ CWORD_CWORD_CWORD_CWORD,
2896 /* 32 " " */ CSPCL_CWORD_CWORD_CWORD,
2897 /* 33 "!" */ CWORD_CCTL_CCTL_CWORD,
2898 /* 34 """ */ CDQUOTE_CENDQUOTE_CWORD_CWORD,
2899 /* 35 "#" */ CWORD_CWORD_CWORD_CWORD,
2900 /* 36 "$" */ CVAR_CVAR_CWORD_CVAR,
2901 /* 37 "%" */ CWORD_CWORD_CWORD_CWORD,
2902 /* 38 "&" */ CSPCL_CWORD_CWORD_CWORD,
2903 /* 39 "'" */ CSQUOTE_CWORD_CENDQUOTE_CWORD,
2904 /* 40 "(" */ CSPCL_CWORD_CWORD_CLP,
2905 /* 41 ")" */ CSPCL_CWORD_CWORD_CRP,
2906 /* 42 "*" */ CWORD_CCTL_CCTL_CWORD,
2907 /* 43 "+" */ CWORD_CWORD_CWORD_CWORD,
2908 /* 44 "," */ CWORD_CWORD_CWORD_CWORD,
2909 /* 45 "-" */ CWORD_CCTL_CCTL_CWORD,
2910 /* 46 "." */ CWORD_CWORD_CWORD_CWORD,
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02002911/* "/" was CWORD_CCTL_CCTL_CWORD, see comment in SIT() function why this is changed: */
2912 /* 47 "/" */ CWORD_CWORD_CWORD_CWORD,
Denys Vlasenkocd716832009-11-28 22:14:02 +01002913 /* 48 "0" */ CWORD_CWORD_CWORD_CWORD,
2914 /* 49 "1" */ CWORD_CWORD_CWORD_CWORD,
2915 /* 50 "2" */ CWORD_CWORD_CWORD_CWORD,
2916 /* 51 "3" */ CWORD_CWORD_CWORD_CWORD,
2917 /* 52 "4" */ CWORD_CWORD_CWORD_CWORD,
2918 /* 53 "5" */ CWORD_CWORD_CWORD_CWORD,
2919 /* 54 "6" */ CWORD_CWORD_CWORD_CWORD,
2920 /* 55 "7" */ CWORD_CWORD_CWORD_CWORD,
2921 /* 56 "8" */ CWORD_CWORD_CWORD_CWORD,
2922 /* 57 "9" */ CWORD_CWORD_CWORD_CWORD,
2923 /* 58 ":" */ CWORD_CCTL_CCTL_CWORD,
2924 /* 59 ";" */ CSPCL_CWORD_CWORD_CWORD,
2925 /* 60 "<" */ CSPCL_CWORD_CWORD_CWORD,
2926 /* 61 "=" */ CWORD_CCTL_CCTL_CWORD,
2927 /* 62 ">" */ CSPCL_CWORD_CWORD_CWORD,
2928 /* 63 "?" */ CWORD_CCTL_CCTL_CWORD,
2929 /* 64 "@" */ CWORD_CWORD_CWORD_CWORD,
2930 /* 65 "A" */ CWORD_CWORD_CWORD_CWORD,
2931 /* 66 "B" */ CWORD_CWORD_CWORD_CWORD,
2932 /* 67 "C" */ CWORD_CWORD_CWORD_CWORD,
2933 /* 68 "D" */ CWORD_CWORD_CWORD_CWORD,
2934 /* 69 "E" */ CWORD_CWORD_CWORD_CWORD,
2935 /* 70 "F" */ CWORD_CWORD_CWORD_CWORD,
2936 /* 71 "G" */ CWORD_CWORD_CWORD_CWORD,
2937 /* 72 "H" */ CWORD_CWORD_CWORD_CWORD,
2938 /* 73 "I" */ CWORD_CWORD_CWORD_CWORD,
2939 /* 74 "J" */ CWORD_CWORD_CWORD_CWORD,
2940 /* 75 "K" */ CWORD_CWORD_CWORD_CWORD,
2941 /* 76 "L" */ CWORD_CWORD_CWORD_CWORD,
2942 /* 77 "M" */ CWORD_CWORD_CWORD_CWORD,
2943 /* 78 "N" */ CWORD_CWORD_CWORD_CWORD,
2944 /* 79 "O" */ CWORD_CWORD_CWORD_CWORD,
2945 /* 80 "P" */ CWORD_CWORD_CWORD_CWORD,
2946 /* 81 "Q" */ CWORD_CWORD_CWORD_CWORD,
2947 /* 82 "R" */ CWORD_CWORD_CWORD_CWORD,
2948 /* 83 "S" */ CWORD_CWORD_CWORD_CWORD,
2949 /* 84 "T" */ CWORD_CWORD_CWORD_CWORD,
2950 /* 85 "U" */ CWORD_CWORD_CWORD_CWORD,
2951 /* 86 "V" */ CWORD_CWORD_CWORD_CWORD,
2952 /* 87 "W" */ CWORD_CWORD_CWORD_CWORD,
2953 /* 88 "X" */ CWORD_CWORD_CWORD_CWORD,
2954 /* 89 "Y" */ CWORD_CWORD_CWORD_CWORD,
2955 /* 90 "Z" */ CWORD_CWORD_CWORD_CWORD,
2956 /* 91 "[" */ CWORD_CCTL_CCTL_CWORD,
2957 /* 92 "\" */ CBACK_CBACK_CCTL_CBACK,
2958 /* 93 "]" */ CWORD_CCTL_CCTL_CWORD,
2959 /* 94 "^" */ CWORD_CWORD_CWORD_CWORD,
2960 /* 95 "_" */ CWORD_CWORD_CWORD_CWORD,
2961 /* 96 "`" */ CBQUOTE_CBQUOTE_CWORD_CBQUOTE,
2962 /* 97 "a" */ CWORD_CWORD_CWORD_CWORD,
2963 /* 98 "b" */ CWORD_CWORD_CWORD_CWORD,
2964 /* 99 "c" */ CWORD_CWORD_CWORD_CWORD,
2965 /* 100 "d" */ CWORD_CWORD_CWORD_CWORD,
2966 /* 101 "e" */ CWORD_CWORD_CWORD_CWORD,
2967 /* 102 "f" */ CWORD_CWORD_CWORD_CWORD,
2968 /* 103 "g" */ CWORD_CWORD_CWORD_CWORD,
2969 /* 104 "h" */ CWORD_CWORD_CWORD_CWORD,
2970 /* 105 "i" */ CWORD_CWORD_CWORD_CWORD,
2971 /* 106 "j" */ CWORD_CWORD_CWORD_CWORD,
2972 /* 107 "k" */ CWORD_CWORD_CWORD_CWORD,
2973 /* 108 "l" */ CWORD_CWORD_CWORD_CWORD,
2974 /* 109 "m" */ CWORD_CWORD_CWORD_CWORD,
2975 /* 110 "n" */ CWORD_CWORD_CWORD_CWORD,
2976 /* 111 "o" */ CWORD_CWORD_CWORD_CWORD,
2977 /* 112 "p" */ CWORD_CWORD_CWORD_CWORD,
2978 /* 113 "q" */ CWORD_CWORD_CWORD_CWORD,
2979 /* 114 "r" */ CWORD_CWORD_CWORD_CWORD,
2980 /* 115 "s" */ CWORD_CWORD_CWORD_CWORD,
2981 /* 116 "t" */ CWORD_CWORD_CWORD_CWORD,
2982 /* 117 "u" */ CWORD_CWORD_CWORD_CWORD,
2983 /* 118 "v" */ CWORD_CWORD_CWORD_CWORD,
2984 /* 119 "w" */ CWORD_CWORD_CWORD_CWORD,
2985 /* 120 "x" */ CWORD_CWORD_CWORD_CWORD,
2986 /* 121 "y" */ CWORD_CWORD_CWORD_CWORD,
2987 /* 122 "z" */ CWORD_CWORD_CWORD_CWORD,
2988 /* 123 "{" */ CWORD_CWORD_CWORD_CWORD,
2989 /* 124 "|" */ CSPCL_CWORD_CWORD_CWORD,
2990 /* 125 "}" */ CENDVAR_CENDVAR_CWORD_CENDVAR,
2991 /* 126 "~" */ CWORD_CCTL_CCTL_CWORD,
2992 /* 127 del */ CWORD_CWORD_CWORD_CWORD,
2993 /* 128 0x80 */ CWORD_CWORD_CWORD_CWORD,
2994 /* 129 CTLESC */ CCTL_CCTL_CCTL_CCTL,
2995 /* 130 CTLVAR */ CCTL_CCTL_CCTL_CCTL,
2996 /* 131 CTLENDVAR */ CCTL_CCTL_CCTL_CCTL,
2997 /* 132 CTLBACKQ */ CCTL_CCTL_CCTL_CCTL,
2998 /* 133 CTLQUOTE */ CCTL_CCTL_CCTL_CCTL,
2999 /* 134 CTLARI */ CCTL_CCTL_CCTL_CCTL,
3000 /* 135 CTLENDARI */ CCTL_CCTL_CCTL_CCTL,
3001 /* 136 CTLQUOTEMARK */ CCTL_CCTL_CCTL_CCTL,
3002 /* 137 */ CWORD_CWORD_CWORD_CWORD,
3003 /* 138 */ CWORD_CWORD_CWORD_CWORD,
3004 /* 139 */ CWORD_CWORD_CWORD_CWORD,
3005 /* 140 */ CWORD_CWORD_CWORD_CWORD,
3006 /* 141 */ CWORD_CWORD_CWORD_CWORD,
3007 /* 142 */ CWORD_CWORD_CWORD_CWORD,
3008 /* 143 */ CWORD_CWORD_CWORD_CWORD,
3009 /* 144 */ CWORD_CWORD_CWORD_CWORD,
3010 /* 145 */ CWORD_CWORD_CWORD_CWORD,
3011 /* 146 */ CWORD_CWORD_CWORD_CWORD,
3012 /* 147 */ CWORD_CWORD_CWORD_CWORD,
3013 /* 148 */ CWORD_CWORD_CWORD_CWORD,
3014 /* 149 */ CWORD_CWORD_CWORD_CWORD,
3015 /* 150 */ CWORD_CWORD_CWORD_CWORD,
3016 /* 151 */ CWORD_CWORD_CWORD_CWORD,
3017 /* 152 */ CWORD_CWORD_CWORD_CWORD,
3018 /* 153 */ CWORD_CWORD_CWORD_CWORD,
3019 /* 154 */ CWORD_CWORD_CWORD_CWORD,
3020 /* 155 */ CWORD_CWORD_CWORD_CWORD,
3021 /* 156 */ CWORD_CWORD_CWORD_CWORD,
3022 /* 157 */ CWORD_CWORD_CWORD_CWORD,
3023 /* 158 */ CWORD_CWORD_CWORD_CWORD,
3024 /* 159 */ CWORD_CWORD_CWORD_CWORD,
3025 /* 160 */ CWORD_CWORD_CWORD_CWORD,
3026 /* 161 */ CWORD_CWORD_CWORD_CWORD,
3027 /* 162 */ CWORD_CWORD_CWORD_CWORD,
3028 /* 163 */ CWORD_CWORD_CWORD_CWORD,
3029 /* 164 */ CWORD_CWORD_CWORD_CWORD,
3030 /* 165 */ CWORD_CWORD_CWORD_CWORD,
3031 /* 166 */ CWORD_CWORD_CWORD_CWORD,
3032 /* 167 */ CWORD_CWORD_CWORD_CWORD,
3033 /* 168 */ CWORD_CWORD_CWORD_CWORD,
3034 /* 169 */ CWORD_CWORD_CWORD_CWORD,
3035 /* 170 */ CWORD_CWORD_CWORD_CWORD,
3036 /* 171 */ CWORD_CWORD_CWORD_CWORD,
3037 /* 172 */ CWORD_CWORD_CWORD_CWORD,
3038 /* 173 */ CWORD_CWORD_CWORD_CWORD,
3039 /* 174 */ CWORD_CWORD_CWORD_CWORD,
3040 /* 175 */ CWORD_CWORD_CWORD_CWORD,
3041 /* 176 */ CWORD_CWORD_CWORD_CWORD,
3042 /* 177 */ CWORD_CWORD_CWORD_CWORD,
3043 /* 178 */ CWORD_CWORD_CWORD_CWORD,
3044 /* 179 */ CWORD_CWORD_CWORD_CWORD,
3045 /* 180 */ CWORD_CWORD_CWORD_CWORD,
3046 /* 181 */ CWORD_CWORD_CWORD_CWORD,
3047 /* 182 */ CWORD_CWORD_CWORD_CWORD,
3048 /* 183 */ CWORD_CWORD_CWORD_CWORD,
3049 /* 184 */ CWORD_CWORD_CWORD_CWORD,
3050 /* 185 */ CWORD_CWORD_CWORD_CWORD,
3051 /* 186 */ CWORD_CWORD_CWORD_CWORD,
3052 /* 187 */ CWORD_CWORD_CWORD_CWORD,
3053 /* 188 */ CWORD_CWORD_CWORD_CWORD,
3054 /* 189 */ CWORD_CWORD_CWORD_CWORD,
3055 /* 190 */ CWORD_CWORD_CWORD_CWORD,
3056 /* 191 */ CWORD_CWORD_CWORD_CWORD,
3057 /* 192 */ CWORD_CWORD_CWORD_CWORD,
3058 /* 193 */ CWORD_CWORD_CWORD_CWORD,
3059 /* 194 */ CWORD_CWORD_CWORD_CWORD,
3060 /* 195 */ CWORD_CWORD_CWORD_CWORD,
3061 /* 196 */ CWORD_CWORD_CWORD_CWORD,
3062 /* 197 */ CWORD_CWORD_CWORD_CWORD,
3063 /* 198 */ CWORD_CWORD_CWORD_CWORD,
3064 /* 199 */ CWORD_CWORD_CWORD_CWORD,
3065 /* 200 */ CWORD_CWORD_CWORD_CWORD,
3066 /* 201 */ CWORD_CWORD_CWORD_CWORD,
3067 /* 202 */ CWORD_CWORD_CWORD_CWORD,
3068 /* 203 */ CWORD_CWORD_CWORD_CWORD,
3069 /* 204 */ CWORD_CWORD_CWORD_CWORD,
3070 /* 205 */ CWORD_CWORD_CWORD_CWORD,
3071 /* 206 */ CWORD_CWORD_CWORD_CWORD,
3072 /* 207 */ CWORD_CWORD_CWORD_CWORD,
3073 /* 208 */ CWORD_CWORD_CWORD_CWORD,
3074 /* 209 */ CWORD_CWORD_CWORD_CWORD,
3075 /* 210 */ CWORD_CWORD_CWORD_CWORD,
3076 /* 211 */ CWORD_CWORD_CWORD_CWORD,
3077 /* 212 */ CWORD_CWORD_CWORD_CWORD,
3078 /* 213 */ CWORD_CWORD_CWORD_CWORD,
3079 /* 214 */ CWORD_CWORD_CWORD_CWORD,
3080 /* 215 */ CWORD_CWORD_CWORD_CWORD,
3081 /* 216 */ CWORD_CWORD_CWORD_CWORD,
3082 /* 217 */ CWORD_CWORD_CWORD_CWORD,
3083 /* 218 */ CWORD_CWORD_CWORD_CWORD,
3084 /* 219 */ CWORD_CWORD_CWORD_CWORD,
3085 /* 220 */ CWORD_CWORD_CWORD_CWORD,
3086 /* 221 */ CWORD_CWORD_CWORD_CWORD,
3087 /* 222 */ CWORD_CWORD_CWORD_CWORD,
3088 /* 223 */ CWORD_CWORD_CWORD_CWORD,
3089 /* 224 */ CWORD_CWORD_CWORD_CWORD,
3090 /* 225 */ CWORD_CWORD_CWORD_CWORD,
3091 /* 226 */ CWORD_CWORD_CWORD_CWORD,
3092 /* 227 */ CWORD_CWORD_CWORD_CWORD,
3093 /* 228 */ CWORD_CWORD_CWORD_CWORD,
3094 /* 229 */ CWORD_CWORD_CWORD_CWORD,
3095 /* 230 */ CWORD_CWORD_CWORD_CWORD,
3096 /* 231 */ CWORD_CWORD_CWORD_CWORD,
3097 /* 232 */ CWORD_CWORD_CWORD_CWORD,
3098 /* 233 */ CWORD_CWORD_CWORD_CWORD,
3099 /* 234 */ CWORD_CWORD_CWORD_CWORD,
3100 /* 235 */ CWORD_CWORD_CWORD_CWORD,
3101 /* 236 */ CWORD_CWORD_CWORD_CWORD,
3102 /* 237 */ CWORD_CWORD_CWORD_CWORD,
3103 /* 238 */ CWORD_CWORD_CWORD_CWORD,
3104 /* 239 */ CWORD_CWORD_CWORD_CWORD,
3105 /* 230 */ CWORD_CWORD_CWORD_CWORD,
3106 /* 241 */ CWORD_CWORD_CWORD_CWORD,
3107 /* 242 */ CWORD_CWORD_CWORD_CWORD,
3108 /* 243 */ CWORD_CWORD_CWORD_CWORD,
3109 /* 244 */ CWORD_CWORD_CWORD_CWORD,
3110 /* 245 */ CWORD_CWORD_CWORD_CWORD,
3111 /* 246 */ CWORD_CWORD_CWORD_CWORD,
3112 /* 247 */ CWORD_CWORD_CWORD_CWORD,
3113 /* 248 */ CWORD_CWORD_CWORD_CWORD,
3114 /* 249 */ CWORD_CWORD_CWORD_CWORD,
3115 /* 250 */ CWORD_CWORD_CWORD_CWORD,
3116 /* 251 */ CWORD_CWORD_CWORD_CWORD,
3117 /* 252 */ CWORD_CWORD_CWORD_CWORD,
3118 /* 253 */ CWORD_CWORD_CWORD_CWORD,
3119 /* 254 */ CWORD_CWORD_CWORD_CWORD,
3120 /* 255 */ CWORD_CWORD_CWORD_CWORD,
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01003121 /* PEOF */ CENDFILE_CENDFILE_CENDFILE_CENDFILE,
Denys Vlasenkocd716832009-11-28 22:14:02 +01003122# if ENABLE_ASH_ALIAS
3123 /* PEOA */ CSPCL_CIGN_CIGN_CIGN,
3124# endif
Eric Andersen2870d962001-07-02 17:27:21 +00003125};
3126
Denys Vlasenko2fe66b12016-12-12 17:39:12 +01003127#if 1
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01003128# define SIT(c, syntax) ((S_I_T[syntax_index_table[c]] >> ((syntax)*4)) & 0xf)
Denys Vlasenko2fe66b12016-12-12 17:39:12 +01003129#else /* debug version, caught one signed char bug */
3130# define SIT(c, syntax) \
3131 ({ \
3132 if ((c) < 0 || (c) > (PEOF + ENABLE_ASH_ALIAS)) \
3133 bb_error_msg_and_die("line:%d c:%d", __LINE__, (c)); \
Denys Vlasenko0b883582016-12-23 16:49:07 +01003134 if ((syntax) < 0 || (syntax) > (2 + ENABLE_FEATURE_SH_MATH)) \
Denys Vlasenko2fe66b12016-12-12 17:39:12 +01003135 bb_error_msg_and_die("line:%d c:%d", __LINE__, (c)); \
3136 ((S_I_T[syntax_index_table[c]] >> ((syntax)*4)) & 0xf); \
3137 })
3138#endif
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00003139
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01003140#endif /* !USE_SIT_FUNCTION */
Eric Andersenc470f442003-07-28 09:56:35 +00003141
Eric Andersen2870d962001-07-02 17:27:21 +00003142
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00003143/* ============ Alias handling */
Denis Vlasenkofc06f292007-02-23 21:09:35 +00003144
Denis Vlasenko131ae172007-02-18 13:00:19 +00003145#if ENABLE_ASH_ALIAS
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00003146
3147#define ALIASINUSE 1
3148#define ALIASDEAD 2
3149
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00003150struct alias {
3151 struct alias *next;
3152 char *name;
3153 char *val;
3154 int flag;
3155};
3156
Denis Vlasenko01631112007-12-16 17:20:38 +00003157
3158static struct alias **atab; // [ATABSIZE];
3159#define INIT_G_alias() do { \
3160 atab = xzalloc(ATABSIZE * sizeof(atab[0])); \
3161} while (0)
3162
Eric Andersen2870d962001-07-02 17:27:21 +00003163
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00003164static struct alias **
Denys Vlasenko37dc08b2016-10-02 04:38:07 +02003165__lookupalias(const char *name)
3166{
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00003167 unsigned int hashval;
3168 struct alias **app;
3169 const char *p;
3170 unsigned int ch;
3171
3172 p = name;
3173
3174 ch = (unsigned char)*p;
3175 hashval = ch << 4;
3176 while (ch) {
3177 hashval += ch;
3178 ch = (unsigned char)*++p;
3179 }
3180 app = &atab[hashval % ATABSIZE];
3181
3182 for (; *app; app = &(*app)->next) {
3183 if (strcmp(name, (*app)->name) == 0) {
3184 break;
3185 }
3186 }
3187
3188 return app;
3189}
3190
3191static struct alias *
3192lookupalias(const char *name, int check)
3193{
3194 struct alias *ap = *__lookupalias(name);
3195
3196 if (check && ap && (ap->flag & ALIASINUSE))
3197 return NULL;
3198 return ap;
3199}
3200
3201static struct alias *
3202freealias(struct alias *ap)
3203{
3204 struct alias *next;
3205
3206 if (ap->flag & ALIASINUSE) {
3207 ap->flag |= ALIASDEAD;
3208 return ap;
3209 }
3210
3211 next = ap->next;
3212 free(ap->name);
3213 free(ap->val);
3214 free(ap);
3215 return next;
3216}
Eric Andersencb57d552001-06-28 07:25:16 +00003217
Eric Andersenc470f442003-07-28 09:56:35 +00003218static void
3219setalias(const char *name, const char *val)
Eric Andersencb57d552001-06-28 07:25:16 +00003220{
3221 struct alias *ap, **app;
3222
3223 app = __lookupalias(name);
3224 ap = *app;
Denis Vlasenkob012b102007-02-19 22:43:01 +00003225 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +00003226 if (ap) {
3227 if (!(ap->flag & ALIASINUSE)) {
Denis Vlasenkob012b102007-02-19 22:43:01 +00003228 free(ap->val);
Eric Andersencb57d552001-06-28 07:25:16 +00003229 }
Denis Vlasenko0c032a42007-02-23 01:03:40 +00003230 ap->val = ckstrdup(val);
Eric Andersencb57d552001-06-28 07:25:16 +00003231 ap->flag &= ~ALIASDEAD;
3232 } else {
3233 /* not found */
Denis Vlasenko597906c2008-02-20 16:38:54 +00003234 ap = ckzalloc(sizeof(struct alias));
Denis Vlasenko0c032a42007-02-23 01:03:40 +00003235 ap->name = ckstrdup(name);
3236 ap->val = ckstrdup(val);
Denis Vlasenko597906c2008-02-20 16:38:54 +00003237 /*ap->flag = 0; - ckzalloc did it */
3238 /*ap->next = NULL;*/
Eric Andersencb57d552001-06-28 07:25:16 +00003239 *app = ap;
3240 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00003241 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +00003242}
3243
Eric Andersenc470f442003-07-28 09:56:35 +00003244static int
3245unalias(const char *name)
Eric Andersen2870d962001-07-02 17:27:21 +00003246{
Eric Andersencb57d552001-06-28 07:25:16 +00003247 struct alias **app;
3248
3249 app = __lookupalias(name);
3250
3251 if (*app) {
Denis Vlasenkob012b102007-02-19 22:43:01 +00003252 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +00003253 *app = freealias(*app);
Denis Vlasenkob012b102007-02-19 22:43:01 +00003254 INT_ON;
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003255 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003256 }
3257
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003258 return 1;
Eric Andersencb57d552001-06-28 07:25:16 +00003259}
3260
Eric Andersenc470f442003-07-28 09:56:35 +00003261static void
3262rmaliases(void)
Eric Andersen2870d962001-07-02 17:27:21 +00003263{
Eric Andersencb57d552001-06-28 07:25:16 +00003264 struct alias *ap, **app;
3265 int i;
3266
Denis Vlasenkob012b102007-02-19 22:43:01 +00003267 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +00003268 for (i = 0; i < ATABSIZE; i++) {
3269 app = &atab[i];
3270 for (ap = *app; ap; ap = *app) {
3271 *app = freealias(*app);
3272 if (ap == *app) {
3273 app = &ap->next;
3274 }
3275 }
3276 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00003277 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +00003278}
3279
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00003280static void
3281printalias(const struct alias *ap)
3282{
3283 out1fmt("%s=%s\n", ap->name, single_quote(ap->val));
3284}
3285
Eric Andersencb57d552001-06-28 07:25:16 +00003286/*
3287 * TODO - sort output
3288 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02003289static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003290aliascmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003291{
3292 char *n, *v;
3293 int ret = 0;
3294 struct alias *ap;
3295
Denis Vlasenko68404f12008-03-17 09:00:54 +00003296 if (!argv[1]) {
Eric Andersencb57d552001-06-28 07:25:16 +00003297 int i;
3298
Denis Vlasenko68404f12008-03-17 09:00:54 +00003299 for (i = 0; i < ATABSIZE; i++) {
Eric Andersencb57d552001-06-28 07:25:16 +00003300 for (ap = atab[i]; ap; ap = ap->next) {
3301 printalias(ap);
3302 }
Denis Vlasenko68404f12008-03-17 09:00:54 +00003303 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003304 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003305 }
3306 while ((n = *++argv) != NULL) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +00003307 v = strchr(n+1, '=');
3308 if (v == NULL) { /* n+1: funny ksh stuff */
3309 ap = *__lookupalias(n);
3310 if (ap == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00003311 fprintf(stderr, "%s: %s not found\n", "alias", n);
Eric Andersencb57d552001-06-28 07:25:16 +00003312 ret = 1;
3313 } else
3314 printalias(ap);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003315 } else {
Eric Andersencb57d552001-06-28 07:25:16 +00003316 *v++ = '\0';
3317 setalias(n, v);
3318 }
3319 }
3320
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003321 return ret;
Eric Andersencb57d552001-06-28 07:25:16 +00003322}
3323
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02003324static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003325unaliascmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +00003326{
3327 int i;
3328
3329 while ((i = nextopt("a")) != '\0') {
3330 if (i == 'a') {
3331 rmaliases();
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003332 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003333 }
3334 }
3335 for (i = 0; *argptr; argptr++) {
3336 if (unalias(*argptr)) {
Eric Andersenc470f442003-07-28 09:56:35 +00003337 fprintf(stderr, "%s: %s not found\n", "unalias", *argptr);
Eric Andersencb57d552001-06-28 07:25:16 +00003338 i = 1;
3339 }
3340 }
3341
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003342 return i;
Eric Andersencb57d552001-06-28 07:25:16 +00003343}
Denis Vlasenkofc06f292007-02-23 21:09:35 +00003344
Denis Vlasenko131ae172007-02-18 13:00:19 +00003345#endif /* ASH_ALIAS */
Eric Andersencb57d552001-06-28 07:25:16 +00003346
Eric Andersenc470f442003-07-28 09:56:35 +00003347
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003348/* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */
Denys Vlasenko285ad152009-12-04 23:02:27 +01003349#define FORK_FG 0
3350#define FORK_BG 1
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003351#define FORK_NOJOB 2
3352
3353/* mode flags for showjob(s) */
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02003354#define SHOW_ONLY_PGID 0x01 /* show only pgid (jobs -p) */
3355#define SHOW_PIDS 0x02 /* show individual pids, not just one line per job */
3356#define SHOW_CHANGED 0x04 /* only jobs whose state has changed */
Denys Vlasenko9c541002015-10-07 15:44:36 +02003357#define SHOW_STDERR 0x08 /* print to stderr (else stdout) */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003358
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003359/*
3360 * A job structure contains information about a job. A job is either a
3361 * single process or a set of processes contained in a pipeline. In the
3362 * latter case, pidlist will be non-NULL, and will point to a -1 terminated
3363 * array of pids.
3364 */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003365struct procstat {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003366 pid_t ps_pid; /* process id */
3367 int ps_status; /* last process status from wait() */
3368 char *ps_cmd; /* text of command being run */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003369};
3370
3371struct job {
3372 struct procstat ps0; /* status of process */
3373 struct procstat *ps; /* status or processes when more than one */
3374#if JOBS
3375 int stopstatus; /* status of a stopped job */
3376#endif
3377 uint32_t
3378 nprocs: 16, /* number of processes */
3379 state: 8,
3380#define JOBRUNNING 0 /* at least one proc running */
3381#define JOBSTOPPED 1 /* all procs are stopped */
3382#define JOBDONE 2 /* all procs are completed */
3383#if JOBS
3384 sigint: 1, /* job was killed by SIGINT */
3385 jobctl: 1, /* job running under job control */
3386#endif
3387 waited: 1, /* true if this entry has been waited for */
3388 used: 1, /* true if this entry is in used */
3389 changed: 1; /* true if status has changed */
3390 struct job *prev_job; /* previous job */
3391};
3392
Denis Vlasenko68404f12008-03-17 09:00:54 +00003393static struct job *makejob(/*union node *,*/ int);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003394static int forkshell(struct job *, union node *, int);
3395static int waitforjob(struct job *);
3396
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00003397#if !JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +00003398enum { doing_jobctl = 0 };
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00003399#define setjobctl(on) do {} while (0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003400#else
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003401static smallint doing_jobctl; //references:8
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003402static void setjobctl(int);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003403#endif
3404
3405/*
Denis Vlasenko4b875702009-03-19 13:30:04 +00003406 * Ignore a signal.
3407 */
3408static void
3409ignoresig(int signo)
3410{
3411 /* Avoid unnecessary system calls. Is it already SIG_IGNed? */
3412 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
3413 /* No, need to do it */
3414 signal(signo, SIG_IGN);
3415 }
3416 sigmode[signo - 1] = S_HARD_IGN;
3417}
3418
3419/*
Denys Vlasenko238bf182010-05-18 15:49:07 +02003420 * Only one usage site - in setsignal()
Denis Vlasenko4b875702009-03-19 13:30:04 +00003421 */
3422static void
Denys Vlasenko238bf182010-05-18 15:49:07 +02003423signal_handler(int signo)
Denis Vlasenko4b875702009-03-19 13:30:04 +00003424{
Denys Vlasenko458c1f22016-10-27 23:51:19 +02003425 if (signo == SIGCHLD) {
3426 got_sigchld = 1;
3427 if (!trap[SIGCHLD])
3428 return;
3429 }
3430
Denis Vlasenko4b875702009-03-19 13:30:04 +00003431 gotsig[signo - 1] = 1;
Denys Vlasenko458c1f22016-10-27 23:51:19 +02003432 pending_sig = signo;
Denis Vlasenko4b875702009-03-19 13:30:04 +00003433
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02003434 if (signo == SIGINT && !trap[SIGINT]) {
3435 if (!suppress_int) {
3436 pending_sig = 0;
Denis Vlasenko4b875702009-03-19 13:30:04 +00003437 raise_interrupt(); /* does not return */
3438 }
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02003439 pending_int = 1;
Denis Vlasenko4b875702009-03-19 13:30:04 +00003440 }
3441}
3442
3443/*
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003444 * Set the signal handler for the specified signal. The routine figures
3445 * out what it should be set to.
3446 */
3447static void
3448setsignal(int signo)
3449{
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003450 char *t;
3451 char cur_act, new_act;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003452 struct sigaction act;
3453
3454 t = trap[signo];
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003455 new_act = S_DFL;
3456 if (t != NULL) { /* trap for this sig is set */
3457 new_act = S_CATCH;
3458 if (t[0] == '\0') /* trap is "": ignore this sig */
3459 new_act = S_IGN;
3460 }
3461
3462 if (rootshell && new_act == S_DFL) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003463 switch (signo) {
3464 case SIGINT:
3465 if (iflag || minusc || sflag == 0)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003466 new_act = S_CATCH;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003467 break;
3468 case SIGQUIT:
3469#if DEBUG
3470 if (debug)
3471 break;
3472#endif
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003473 /* man bash:
3474 * "In all cases, bash ignores SIGQUIT. Non-builtin
3475 * commands run by bash have signal handlers
3476 * set to the values inherited by the shell
3477 * from its parent". */
3478 new_act = S_IGN;
3479 break;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003480 case SIGTERM:
3481 if (iflag)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003482 new_act = S_IGN;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003483 break;
3484#if JOBS
3485 case SIGTSTP:
3486 case SIGTTOU:
3487 if (mflag)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003488 new_act = S_IGN;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003489 break;
3490#endif
3491 }
3492 }
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003493//TODO: if !rootshell, we reset SIGQUIT to DFL,
3494//whereas we have to restore it to what shell got on entry
3495//from the parent. See comment above
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003496
Denys Vlasenko458c1f22016-10-27 23:51:19 +02003497 if (signo == SIGCHLD)
3498 new_act = S_CATCH;
3499
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003500 t = &sigmode[signo - 1];
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003501 cur_act = *t;
3502 if (cur_act == 0) {
3503 /* current setting is not yet known */
3504 if (sigaction(signo, NULL, &act)) {
3505 /* pretend it worked; maybe we should give a warning,
3506 * but other shells don't. We don't alter sigmode,
3507 * so we retry every time.
3508 * btw, in Linux it never fails. --vda */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003509 return;
3510 }
3511 if (act.sa_handler == SIG_IGN) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003512 cur_act = S_HARD_IGN;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003513 if (mflag
3514 && (signo == SIGTSTP || signo == SIGTTIN || signo == SIGTTOU)
3515 ) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003516 cur_act = S_IGN; /* don't hard ignore these */
Denis Vlasenko991a1da2008-02-10 19:02:53 +00003517 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003518 }
3519 }
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003520 if (cur_act == S_HARD_IGN || cur_act == new_act)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003521 return;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003522
Denis Vlasenko991a1da2008-02-10 19:02:53 +00003523 act.sa_handler = SIG_DFL;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003524 switch (new_act) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003525 case S_CATCH:
Denys Vlasenko238bf182010-05-18 15:49:07 +02003526 act.sa_handler = signal_handler;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003527 break;
3528 case S_IGN:
3529 act.sa_handler = SIG_IGN;
3530 break;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003531 }
Ian Wienand89b3cba2011-04-16 20:05:14 +02003532
3533 /* flags and mask matter only if !DFL and !IGN, but we do it
3534 * for all cases for more deterministic behavior:
3535 */
3536 act.sa_flags = 0;
3537 sigfillset(&act.sa_mask);
3538
Denis Vlasenko8e2cfec2008-03-12 23:19:35 +00003539 sigaction_set(signo, &act);
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003540
3541 *t = new_act;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003542}
3543
3544/* mode flags for set_curjob */
3545#define CUR_DELETE 2
3546#define CUR_RUNNING 1
3547#define CUR_STOPPED 0
3548
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003549#if JOBS
3550/* pgrp of shell on invocation */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003551static int initialpgrp; //references:2
3552static int ttyfd = -1; //5
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003553#endif
3554/* array of jobs */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003555static struct job *jobtab; //5
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003556/* size of array */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003557static unsigned njobs; //4
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003558/* current job */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003559static struct job *curjob; //lots
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003560/* number of presumed living untracked jobs */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003561static int jobless; //4
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003562
3563static void
3564set_curjob(struct job *jp, unsigned mode)
3565{
3566 struct job *jp1;
3567 struct job **jpp, **curp;
3568
3569 /* first remove from list */
3570 jpp = curp = &curjob;
Denys Vlasenko940c7202011-03-02 04:07:14 +01003571 while (1) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003572 jp1 = *jpp;
3573 if (jp1 == jp)
3574 break;
3575 jpp = &jp1->prev_job;
Denys Vlasenko940c7202011-03-02 04:07:14 +01003576 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003577 *jpp = jp1->prev_job;
3578
3579 /* Then re-insert in correct position */
3580 jpp = curp;
3581 switch (mode) {
3582 default:
3583#if DEBUG
3584 abort();
3585#endif
3586 case CUR_DELETE:
3587 /* job being deleted */
3588 break;
3589 case CUR_RUNNING:
3590 /* newly created job or backgrounded job,
Denys Vlasenko60cb48c2013-01-14 15:57:44 +01003591 * put after all stopped jobs.
3592 */
Denys Vlasenko940c7202011-03-02 04:07:14 +01003593 while (1) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003594 jp1 = *jpp;
3595#if JOBS
3596 if (!jp1 || jp1->state != JOBSTOPPED)
3597#endif
3598 break;
3599 jpp = &jp1->prev_job;
Denys Vlasenko940c7202011-03-02 04:07:14 +01003600 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003601 /* FALLTHROUGH */
3602#if JOBS
3603 case CUR_STOPPED:
3604#endif
3605 /* newly stopped job - becomes curjob */
3606 jp->prev_job = *jpp;
3607 *jpp = jp;
3608 break;
3609 }
3610}
3611
3612#if JOBS || DEBUG
3613static int
3614jobno(const struct job *jp)
3615{
3616 return jp - jobtab + 1;
3617}
3618#endif
3619
3620/*
3621 * Convert a job name to a job structure.
3622 */
Denis Vlasenko85c24712008-03-17 09:04:04 +00003623#if !JOBS
3624#define getjob(name, getctl) getjob(name)
3625#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003626static struct job *
3627getjob(const char *name, int getctl)
3628{
3629 struct job *jp;
3630 struct job *found;
Denys Vlasenkoffc39202009-08-17 02:12:20 +02003631 const char *err_msg = "%s: no such job";
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003632 unsigned num;
3633 int c;
3634 const char *p;
3635 char *(*match)(const char *, const char *);
3636
3637 jp = curjob;
3638 p = name;
3639 if (!p)
3640 goto currentjob;
3641
3642 if (*p != '%')
3643 goto err;
3644
3645 c = *++p;
3646 if (!c)
3647 goto currentjob;
3648
3649 if (!p[1]) {
3650 if (c == '+' || c == '%') {
3651 currentjob:
3652 err_msg = "No current job";
3653 goto check;
3654 }
3655 if (c == '-') {
3656 if (jp)
3657 jp = jp->prev_job;
3658 err_msg = "No previous job";
3659 check:
3660 if (!jp)
3661 goto err;
3662 goto gotit;
3663 }
3664 }
3665
3666 if (is_number(p)) {
3667 num = atoi(p);
Denys Vlasenko46a45ce2016-09-29 01:10:08 +02003668 if (num > 0 && num <= njobs) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003669 jp = jobtab + num - 1;
3670 if (jp->used)
3671 goto gotit;
3672 goto err;
3673 }
3674 }
3675
3676 match = prefix;
3677 if (*p == '?') {
3678 match = strstr;
3679 p++;
3680 }
3681
Denys Vlasenkoffc39202009-08-17 02:12:20 +02003682 found = NULL;
3683 while (jp) {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003684 if (match(jp->ps[0].ps_cmd, p)) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003685 if (found)
3686 goto err;
3687 found = jp;
3688 err_msg = "%s: ambiguous";
3689 }
3690 jp = jp->prev_job;
3691 }
Denys Vlasenkoffc39202009-08-17 02:12:20 +02003692 if (!found)
3693 goto err;
3694 jp = found;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003695
3696 gotit:
3697#if JOBS
3698 err_msg = "job %s not created under job control";
3699 if (getctl && jp->jobctl == 0)
3700 goto err;
3701#endif
3702 return jp;
3703 err:
3704 ash_msg_and_raise_error(err_msg, name);
3705}
3706
3707/*
3708 * Mark a job structure as unused.
3709 */
3710static void
3711freejob(struct job *jp)
3712{
3713 struct procstat *ps;
3714 int i;
3715
3716 INT_OFF;
3717 for (i = jp->nprocs, ps = jp->ps; --i >= 0; ps++) {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003718 if (ps->ps_cmd != nullstr)
3719 free(ps->ps_cmd);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003720 }
3721 if (jp->ps != &jp->ps0)
3722 free(jp->ps);
3723 jp->used = 0;
3724 set_curjob(jp, CUR_DELETE);
3725 INT_ON;
3726}
3727
3728#if JOBS
3729static void
3730xtcsetpgrp(int fd, pid_t pgrp)
3731{
3732 if (tcsetpgrp(fd, pgrp))
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +00003733 ash_msg_and_raise_error("can't set tty process group (%m)");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003734}
3735
3736/*
3737 * Turn job control on and off.
3738 *
3739 * Note: This code assumes that the third arg to ioctl is a character
3740 * pointer, which is true on Berkeley systems but not System V. Since
3741 * System V doesn't have job control yet, this isn't a problem now.
3742 *
3743 * Called with interrupts off.
3744 */
3745static void
3746setjobctl(int on)
3747{
3748 int fd;
3749 int pgrp;
3750
Denis Vlasenkob07a4962008-06-22 13:16:23 +00003751 if (on == doing_jobctl || rootshell == 0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003752 return;
3753 if (on) {
3754 int ofd;
3755 ofd = fd = open(_PATH_TTY, O_RDWR);
3756 if (fd < 0) {
3757 /* BTW, bash will try to open(ttyname(0)) if open("/dev/tty") fails.
3758 * That sometimes helps to acquire controlling tty.
3759 * Obviously, a workaround for bugs when someone
3760 * failed to provide a controlling tty to bash! :) */
Denis Vlasenkoed270a52007-11-26 05:37:07 +00003761 fd = 2;
3762 while (!isatty(fd))
3763 if (--fd < 0)
3764 goto out;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003765 }
Denys Vlasenko64774602016-10-26 15:24:30 +02003766 /* fd is a tty at this point */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003767 fd = fcntl(fd, F_DUPFD, 10);
Denys Vlasenko64774602016-10-26 15:24:30 +02003768 if (ofd >= 0) /* if it is "/dev/tty", close. If 0/1/2, dont */
Denis Vlasenkoed270a52007-11-26 05:37:07 +00003769 close(ofd);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003770 if (fd < 0)
Denys Vlasenko64774602016-10-26 15:24:30 +02003771 goto out; /* F_DUPFD failed */
Denis Vlasenko96e1b382007-09-30 23:50:48 +00003772 close_on_exec_on(fd);
Denys Vlasenko940c7202011-03-02 04:07:14 +01003773 while (1) { /* while we are in the background */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003774 pgrp = tcgetpgrp(fd);
3775 if (pgrp < 0) {
3776 out:
3777 ash_msg("can't access tty; job control turned off");
3778 mflag = on = 0;
3779 goto close;
3780 }
3781 if (pgrp == getpgrp())
3782 break;
3783 killpg(0, SIGTTIN);
Denys Vlasenko940c7202011-03-02 04:07:14 +01003784 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003785 initialpgrp = pgrp;
3786
3787 setsignal(SIGTSTP);
3788 setsignal(SIGTTOU);
3789 setsignal(SIGTTIN);
3790 pgrp = rootpid;
3791 setpgid(0, pgrp);
3792 xtcsetpgrp(fd, pgrp);
3793 } else {
3794 /* turning job control off */
3795 fd = ttyfd;
3796 pgrp = initialpgrp;
Denis Vlasenko08c8c1d2007-04-28 22:39:02 +00003797 /* was xtcsetpgrp, but this can make exiting ash
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00003798 * loop forever if pty is already deleted */
Denis Vlasenko08c8c1d2007-04-28 22:39:02 +00003799 tcsetpgrp(fd, pgrp);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003800 setpgid(0, pgrp);
3801 setsignal(SIGTSTP);
3802 setsignal(SIGTTOU);
3803 setsignal(SIGTTIN);
3804 close:
Denis Vlasenkoed270a52007-11-26 05:37:07 +00003805 if (fd >= 0)
3806 close(fd);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003807 fd = -1;
3808 }
3809 ttyfd = fd;
Denis Vlasenkob07a4962008-06-22 13:16:23 +00003810 doing_jobctl = on;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003811}
3812
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02003813static int FAST_FUNC
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003814killcmd(int argc, char **argv)
3815{
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003816 if (argv[1] && strcmp(argv[1], "-l") != 0) {
Denys Vlasenkob12553f2011-02-21 03:22:20 +01003817 int i = 1;
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003818 do {
3819 if (argv[i][0] == '%') {
Denys Vlasenkob12553f2011-02-21 03:22:20 +01003820 /*
3821 * "kill %N" - job kill
3822 * Converting to pgrp / pid kill
3823 */
3824 struct job *jp;
3825 char *dst;
3826 int j, n;
3827
3828 jp = getjob(argv[i], 0);
3829 /*
3830 * In jobs started under job control, we signal
3831 * entire process group by kill -PGRP_ID.
3832 * This happens, f.e., in interactive shell.
3833 *
3834 * Otherwise, we signal each child via
3835 * kill PID1 PID2 PID3.
3836 * Testcases:
3837 * sh -c 'sleep 1|sleep 1 & kill %1'
3838 * sh -c 'true|sleep 2 & sleep 1; kill %1'
3839 * sh -c 'true|sleep 1 & sleep 2; kill %1'
3840 */
3841 n = jp->nprocs; /* can't be 0 (I hope) */
3842 if (jp->jobctl)
3843 n = 1;
3844 dst = alloca(n * sizeof(int)*4);
3845 argv[i] = dst;
3846 for (j = 0; j < n; j++) {
3847 struct procstat *ps = &jp->ps[j];
3848 /* Skip non-running and not-stopped members
3849 * (i.e. dead members) of the job
3850 */
3851 if (ps->ps_status != -1 && !WIFSTOPPED(ps->ps_status))
3852 continue;
3853 /*
3854 * kill_main has matching code to expect
3855 * leading space. Needed to not confuse
3856 * negative pids with "kill -SIGNAL_NO" syntax
3857 */
3858 dst += sprintf(dst, jp->jobctl ? " -%u" : " %u", (int)ps->ps_pid);
3859 }
3860 *dst = '\0';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003861 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003862 } while (argv[++i]);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003863 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003864 return kill_main(argc, argv);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003865}
3866
3867static void
Denys Vlasenko285ad152009-12-04 23:02:27 +01003868showpipe(struct job *jp /*, FILE *out*/)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003869{
Denys Vlasenko285ad152009-12-04 23:02:27 +01003870 struct procstat *ps;
3871 struct procstat *psend;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003872
Denys Vlasenko285ad152009-12-04 23:02:27 +01003873 psend = jp->ps + jp->nprocs;
3874 for (ps = jp->ps + 1; ps < psend; ps++)
3875 printf(" | %s", ps->ps_cmd);
Denys Vlasenko9c541002015-10-07 15:44:36 +02003876 newline_and_flush(stdout);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003877 flush_stdout_stderr();
3878}
3879
3880
3881static int
3882restartjob(struct job *jp, int mode)
3883{
3884 struct procstat *ps;
3885 int i;
3886 int status;
3887 pid_t pgid;
3888
3889 INT_OFF;
3890 if (jp->state == JOBDONE)
3891 goto out;
3892 jp->state = JOBRUNNING;
Denys Vlasenko285ad152009-12-04 23:02:27 +01003893 pgid = jp->ps[0].ps_pid;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003894 if (mode == FORK_FG)
3895 xtcsetpgrp(ttyfd, pgid);
3896 killpg(pgid, SIGCONT);
3897 ps = jp->ps;
3898 i = jp->nprocs;
3899 do {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003900 if (WIFSTOPPED(ps->ps_status)) {
3901 ps->ps_status = -1;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003902 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003903 ps++;
3904 } while (--i);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003905 out:
3906 status = (mode == FORK_FG) ? waitforjob(jp) : 0;
3907 INT_ON;
3908 return status;
3909}
3910
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02003911static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003912fg_bgcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003913{
3914 struct job *jp;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003915 int mode;
3916 int retval;
3917
3918 mode = (**argv == 'f') ? FORK_FG : FORK_BG;
3919 nextopt(nullstr);
3920 argv = argptr;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003921 do {
3922 jp = getjob(*argv, 1);
3923 if (mode == FORK_BG) {
3924 set_curjob(jp, CUR_RUNNING);
Denys Vlasenko285ad152009-12-04 23:02:27 +01003925 printf("[%d] ", jobno(jp));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003926 }
Denys Vlasenko285ad152009-12-04 23:02:27 +01003927 out1str(jp->ps[0].ps_cmd);
3928 showpipe(jp /*, stdout*/);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003929 retval = restartjob(jp, mode);
3930 } while (*argv && *++argv);
3931 return retval;
3932}
3933#endif
3934
3935static int
Denys Vlasenko9c541002015-10-07 15:44:36 +02003936sprint_status48(char *s, int status, int sigonly)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003937{
3938 int col;
3939 int st;
3940
3941 col = 0;
3942 if (!WIFEXITED(status)) {
Denys Vlasenko4700fb52015-10-09 15:40:13 +02003943 if (JOBS && WIFSTOPPED(status))
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003944 st = WSTOPSIG(status);
3945 else
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003946 st = WTERMSIG(status);
3947 if (sigonly) {
3948 if (st == SIGINT || st == SIGPIPE)
3949 goto out;
Denys Vlasenko4700fb52015-10-09 15:40:13 +02003950 if (JOBS && WIFSTOPPED(status))
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003951 goto out;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003952 }
3953 st &= 0x7f;
Denys Vlasenko7c6f2462011-02-14 17:17:10 +01003954//TODO: use bbox's get_signame? strsignal adds ~600 bytes to text+rodata
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003955 col = fmtstr(s, 32, strsignal(st));
3956 if (WCOREDUMP(status)) {
Denys Vlasenko9c541002015-10-07 15:44:36 +02003957 strcpy(s + col, " (core dumped)");
3958 col += sizeof(" (core dumped)")-1;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003959 }
3960 } else if (!sigonly) {
3961 st = WEXITSTATUS(status);
Denys Vlasenko9c541002015-10-07 15:44:36 +02003962 col = fmtstr(s, 16, (st ? "Done(%d)" : "Done"), st);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003963 }
3964 out:
3965 return col;
3966}
3967
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003968static int
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02003969wait_block_or_sig(int *status)
Denys Vlasenko458c1f22016-10-27 23:51:19 +02003970{
Denys Vlasenko458c1f22016-10-27 23:51:19 +02003971 int pid;
3972
3973 do {
Denys Vlasenko1ab7c2f2016-11-03 20:17:23 +01003974 sigset_t mask;
3975
Denys Vlasenko458c1f22016-10-27 23:51:19 +02003976 /* Poll all children for changes in their state */
3977 got_sigchld = 0;
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02003978 /* if job control is active, accept stopped processes too */
3979 pid = waitpid(-1, status, doing_jobctl ? (WNOHANG|WUNTRACED) : WNOHANG);
Denys Vlasenko458c1f22016-10-27 23:51:19 +02003980 if (pid != 0)
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02003981 break; /* Error (e.g. EINTR, ECHILD) or pid */
Denys Vlasenko458c1f22016-10-27 23:51:19 +02003982
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02003983 /* Children exist, but none are ready. Sleep until interesting signal */
Denys Vlasenko1ab7c2f2016-11-03 20:17:23 +01003984#if 1
Denys Vlasenko458c1f22016-10-27 23:51:19 +02003985 sigfillset(&mask);
3986 sigprocmask(SIG_SETMASK, &mask, &mask);
3987 while (!got_sigchld && !pending_sig)
3988 sigsuspend(&mask);
3989 sigprocmask(SIG_SETMASK, &mask, NULL);
Denys Vlasenko1ab7c2f2016-11-03 20:17:23 +01003990#else /* unsafe: a signal can set pending_sig after check, but before pause() */
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02003991 while (!got_sigchld && !pending_sig)
3992 pause();
3993#endif
Denys Vlasenko458c1f22016-10-27 23:51:19 +02003994
3995 /* If it was SIGCHLD, poll children again */
3996 } while (got_sigchld);
3997
3998 return pid;
3999}
4000
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004001#define DOWAIT_NONBLOCK 0
4002#define DOWAIT_BLOCK 1
4003#define DOWAIT_BLOCK_OR_SIG 2
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004004
4005static int
Denys Vlasenkob543bda2016-10-27 20:08:28 +02004006dowait(int block, struct job *job)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004007{
4008 int pid;
4009 int status;
4010 struct job *jp;
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004011 struct job *thisjob = NULL;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004012
Denys Vlasenkob543bda2016-10-27 20:08:28 +02004013 TRACE(("dowait(0x%x) called\n", block));
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +00004014
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004015 /* It's wrong to call waitpid() outside of INT_OFF region:
4016 * signal can arrive just after syscall return and handler can
4017 * longjmp away, losing stop/exit notification processing.
4018 * Thus, for "jobs" builtin, and for waiting for a fg job,
4019 * we call waitpid() (blocking or non-blocking) inside INT_OFF.
4020 *
4021 * However, for "wait" builtin it is wrong to simply call waitpid()
4022 * in INT_OFF region: "wait" needs to wait for any running job
4023 * to change state, but should exit on any trap too.
4024 * In INT_OFF region, a signal just before syscall entry can set
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004025 * pending_sig variables, but we can't check them, and we would
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004026 * either enter a sleeping waitpid() (BUG), or need to busy-loop.
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004027 *
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004028 * Because of this, we run inside INT_OFF, but use a special routine
Denys Vlasenko1ab7c2f2016-11-03 20:17:23 +01004029 * which combines waitpid() and sigsuspend().
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004030 * This is the reason why we need to have a handler for SIGCHLD:
Denys Vlasenko1ab7c2f2016-11-03 20:17:23 +01004031 * SIG_DFL handler does not wake sigsuspend().
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004032 */
4033 INT_OFF;
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004034 if (block == DOWAIT_BLOCK_OR_SIG) {
4035 pid = wait_block_or_sig(&status);
4036 } else {
4037 int wait_flags = 0;
4038 if (block == DOWAIT_NONBLOCK)
4039 wait_flags = WNOHANG;
4040 /* if job control is active, accept stopped processes too */
4041 if (doing_jobctl)
4042 wait_flags |= WUNTRACED;
4043 /* NB: _not_ safe_waitpid, we need to detect EINTR */
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004044 pid = waitpid(-1, &status, wait_flags);
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004045 }
Denis Vlasenkob21f3792009-03-19 23:09:58 +00004046 TRACE(("wait returns pid=%d, status=0x%x, errno=%d(%s)\n",
4047 pid, status, errno, strerror(errno)));
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004048 if (pid <= 0)
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004049 goto out;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004050
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004051 thisjob = NULL;
4052 for (jp = curjob; jp; jp = jp->prev_job) {
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004053 int jobstate;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004054 struct procstat *ps;
4055 struct procstat *psend;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004056 if (jp->state == JOBDONE)
4057 continue;
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004058 jobstate = JOBDONE;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004059 ps = jp->ps;
4060 psend = ps + jp->nprocs;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004061 do {
Denys Vlasenko285ad152009-12-04 23:02:27 +01004062 if (ps->ps_pid == pid) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004063 TRACE(("Job %d: changing status of proc %d "
4064 "from 0x%x to 0x%x\n",
Denys Vlasenko285ad152009-12-04 23:02:27 +01004065 jobno(jp), pid, ps->ps_status, status));
4066 ps->ps_status = status;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004067 thisjob = jp;
4068 }
Denys Vlasenko285ad152009-12-04 23:02:27 +01004069 if (ps->ps_status == -1)
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004070 jobstate = JOBRUNNING;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004071#if JOBS
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004072 if (jobstate == JOBRUNNING)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004073 continue;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004074 if (WIFSTOPPED(ps->ps_status)) {
4075 jp->stopstatus = ps->ps_status;
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004076 jobstate = JOBSTOPPED;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004077 }
4078#endif
Denys Vlasenko285ad152009-12-04 23:02:27 +01004079 } while (++ps < psend);
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004080 if (!thisjob)
4081 continue;
4082
4083 /* Found the job where one of its processes changed its state.
4084 * Is there at least one live and running process in this job? */
4085 if (jobstate != JOBRUNNING) {
4086 /* No. All live processes in the job are stopped
4087 * (JOBSTOPPED) or there are no live processes (JOBDONE)
4088 */
4089 thisjob->changed = 1;
4090 if (thisjob->state != jobstate) {
4091 TRACE(("Job %d: changing state from %d to %d\n",
4092 jobno(thisjob), thisjob->state, jobstate));
4093 thisjob->state = jobstate;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004094#if JOBS
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004095 if (jobstate == JOBSTOPPED)
4096 set_curjob(thisjob, CUR_STOPPED);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004097#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004098 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004099 }
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004100 goto out;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004101 }
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004102 /* The process wasn't found in job list */
4103 if (JOBS && !WIFSTOPPED(status))
4104 jobless--;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004105 out:
4106 INT_ON;
4107
4108 if (thisjob && thisjob == job) {
4109 char s[48 + 1];
4110 int len;
4111
Denys Vlasenko9c541002015-10-07 15:44:36 +02004112 len = sprint_status48(s, status, 1);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004113 if (len) {
4114 s[len] = '\n';
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004115 s[len + 1] = '\0';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004116 out2str(s);
4117 }
4118 }
4119 return pid;
4120}
4121
4122#if JOBS
4123static void
Denys Vlasenko9c541002015-10-07 15:44:36 +02004124showjob(struct job *jp, int mode)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004125{
4126 struct procstat *ps;
4127 struct procstat *psend;
4128 int col;
Denis Vlasenko40ba9982007-07-14 00:48:29 +00004129 int indent_col;
Denys Vlasenko9c541002015-10-07 15:44:36 +02004130 char s[16 + 16 + 48];
4131 FILE *out = (mode & SHOW_STDERR ? stderr : stdout);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004132
4133 ps = jp->ps;
4134
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004135 if (mode & SHOW_ONLY_PGID) { /* jobs -p */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004136 /* just output process (group) id of pipeline */
Denys Vlasenko285ad152009-12-04 23:02:27 +01004137 fprintf(out, "%d\n", ps->ps_pid);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004138 return;
4139 }
4140
4141 col = fmtstr(s, 16, "[%d] ", jobno(jp));
Denis Vlasenko40ba9982007-07-14 00:48:29 +00004142 indent_col = col;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004143
4144 if (jp == curjob)
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004145 s[col - 3] = '+';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004146 else if (curjob && jp == curjob->prev_job)
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004147 s[col - 3] = '-';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004148
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004149 if (mode & SHOW_PIDS)
Denys Vlasenko285ad152009-12-04 23:02:27 +01004150 col += fmtstr(s + col, 16, "%d ", ps->ps_pid);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004151
4152 psend = ps + jp->nprocs;
4153
4154 if (jp->state == JOBRUNNING) {
4155 strcpy(s + col, "Running");
4156 col += sizeof("Running") - 1;
4157 } else {
Denys Vlasenko285ad152009-12-04 23:02:27 +01004158 int status = psend[-1].ps_status;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004159 if (jp->state == JOBSTOPPED)
4160 status = jp->stopstatus;
Denys Vlasenko9c541002015-10-07 15:44:36 +02004161 col += sprint_status48(s + col, status, 0);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004162 }
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004163 /* By now, "[JOBID]* [maybe PID] STATUS" is printed */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004164
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004165 /* This loop either prints "<cmd1> | <cmd2> | <cmd3>" line
4166 * or prints several "PID | <cmdN>" lines,
4167 * depending on SHOW_PIDS bit.
4168 * We do not print status of individual processes
4169 * between PID and <cmdN>. bash does it, but not very well:
4170 * first line shows overall job status, not process status,
4171 * making it impossible to know 1st process status.
4172 */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004173 goto start;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004174 do {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004175 /* for each process */
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004176 s[0] = '\0';
4177 col = 33;
4178 if (mode & SHOW_PIDS)
Denys Vlasenko285ad152009-12-04 23:02:27 +01004179 col = fmtstr(s, 48, "\n%*c%d ", indent_col, ' ', ps->ps_pid) - 1;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004180 start:
Denys Vlasenko285ad152009-12-04 23:02:27 +01004181 fprintf(out, "%s%*c%s%s",
4182 s,
4183 33 - col >= 0 ? 33 - col : 0, ' ',
4184 ps == jp->ps ? "" : "| ",
4185 ps->ps_cmd
4186 );
4187 } while (++ps != psend);
Denys Vlasenko9c541002015-10-07 15:44:36 +02004188 newline_and_flush(out);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004189
4190 jp->changed = 0;
4191
4192 if (jp->state == JOBDONE) {
4193 TRACE(("showjob: freeing job %d\n", jobno(jp)));
4194 freejob(jp);
4195 }
4196}
4197
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004198/*
4199 * Print a list of jobs. If "change" is nonzero, only print jobs whose
4200 * statuses have changed since the last call to showjobs.
4201 */
4202static void
Denys Vlasenko9c541002015-10-07 15:44:36 +02004203showjobs(int mode)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004204{
4205 struct job *jp;
4206
Denys Vlasenko883cea42009-07-11 15:31:59 +02004207 TRACE(("showjobs(0x%x) called\n", mode));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004208
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004209 /* Handle all finished jobs */
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004210 while (dowait(DOWAIT_NONBLOCK, NULL) > 0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004211 continue;
4212
4213 for (jp = curjob; jp; jp = jp->prev_job) {
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004214 if (!(mode & SHOW_CHANGED) || jp->changed) {
Denys Vlasenko9c541002015-10-07 15:44:36 +02004215 showjob(jp, mode);
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004216 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004217 }
4218}
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004219
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02004220static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00004221jobscmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004222{
4223 int mode, m;
4224
4225 mode = 0;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02004226 while ((m = nextopt("lp")) != '\0') {
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004227 if (m == 'l')
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004228 mode |= SHOW_PIDS;
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004229 else
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004230 mode |= SHOW_ONLY_PGID;
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004231 }
4232
4233 argv = argptr;
4234 if (*argv) {
4235 do
Denys Vlasenko9c541002015-10-07 15:44:36 +02004236 showjob(getjob(*argv, 0), mode);
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004237 while (*++argv);
Denys Vlasenko285ad152009-12-04 23:02:27 +01004238 } else {
Denys Vlasenko9c541002015-10-07 15:44:36 +02004239 showjobs(mode);
Denys Vlasenko285ad152009-12-04 23:02:27 +01004240 }
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004241
4242 return 0;
4243}
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004244#endif /* JOBS */
4245
Michael Abbott359da5e2009-12-04 23:03:29 +01004246/* Called only on finished or stopped jobs (no members are running) */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004247static int
4248getstatus(struct job *job)
4249{
4250 int status;
4251 int retval;
Michael Abbott359da5e2009-12-04 23:03:29 +01004252 struct procstat *ps;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004253
Michael Abbott359da5e2009-12-04 23:03:29 +01004254 /* Fetch last member's status */
4255 ps = job->ps + job->nprocs - 1;
4256 status = ps->ps_status;
4257 if (pipefail) {
4258 /* "set -o pipefail" mode: use last _nonzero_ status */
4259 while (status == 0 && --ps >= job->ps)
4260 status = ps->ps_status;
4261 }
4262
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004263 retval = WEXITSTATUS(status);
4264 if (!WIFEXITED(status)) {
4265#if JOBS
4266 retval = WSTOPSIG(status);
4267 if (!WIFSTOPPED(status))
4268#endif
4269 {
4270 /* XXX: limits number of signals */
4271 retval = WTERMSIG(status);
4272#if JOBS
4273 if (retval == SIGINT)
4274 job->sigint = 1;
4275#endif
4276 }
4277 retval += 128;
4278 }
Denys Vlasenko883cea42009-07-11 15:31:59 +02004279 TRACE(("getstatus: job %d, nproc %d, status 0x%x, retval 0x%x\n",
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004280 jobno(job), job->nprocs, status, retval));
4281 return retval;
4282}
4283
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02004284static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00004285waitcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004286{
4287 struct job *job;
4288 int retval;
4289 struct job *jp;
4290
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004291 nextopt(nullstr);
4292 retval = 0;
4293
4294 argv = argptr;
4295 if (!*argv) {
4296 /* wait for all jobs */
4297 for (;;) {
4298 jp = curjob;
4299 while (1) {
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004300 if (!jp) /* no running procs */
4301 goto ret;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004302 if (jp->state == JOBRUNNING)
4303 break;
4304 jp->waited = 1;
4305 jp = jp->prev_job;
4306 }
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004307 /* man bash:
4308 * "When bash is waiting for an asynchronous command via
4309 * the wait builtin, the reception of a signal for which a trap
4310 * has been set will cause the wait builtin to return immediately
4311 * with an exit status greater than 128, immediately after which
4312 * the trap is executed."
Denys Vlasenko69188112016-10-27 20:18:18 +02004313 */
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004314 dowait(DOWAIT_BLOCK_OR_SIG, NULL);
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02004315 /* if child sends us a signal *and immediately exits*,
4316 * dowait() returns pid > 0. Check this case,
4317 * not "if (dowait() < 0)"!
4318 */
Denys Vlasenko7c1ed9f2010-05-17 04:42:40 +02004319 if (pending_sig)
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02004320 goto sigout;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004321 }
4322 }
4323
4324 retval = 127;
4325 do {
4326 if (**argv != '%') {
4327 pid_t pid = number(*argv);
4328 job = curjob;
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004329 while (1) {
4330 if (!job)
4331 goto repeat;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004332 if (job->ps[job->nprocs - 1].ps_pid == pid)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004333 break;
4334 job = job->prev_job;
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004335 }
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004336 } else {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004337 job = getjob(*argv, 0);
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004338 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004339 /* loop until process terminated or stopped */
Denys Vlasenko69188112016-10-27 20:18:18 +02004340 while (job->state == JOBRUNNING) {
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004341 dowait(DOWAIT_BLOCK_OR_SIG, NULL);
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02004342 if (pending_sig)
4343 goto sigout;
Denys Vlasenko69188112016-10-27 20:18:18 +02004344 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004345 job->waited = 1;
4346 retval = getstatus(job);
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004347 repeat: ;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004348 } while (*++argv);
4349
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004350 ret:
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004351 return retval;
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02004352 sigout:
4353 retval = 128 + pending_sig;
4354 return retval;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004355}
4356
4357static struct job *
4358growjobtab(void)
4359{
4360 size_t len;
4361 ptrdiff_t offset;
4362 struct job *jp, *jq;
4363
4364 len = njobs * sizeof(*jp);
4365 jq = jobtab;
4366 jp = ckrealloc(jq, len + 4 * sizeof(*jp));
4367
4368 offset = (char *)jp - (char *)jq;
4369 if (offset) {
4370 /* Relocate pointers */
4371 size_t l = len;
4372
4373 jq = (struct job *)((char *)jq + l);
4374 while (l) {
4375 l -= sizeof(*jp);
4376 jq--;
4377#define joff(p) ((struct job *)((char *)(p) + l))
4378#define jmove(p) (p) = (void *)((char *)(p) + offset)
4379 if (joff(jp)->ps == &jq->ps0)
4380 jmove(joff(jp)->ps);
4381 if (joff(jp)->prev_job)
4382 jmove(joff(jp)->prev_job);
4383 }
4384 if (curjob)
4385 jmove(curjob);
4386#undef joff
4387#undef jmove
4388 }
4389
4390 njobs += 4;
4391 jobtab = jp;
4392 jp = (struct job *)((char *)jp + len);
4393 jq = jp + 3;
4394 do {
4395 jq->used = 0;
4396 } while (--jq >= jp);
4397 return jp;
4398}
4399
4400/*
4401 * Return a new job structure.
4402 * Called with interrupts off.
4403 */
4404static struct job *
Denis Vlasenko68404f12008-03-17 09:00:54 +00004405makejob(/*union node *node,*/ int nprocs)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004406{
4407 int i;
4408 struct job *jp;
4409
4410 for (i = njobs, jp = jobtab; ; jp++) {
4411 if (--i < 0) {
4412 jp = growjobtab();
4413 break;
4414 }
4415 if (jp->used == 0)
4416 break;
4417 if (jp->state != JOBDONE || !jp->waited)
4418 continue;
4419#if JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +00004420 if (doing_jobctl)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004421 continue;
4422#endif
4423 freejob(jp);
4424 break;
4425 }
4426 memset(jp, 0, sizeof(*jp));
4427#if JOBS
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004428 /* jp->jobctl is a bitfield.
4429 * "jp->jobctl |= jobctl" likely to give awful code */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00004430 if (doing_jobctl)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004431 jp->jobctl = 1;
4432#endif
4433 jp->prev_job = curjob;
4434 curjob = jp;
4435 jp->used = 1;
4436 jp->ps = &jp->ps0;
4437 if (nprocs > 1) {
4438 jp->ps = ckmalloc(nprocs * sizeof(struct procstat));
4439 }
Denis Vlasenko68404f12008-03-17 09:00:54 +00004440 TRACE(("makejob(%d) returns %%%d\n", nprocs,
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004441 jobno(jp)));
4442 return jp;
4443}
4444
4445#if JOBS
4446/*
4447 * Return a string identifying a command (to be printed by the
4448 * jobs command).
4449 */
4450static char *cmdnextc;
4451
4452static void
4453cmdputs(const char *s)
4454{
Denis Vlasenko92e13c22008-03-25 01:17:40 +00004455 static const char vstype[VSTYPE + 1][3] = {
4456 "", "}", "-", "+", "?", "=",
4457 "%", "%%", "#", "##"
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00004458 IF_ASH_BASH_COMPAT(, ":", "/", "//")
Denis Vlasenko92e13c22008-03-25 01:17:40 +00004459 };
4460
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004461 const char *p, *str;
Denys Vlasenko46a14772009-12-10 21:27:13 +01004462 char cc[2];
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004463 char *nextc;
Denys Vlasenkocd716832009-11-28 22:14:02 +01004464 unsigned char c;
4465 unsigned char subtype = 0;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004466 int quoted = 0;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004467
Denys Vlasenko46a14772009-12-10 21:27:13 +01004468 cc[1] = '\0';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004469 nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
4470 p = s;
Denys Vlasenko46a14772009-12-10 21:27:13 +01004471 while ((c = *p++) != '\0') {
Denis Vlasenkoef527f52008-06-23 01:52:30 +00004472 str = NULL;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004473 switch (c) {
4474 case CTLESC:
4475 c = *p++;
4476 break;
4477 case CTLVAR:
4478 subtype = *p++;
4479 if ((subtype & VSTYPE) == VSLENGTH)
4480 str = "${#";
4481 else
4482 str = "${";
Ron Yorston549deab2015-05-18 09:57:51 +02004483 goto dostr;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004484 case CTLENDVAR:
4485 str = "\"}" + !(quoted & 1);
4486 quoted >>= 1;
4487 subtype = 0;
4488 goto dostr;
4489 case CTLBACKQ:
4490 str = "$(...)";
4491 goto dostr;
Denys Vlasenko0b883582016-12-23 16:49:07 +01004492#if ENABLE_FEATURE_SH_MATH
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004493 case CTLARI:
4494 str = "$((";
4495 goto dostr;
4496 case CTLENDARI:
4497 str = "))";
4498 goto dostr;
4499#endif
4500 case CTLQUOTEMARK:
4501 quoted ^= 1;
4502 c = '"';
4503 break;
4504 case '=':
4505 if (subtype == 0)
4506 break;
4507 if ((subtype & VSTYPE) != VSNORMAL)
4508 quoted <<= 1;
4509 str = vstype[subtype & VSTYPE];
4510 if (subtype & VSNUL)
4511 c = ':';
4512 else
4513 goto checkstr;
4514 break;
4515 case '\'':
4516 case '\\':
4517 case '"':
4518 case '$':
4519 /* These can only happen inside quotes */
4520 cc[0] = c;
4521 str = cc;
4522 c = '\\';
4523 break;
4524 default:
4525 break;
4526 }
4527 USTPUTC(c, nextc);
4528 checkstr:
4529 if (!str)
4530 continue;
4531 dostr:
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02004532 while ((c = *str++) != '\0') {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004533 USTPUTC(c, nextc);
4534 }
Denys Vlasenko46a14772009-12-10 21:27:13 +01004535 } /* while *p++ not NUL */
4536
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004537 if (quoted & 1) {
4538 USTPUTC('"', nextc);
4539 }
4540 *nextc = 0;
4541 cmdnextc = nextc;
4542}
4543
4544/* cmdtxt() and cmdlist() call each other */
4545static void cmdtxt(union node *n);
4546
4547static void
4548cmdlist(union node *np, int sep)
4549{
4550 for (; np; np = np->narg.next) {
4551 if (!sep)
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00004552 cmdputs(" ");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004553 cmdtxt(np);
4554 if (sep && np->narg.next)
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00004555 cmdputs(" ");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004556 }
4557}
4558
4559static void
4560cmdtxt(union node *n)
4561{
4562 union node *np;
4563 struct nodelist *lp;
4564 const char *p;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004565
4566 if (!n)
4567 return;
4568 switch (n->type) {
4569 default:
4570#if DEBUG
4571 abort();
4572#endif
4573 case NPIPE:
4574 lp = n->npipe.cmdlist;
4575 for (;;) {
4576 cmdtxt(lp->n);
4577 lp = lp->next;
4578 if (!lp)
4579 break;
4580 cmdputs(" | ");
4581 }
4582 break;
4583 case NSEMI:
4584 p = "; ";
4585 goto binop;
4586 case NAND:
4587 p = " && ";
4588 goto binop;
4589 case NOR:
4590 p = " || ";
4591 binop:
4592 cmdtxt(n->nbinary.ch1);
4593 cmdputs(p);
4594 n = n->nbinary.ch2;
4595 goto donode;
4596 case NREDIR:
4597 case NBACKGND:
4598 n = n->nredir.n;
4599 goto donode;
4600 case NNOT:
4601 cmdputs("!");
4602 n = n->nnot.com;
4603 donode:
4604 cmdtxt(n);
4605 break;
4606 case NIF:
4607 cmdputs("if ");
4608 cmdtxt(n->nif.test);
4609 cmdputs("; then ");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004610 if (n->nif.elsepart) {
Denys Vlasenko7cee00e2009-07-24 01:08:03 +02004611 cmdtxt(n->nif.ifpart);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004612 cmdputs("; else ");
4613 n = n->nif.elsepart;
Denys Vlasenko7cee00e2009-07-24 01:08:03 +02004614 } else {
4615 n = n->nif.ifpart;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004616 }
4617 p = "; fi";
4618 goto dotail;
4619 case NSUBSHELL:
4620 cmdputs("(");
4621 n = n->nredir.n;
4622 p = ")";
4623 goto dotail;
4624 case NWHILE:
4625 p = "while ";
4626 goto until;
4627 case NUNTIL:
4628 p = "until ";
4629 until:
4630 cmdputs(p);
4631 cmdtxt(n->nbinary.ch1);
4632 n = n->nbinary.ch2;
4633 p = "; done";
4634 dodo:
4635 cmdputs("; do ");
4636 dotail:
4637 cmdtxt(n);
4638 goto dotail2;
4639 case NFOR:
4640 cmdputs("for ");
4641 cmdputs(n->nfor.var);
4642 cmdputs(" in ");
4643 cmdlist(n->nfor.args, 1);
4644 n = n->nfor.body;
4645 p = "; done";
4646 goto dodo;
4647 case NDEFUN:
4648 cmdputs(n->narg.text);
4649 p = "() { ... }";
4650 goto dotail2;
4651 case NCMD:
4652 cmdlist(n->ncmd.args, 1);
4653 cmdlist(n->ncmd.redirect, 0);
4654 break;
4655 case NARG:
4656 p = n->narg.text;
4657 dotail2:
4658 cmdputs(p);
4659 break;
4660 case NHERE:
4661 case NXHERE:
4662 p = "<<...";
4663 goto dotail2;
4664 case NCASE:
4665 cmdputs("case ");
4666 cmdputs(n->ncase.expr->narg.text);
4667 cmdputs(" in ");
4668 for (np = n->ncase.cases; np; np = np->nclist.next) {
4669 cmdtxt(np->nclist.pattern);
4670 cmdputs(") ");
4671 cmdtxt(np->nclist.body);
4672 cmdputs(";; ");
4673 }
4674 p = "esac";
4675 goto dotail2;
4676 case NTO:
4677 p = ">";
4678 goto redir;
4679 case NCLOBBER:
4680 p = ">|";
4681 goto redir;
4682 case NAPPEND:
4683 p = ">>";
4684 goto redir;
Denis Vlasenko559691a2008-10-05 18:39:31 +00004685#if ENABLE_ASH_BASH_COMPAT
4686 case NTO2:
4687#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004688 case NTOFD:
4689 p = ">&";
4690 goto redir;
4691 case NFROM:
4692 p = "<";
4693 goto redir;
4694 case NFROMFD:
4695 p = "<&";
4696 goto redir;
4697 case NFROMTO:
4698 p = "<>";
4699 redir:
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00004700 cmdputs(utoa(n->nfile.fd));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004701 cmdputs(p);
4702 if (n->type == NTOFD || n->type == NFROMFD) {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00004703 cmdputs(utoa(n->ndup.dupfd));
4704 break;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004705 }
4706 n = n->nfile.fname;
4707 goto donode;
4708 }
4709}
4710
4711static char *
4712commandtext(union node *n)
4713{
4714 char *name;
4715
4716 STARTSTACKSTR(cmdnextc);
4717 cmdtxt(n);
4718 name = stackblock();
Denys Vlasenko6a94cee2016-10-25 17:40:25 +02004719 TRACE(("commandtext: name %p, end %p\n", name, cmdnextc));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004720 return ckstrdup(name);
4721}
4722#endif /* JOBS */
4723
4724/*
4725 * Fork off a subshell. If we are doing job control, give the subshell its
4726 * own process group. Jp is a job structure that the job is to be added to.
4727 * N is the command that will be evaluated by the child. Both jp and n may
4728 * be NULL. The mode parameter can be one of the following:
4729 * FORK_FG - Fork off a foreground process.
4730 * FORK_BG - Fork off a background process.
4731 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
4732 * process group even if job control is on.
4733 *
4734 * When job control is turned off, background processes have their standard
4735 * input redirected to /dev/null (except for the second and later processes
4736 * in a pipeline).
4737 *
4738 * Called with interrupts off.
4739 */
4740/*
4741 * Clear traps on a fork.
4742 */
4743static void
4744clear_traps(void)
4745{
4746 char **tp;
4747
Denys Vlasenkob4f51d32016-10-27 12:55:09 +02004748 INT_OFF;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004749 for (tp = trap; tp < &trap[NSIG]; tp++) {
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004750 if (*tp && **tp) { /* trap not NULL or "" (SIG_IGN) */
Denys Vlasenkoe305c282009-09-25 02:12:27 +02004751 if (trap_ptr == trap)
4752 free(*tp);
4753 /* else: it "belongs" to trap_ptr vector, don't free */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004754 *tp = NULL;
Denys Vlasenko0800e3a2009-09-24 03:09:26 +02004755 if ((tp - trap) != 0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004756 setsignal(tp - trap);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004757 }
4758 }
Alexander Shishkinccb97712010-07-25 13:07:39 +02004759 may_have_traps = 0;
Denys Vlasenkob4f51d32016-10-27 12:55:09 +02004760 INT_ON;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004761}
Denis Vlasenkobdc406d2007-07-15 01:13:25 +00004762
4763/* Lives far away from here, needed for forkchild */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004764static void closescript(void);
Denis Vlasenko41770222007-10-07 18:02:52 +00004765
Denis Vlasenkobdc406d2007-07-15 01:13:25 +00004766/* Called after fork(), in child */
Denys Vlasenko70392332016-10-27 02:31:55 +02004767/* jp and n are NULL when called by openhere() for heredoc support */
Denys Vlasenko21d87d42009-09-25 00:06:51 +02004768static NOINLINE void
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02004769forkchild(struct job *jp, union node *n, int mode)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004770{
4771 int oldlvl;
4772
4773 TRACE(("Child shell %d\n", getpid()));
4774 oldlvl = shlvl;
4775 shlvl++;
4776
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004777 /* man bash: "Non-builtin commands run by bash have signal handlers
4778 * set to the values inherited by the shell from its parent".
4779 * Do we do it correctly? */
4780
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004781 closescript();
Denys Vlasenko844f9902009-09-23 03:25:52 +02004782
4783 if (mode == FORK_NOJOB /* is it `xxx` ? */
4784 && n && n->type == NCMD /* is it single cmd? */
4785 /* && n->ncmd.args->type == NARG - always true? */
Denys Vlasenko74269202010-02-21 01:26:42 +01004786 && n->ncmd.args && strcmp(n->ncmd.args->narg.text, "trap") == 0
Denys Vlasenko844f9902009-09-23 03:25:52 +02004787 && n->ncmd.args->narg.next == NULL /* "trap" with no arguments */
4788 /* && n->ncmd.args->narg.backquote == NULL - do we need to check this? */
4789 ) {
4790 TRACE(("Trap hack\n"));
4791 /* Awful hack for `trap` or $(trap).
4792 *
4793 * http://www.opengroup.org/onlinepubs/009695399/utilities/trap.html
4794 * contains an example where "trap" is executed in a subshell:
4795 *
4796 * save_traps=$(trap)
4797 * ...
4798 * eval "$save_traps"
4799 *
4800 * Standard does not say that "trap" in subshell shall print
4801 * parent shell's traps. It only says that its output
4802 * must have suitable form, but then, in the above example
4803 * (which is not supposed to be normative), it implies that.
4804 *
4805 * bash (and probably other shell) does implement it
4806 * (traps are reset to defaults, but "trap" still shows them),
4807 * but as a result, "trap" logic is hopelessly messed up:
4808 *
4809 * # trap
4810 * trap -- 'echo Ho' SIGWINCH <--- we have a handler
4811 * # (trap) <--- trap is in subshell - no output (correct, traps are reset)
4812 * # true | trap <--- trap is in subshell - no output (ditto)
4813 * # echo `true | trap` <--- in subshell - output (but traps are reset!)
4814 * trap -- 'echo Ho' SIGWINCH
4815 * # echo `(trap)` <--- in subshell in subshell - output
4816 * trap -- 'echo Ho' SIGWINCH
4817 * # echo `true | (trap)` <--- in subshell in subshell in subshell - output!
4818 * trap -- 'echo Ho' SIGWINCH
4819 *
4820 * The rules when to forget and when to not forget traps
4821 * get really complex and nonsensical.
4822 *
4823 * Our solution: ONLY bare $(trap) or `trap` is special.
4824 */
Denys Vlasenko8f88d852009-09-25 12:12:53 +02004825 /* Save trap handler strings for trap builtin to print */
Ron Yorstond840c5d2015-07-19 23:05:20 +02004826 trap_ptr = xmemdup(trap, sizeof(trap));
Denys Vlasenko8f88d852009-09-25 12:12:53 +02004827 /* Fall through into clearing traps */
Denys Vlasenko844f9902009-09-23 03:25:52 +02004828 }
Denys Vlasenkoe305c282009-09-25 02:12:27 +02004829 clear_traps();
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004830#if JOBS
4831 /* do job control only in root shell */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00004832 doing_jobctl = 0;
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004833 if (mode != FORK_NOJOB && jp->jobctl && oldlvl == 0) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004834 pid_t pgrp;
4835
4836 if (jp->nprocs == 0)
4837 pgrp = getpid();
4838 else
Denys Vlasenko285ad152009-12-04 23:02:27 +01004839 pgrp = jp->ps[0].ps_pid;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004840 /* this can fail because we are doing it in the parent also */
4841 setpgid(0, pgrp);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004842 if (mode == FORK_FG)
4843 xtcsetpgrp(ttyfd, pgrp);
4844 setsignal(SIGTSTP);
4845 setsignal(SIGTTOU);
4846 } else
4847#endif
4848 if (mode == FORK_BG) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004849 /* man bash: "When job control is not in effect,
4850 * asynchronous commands ignore SIGINT and SIGQUIT" */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004851 ignoresig(SIGINT);
4852 ignoresig(SIGQUIT);
4853 if (jp->nprocs == 0) {
4854 close(0);
4855 if (open(bb_dev_null, O_RDONLY) != 0)
Denis Vlasenko9604e1b2009-03-03 18:47:56 +00004856 ash_msg_and_raise_error("can't open '%s'", bb_dev_null);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004857 }
4858 }
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004859 if (oldlvl == 0) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004860 if (iflag) { /* why if iflag only? */
4861 setsignal(SIGINT);
4862 setsignal(SIGTERM);
4863 }
4864 /* man bash:
4865 * "In all cases, bash ignores SIGQUIT. Non-builtin
4866 * commands run by bash have signal handlers
4867 * set to the values inherited by the shell
4868 * from its parent".
4869 * Take care of the second rule: */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004870 setsignal(SIGQUIT);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004871 }
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02004872#if JOBS
Denys Vlasenko844f9902009-09-23 03:25:52 +02004873 if (n && n->type == NCMD
Denys Vlasenko74269202010-02-21 01:26:42 +01004874 && n->ncmd.args && strcmp(n->ncmd.args->narg.text, "jobs") == 0
Denys Vlasenko844f9902009-09-23 03:25:52 +02004875 ) {
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02004876 TRACE(("Job hack\n"));
Denys Vlasenko844f9902009-09-23 03:25:52 +02004877 /* "jobs": we do not want to clear job list for it,
4878 * instead we remove only _its_ own_ job from job list.
4879 * This makes "jobs .... | cat" more useful.
4880 */
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02004881 freejob(curjob);
4882 return;
4883 }
4884#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004885 for (jp = curjob; jp; jp = jp->prev_job)
4886 freejob(jp);
4887 jobless = 0;
4888}
4889
Denis Vlasenkobdc406d2007-07-15 01:13:25 +00004890/* Called after fork(), in parent */
Denis Vlasenko85c24712008-03-17 09:04:04 +00004891#if !JOBS
4892#define forkparent(jp, n, mode, pid) forkparent(jp, mode, pid)
4893#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004894static void
4895forkparent(struct job *jp, union node *n, int mode, pid_t pid)
4896{
4897 TRACE(("In parent shell: child = %d\n", pid));
4898 if (!jp) {
Denys Vlasenko70392332016-10-27 02:31:55 +02004899 /* jp is NULL when called by openhere() for heredoc support */
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004900 while (jobless && dowait(DOWAIT_NONBLOCK, NULL) > 0)
4901 continue;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004902 jobless++;
4903 return;
4904 }
4905#if JOBS
4906 if (mode != FORK_NOJOB && jp->jobctl) {
4907 int pgrp;
4908
4909 if (jp->nprocs == 0)
4910 pgrp = pid;
4911 else
Denys Vlasenko285ad152009-12-04 23:02:27 +01004912 pgrp = jp->ps[0].ps_pid;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004913 /* This can fail because we are doing it in the child also */
4914 setpgid(pid, pgrp);
4915 }
4916#endif
4917 if (mode == FORK_BG) {
4918 backgndpid = pid; /* set $! */
4919 set_curjob(jp, CUR_RUNNING);
4920 }
4921 if (jp) {
4922 struct procstat *ps = &jp->ps[jp->nprocs++];
Denys Vlasenko285ad152009-12-04 23:02:27 +01004923 ps->ps_pid = pid;
4924 ps->ps_status = -1;
4925 ps->ps_cmd = nullstr;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004926#if JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +00004927 if (doing_jobctl && n)
Denys Vlasenko285ad152009-12-04 23:02:27 +01004928 ps->ps_cmd = commandtext(n);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004929#endif
4930 }
4931}
4932
Denys Vlasenko70392332016-10-27 02:31:55 +02004933/* jp and n are NULL when called by openhere() for heredoc support */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004934static int
4935forkshell(struct job *jp, union node *n, int mode)
4936{
4937 int pid;
4938
4939 TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
4940 pid = fork();
4941 if (pid < 0) {
4942 TRACE(("Fork failed, errno=%d", errno));
4943 if (jp)
4944 freejob(jp);
Denis Vlasenkofa0b56d2008-07-01 16:09:07 +00004945 ash_msg_and_raise_error("can't fork");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004946 }
Denys Vlasenko76ace252009-10-12 15:25:01 +02004947 if (pid == 0) {
4948 CLEAR_RANDOM_T(&random_gen); /* or else $RANDOM repeats in child */
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02004949 forkchild(jp, n, mode);
Denys Vlasenko76ace252009-10-12 15:25:01 +02004950 } else {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004951 forkparent(jp, n, mode, pid);
Denys Vlasenko76ace252009-10-12 15:25:01 +02004952 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004953 return pid;
4954}
4955
4956/*
4957 * Wait for job to finish.
4958 *
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004959 * Under job control we have the problem that while a child process
4960 * is running interrupts generated by the user are sent to the child
4961 * but not to the shell. This means that an infinite loop started by
4962 * an interactive user may be hard to kill. With job control turned off,
4963 * an interactive user may place an interactive program inside a loop.
4964 * If the interactive program catches interrupts, the user doesn't want
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004965 * these interrupts to also abort the loop. The approach we take here
4966 * is to have the shell ignore interrupt signals while waiting for a
4967 * foreground process to terminate, and then send itself an interrupt
4968 * signal if the child process was terminated by an interrupt signal.
4969 * Unfortunately, some programs want to do a bit of cleanup and then
4970 * exit on interrupt; unless these processes terminate themselves by
4971 * sending a signal to themselves (instead of calling exit) they will
4972 * confuse this approach.
4973 *
4974 * Called with interrupts off.
4975 */
4976static int
4977waitforjob(struct job *jp)
4978{
4979 int st;
4980
4981 TRACE(("waitforjob(%%%d) called\n", jobno(jp)));
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004982
4983 INT_OFF;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004984 while (jp->state == JOBRUNNING) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004985 /* In non-interactive shells, we _can_ get
4986 * a keyboard signal here and be EINTRed,
4987 * but we just loop back, waiting for command to complete.
4988 *
4989 * man bash:
4990 * "If bash is waiting for a command to complete and receives
4991 * a signal for which a trap has been set, the trap
4992 * will not be executed until the command completes."
4993 *
4994 * Reality is that even if trap is not set, bash
4995 * will not act on the signal until command completes.
4996 * Try this. sleep5intoff.c:
4997 * #include <signal.h>
4998 * #include <unistd.h>
4999 * int main() {
5000 * sigset_t set;
5001 * sigemptyset(&set);
5002 * sigaddset(&set, SIGINT);
5003 * sigaddset(&set, SIGQUIT);
5004 * sigprocmask(SIG_BLOCK, &set, NULL);
5005 * sleep(5);
5006 * return 0;
5007 * }
5008 * $ bash -c './sleep5intoff; echo hi'
5009 * ^C^C^C^C <--- pressing ^C once a second
5010 * $ _
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005011 * $ bash -c './sleep5intoff; echo hi'
5012 * ^\^\^\^\hi <--- pressing ^\ (SIGQUIT)
5013 * $ _
5014 */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005015 dowait(DOWAIT_BLOCK, jp);
5016 }
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005017 INT_ON;
5018
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005019 st = getstatus(jp);
5020#if JOBS
5021 if (jp->jobctl) {
5022 xtcsetpgrp(ttyfd, rootpid);
5023 /*
5024 * This is truly gross.
5025 * If we're doing job control, then we did a TIOCSPGRP which
5026 * caused us (the shell) to no longer be in the controlling
5027 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
5028 * intuit from the subprocess exit status whether a SIGINT
5029 * occurred, and if so interrupt ourselves. Yuck. - mycroft
5030 */
Denis Vlasenko991a1da2008-02-10 19:02:53 +00005031 if (jp->sigint) /* TODO: do the same with all signals */
5032 raise(SIGINT); /* ... by raise(jp->sig) instead? */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005033 }
5034 if (jp->state == JOBDONE)
5035#endif
5036 freejob(jp);
5037 return st;
5038}
5039
5040/*
5041 * return 1 if there are stopped jobs, otherwise 0
5042 */
5043static int
5044stoppedjobs(void)
5045{
5046 struct job *jp;
5047 int retval;
5048
5049 retval = 0;
5050 if (job_warning)
5051 goto out;
5052 jp = curjob;
5053 if (jp && jp->state == JOBSTOPPED) {
5054 out2str("You have stopped jobs.\n");
5055 job_warning = 2;
5056 retval++;
5057 }
5058 out:
5059 return retval;
5060}
5061
5062
Denys Vlasenko70392332016-10-27 02:31:55 +02005063/*
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005064 * Code for dealing with input/output redirection.
5065 */
5066
Denys Vlasenko8d0e0cd2011-01-25 23:21:46 +01005067#undef EMPTY
5068#undef CLOSED
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005069#define EMPTY -2 /* marks an unused slot in redirtab */
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005070#define CLOSED -3 /* marks a slot of previously-closed fd */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005071
5072/*
5073 * Open a file in noclobber mode.
5074 * The code was copied from bash.
5075 */
5076static int
5077noclobberopen(const char *fname)
5078{
5079 int r, fd;
5080 struct stat finfo, finfo2;
5081
5082 /*
5083 * If the file exists and is a regular file, return an error
5084 * immediately.
5085 */
5086 r = stat(fname, &finfo);
5087 if (r == 0 && S_ISREG(finfo.st_mode)) {
5088 errno = EEXIST;
5089 return -1;
5090 }
5091
5092 /*
5093 * If the file was not present (r != 0), make sure we open it
5094 * exclusively so that if it is created before we open it, our open
5095 * will fail. Make sure that we do not truncate an existing file.
5096 * Note that we don't turn on O_EXCL unless the stat failed -- if the
5097 * file was not a regular file, we leave O_EXCL off.
5098 */
5099 if (r != 0)
5100 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
5101 fd = open(fname, O_WRONLY|O_CREAT, 0666);
5102
5103 /* If the open failed, return the file descriptor right away. */
5104 if (fd < 0)
5105 return fd;
5106
5107 /*
5108 * OK, the open succeeded, but the file may have been changed from a
5109 * non-regular file to a regular file between the stat and the open.
5110 * We are assuming that the O_EXCL open handles the case where FILENAME
5111 * did not exist and is symlinked to an existing file between the stat
5112 * and open.
5113 */
5114
5115 /*
5116 * If we can open it and fstat the file descriptor, and neither check
5117 * revealed that it was a regular file, and the file has not been
5118 * replaced, return the file descriptor.
5119 */
Denys Vlasenko8d3e2252010-08-31 12:42:06 +02005120 if (fstat(fd, &finfo2) == 0
5121 && !S_ISREG(finfo2.st_mode)
5122 && finfo.st_dev == finfo2.st_dev
5123 && finfo.st_ino == finfo2.st_ino
5124 ) {
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005125 return fd;
Denys Vlasenko8d3e2252010-08-31 12:42:06 +02005126 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005127
5128 /* The file has been replaced. badness. */
5129 close(fd);
5130 errno = EEXIST;
5131 return -1;
5132}
5133
5134/*
5135 * Handle here documents. Normally we fork off a process to write the
5136 * data to a pipe. If the document is short, we can stuff the data in
5137 * the pipe without forking.
5138 */
5139/* openhere needs this forward reference */
5140static void expandhere(union node *arg, int fd);
5141static int
5142openhere(union node *redir)
5143{
5144 int pip[2];
5145 size_t len = 0;
5146
5147 if (pipe(pip) < 0)
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00005148 ash_msg_and_raise_error("pipe call failed");
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005149 if (redir->type == NHERE) {
5150 len = strlen(redir->nhere.doc->narg.text);
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005151 if (len <= PIPE_BUF) {
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005152 full_write(pip[1], redir->nhere.doc->narg.text, len);
5153 goto out;
5154 }
5155 }
5156 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
Denis Vlasenko0b769642008-07-24 07:54:57 +00005157 /* child */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005158 close(pip[0]);
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005159 ignoresig(SIGINT); //signal(SIGINT, SIG_IGN);
5160 ignoresig(SIGQUIT); //signal(SIGQUIT, SIG_IGN);
5161 ignoresig(SIGHUP); //signal(SIGHUP, SIG_IGN);
5162 ignoresig(SIGTSTP); //signal(SIGTSTP, SIG_IGN);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005163 signal(SIGPIPE, SIG_DFL);
5164 if (redir->type == NHERE)
5165 full_write(pip[1], redir->nhere.doc->narg.text, len);
Denis Vlasenko0b769642008-07-24 07:54:57 +00005166 else /* NXHERE */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005167 expandhere(redir->nhere.doc, pip[1]);
Bernhard Reutner-Fischer636a1f82008-05-19 09:29:47 +00005168 _exit(EXIT_SUCCESS);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005169 }
5170 out:
5171 close(pip[1]);
5172 return pip[0];
5173}
5174
5175static int
5176openredirect(union node *redir)
5177{
5178 char *fname;
5179 int f;
5180
5181 switch (redir->nfile.type) {
Denys Vlasenko557482c2016-09-25 21:24:04 +02005182/* Can't happen, our single caller does this itself */
5183// case NTOFD:
5184// case NFROMFD:
5185// return -1;
5186 case NHERE:
5187 case NXHERE:
5188 return openhere(redir);
5189 }
5190
5191 /* For N[X]HERE, reading redir->nfile.expfname would touch beyond
5192 * allocated space. Do it only when we know it is safe.
5193 */
5194 fname = redir->nfile.expfname;
5195
5196 switch (redir->nfile.type) {
5197 default:
5198#if DEBUG
5199 abort();
5200#endif
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005201 case NFROM:
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005202 f = open(fname, O_RDONLY);
5203 if (f < 0)
5204 goto eopen;
5205 break;
5206 case NFROMTO:
Andreas Bühmannda75f442010-06-24 04:32:37 +02005207 f = open(fname, O_RDWR|O_CREAT, 0666);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005208 if (f < 0)
5209 goto ecreate;
5210 break;
5211 case NTO:
Denis Vlasenko559691a2008-10-05 18:39:31 +00005212#if ENABLE_ASH_BASH_COMPAT
5213 case NTO2:
5214#endif
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005215 /* Take care of noclobber mode. */
5216 if (Cflag) {
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005217 f = noclobberopen(fname);
5218 if (f < 0)
5219 goto ecreate;
5220 break;
5221 }
5222 /* FALLTHROUGH */
5223 case NCLOBBER:
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005224 f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666);
5225 if (f < 0)
5226 goto ecreate;
5227 break;
5228 case NAPPEND:
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005229 f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666);
5230 if (f < 0)
5231 goto ecreate;
5232 break;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005233 }
5234
5235 return f;
5236 ecreate:
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +00005237 ash_msg_and_raise_error("can't create %s: %s", fname, errmsg(errno, "nonexistent directory"));
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005238 eopen:
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +00005239 ash_msg_and_raise_error("can't open %s: %s", fname, errmsg(errno, "no such file"));
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005240}
5241
5242/*
Denys Vlasenko64774602016-10-26 15:24:30 +02005243 * Copy a file descriptor to be >= 10. Throws exception on error.
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005244 */
5245static int
Denys Vlasenko64774602016-10-26 15:24:30 +02005246savefd(int from)
5247{
5248 int newfd;
5249 int err;
5250
5251 newfd = fcntl(from, F_DUPFD, 10);
5252 err = newfd < 0 ? errno : 0;
5253 if (err != EBADF) {
5254 if (err)
5255 ash_msg_and_raise_error("%d: %m", from);
5256 close(from);
5257 fcntl(newfd, F_SETFD, FD_CLOEXEC);
5258 }
5259
5260 return newfd;
5261}
5262static int
5263dup2_or_raise(int from, int to)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005264{
5265 int newfd;
5266
Denys Vlasenko64774602016-10-26 15:24:30 +02005267 newfd = (from != to) ? dup2(from, to) : to;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005268 if (newfd < 0) {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005269 /* Happens when source fd is not open: try "echo >&99" */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005270 ash_msg_and_raise_error("%d: %m", from);
5271 }
5272 return newfd;
5273}
5274
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005275/* Struct def and variable are moved down to the first usage site */
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005276struct two_fd_t {
5277 int orig, copy;
5278};
Denis Vlasenko0b769642008-07-24 07:54:57 +00005279struct redirtab {
5280 struct redirtab *next;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005281 int pair_count;
Denys Vlasenko606291b2009-09-23 23:15:43 +02005282 struct two_fd_t two_fd[];
Denis Vlasenko0b769642008-07-24 07:54:57 +00005283};
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005284#define redirlist (G_var.redirlist)
Denys Vlasenko64774602016-10-26 15:24:30 +02005285enum {
5286 COPYFD_RESTORE = (int)~(INT_MAX),
5287};
Denis Vlasenko0b769642008-07-24 07:54:57 +00005288
Denys Vlasenko37dc08b2016-10-02 04:38:07 +02005289static int
5290need_to_remember(struct redirtab *rp, int fd)
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005291{
5292 int i;
5293
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005294 if (!rp) /* remembering was not requested */
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005295 return 0;
5296
5297 for (i = 0; i < rp->pair_count; i++) {
5298 if (rp->two_fd[i].orig == fd) {
5299 /* already remembered */
5300 return 0;
5301 }
5302 }
5303 return 1;
5304}
5305
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005306/* "hidden" fd is a fd used to read scripts, or a copy of such */
Denys Vlasenko37dc08b2016-10-02 04:38:07 +02005307static int
5308is_hidden_fd(struct redirtab *rp, int fd)
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005309{
5310 int i;
Denis Vlasenko34c73c42008-08-16 11:48:02 +00005311 struct parsefile *pf;
5312
5313 if (fd == -1)
5314 return 0;
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005315 /* Check open scripts' fds */
Denis Vlasenko34c73c42008-08-16 11:48:02 +00005316 pf = g_parsefile;
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005317 while (pf) {
Denys Vlasenko79b3d422010-06-03 04:29:08 +02005318 /* We skip pf_fd == 0 case because of the following case:
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005319 * $ ash # running ash interactively
5320 * $ . ./script.sh
5321 * and in script.sh: "exec 9>&0".
Denys Vlasenko79b3d422010-06-03 04:29:08 +02005322 * Even though top-level pf_fd _is_ 0,
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005323 * it's still ok to use it: "read" builtin uses it,
5324 * why should we cripple "exec" builtin?
5325 */
Denys Vlasenko79b3d422010-06-03 04:29:08 +02005326 if (pf->pf_fd > 0 && fd == pf->pf_fd) {
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005327 return 1;
5328 }
5329 pf = pf->prev;
5330 }
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005331
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005332 if (!rp)
5333 return 0;
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005334 /* Check saved fds of redirects */
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005335 fd |= COPYFD_RESTORE;
5336 for (i = 0; i < rp->pair_count; i++) {
5337 if (rp->two_fd[i].copy == fd) {
5338 return 1;
5339 }
5340 }
5341 return 0;
5342}
5343
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005344/*
5345 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
5346 * old file descriptors are stashed away so that the redirection can be
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005347 * undone by calling popredir.
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005348 */
5349/* flags passed to redirect */
5350#define REDIR_PUSH 01 /* save previous values of file descriptors */
5351#define REDIR_SAVEFD2 03 /* set preverrout */
5352static void
5353redirect(union node *redir, int flags)
5354{
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005355 struct redirtab *sv;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005356 int sv_pos;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005357 int i;
5358 int fd;
5359 int newfd;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005360 int copied_fd2 = -1;
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005361
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005362 if (!redir) {
5363 return;
5364 }
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005365
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005366 sv = NULL;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005367 sv_pos = 0;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005368 INT_OFF;
5369 if (flags & REDIR_PUSH) {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005370 union node *tmp = redir;
5371 do {
5372 sv_pos++;
Denis Vlasenko559691a2008-10-05 18:39:31 +00005373#if ENABLE_ASH_BASH_COMPAT
Chris Metcalfc3c1fb62010-01-08 13:18:06 +01005374 if (tmp->nfile.type == NTO2)
Denis Vlasenko559691a2008-10-05 18:39:31 +00005375 sv_pos++;
5376#endif
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005377 tmp = tmp->nfile.next;
5378 } while (tmp);
5379 sv = ckmalloc(sizeof(*sv) + sv_pos * sizeof(sv->two_fd[0]));
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005380 sv->next = redirlist;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005381 sv->pair_count = sv_pos;
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005382 redirlist = sv;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005383 while (sv_pos > 0) {
5384 sv_pos--;
5385 sv->two_fd[sv_pos].orig = sv->two_fd[sv_pos].copy = EMPTY;
5386 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005387 }
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005388
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005389 do {
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005390 int right_fd = -1;
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00005391 fd = redir->nfile.fd;
Denis Vlasenko0b769642008-07-24 07:54:57 +00005392 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005393 right_fd = redir->ndup.dupfd;
5394 //bb_error_msg("doing %d > %d", fd, right_fd);
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005395 /* redirect from/to same file descriptor? */
5396 if (right_fd == fd)
5397 continue;
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005398 /* "echo >&10" and 10 is a fd opened to a sh script? */
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005399 if (is_hidden_fd(sv, right_fd)) {
5400 errno = EBADF; /* as if it is closed */
5401 ash_msg_and_raise_error("%d: %m", right_fd);
5402 }
Denis Vlasenko0b769642008-07-24 07:54:57 +00005403 newfd = -1;
5404 } else {
5405 newfd = openredirect(redir); /* always >= 0 */
5406 if (fd == newfd) {
5407 /* Descriptor wasn't open before redirect.
5408 * Mark it for close in the future */
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005409 if (need_to_remember(sv, fd)) {
Denis Vlasenko5a867312008-07-24 19:46:38 +00005410 goto remember_to_close;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005411 }
Denis Vlasenko0b769642008-07-24 07:54:57 +00005412 continue;
5413 }
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005414 }
Denis Vlasenko559691a2008-10-05 18:39:31 +00005415#if ENABLE_ASH_BASH_COMPAT
5416 redirect_more:
5417#endif
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005418 if (need_to_remember(sv, fd)) {
Denis Vlasenko0b769642008-07-24 07:54:57 +00005419 /* Copy old descriptor */
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005420 /* Careful to not accidentally "save"
5421 * to the same fd as right side fd in N>&M */
5422 int minfd = right_fd < 10 ? 10 : right_fd + 1;
Denys Vlasenko86584e12017-01-07 10:15:01 +01005423#if defined(F_DUPFD_CLOEXEC)
5424 i = fcntl(fd, F_DUPFD_CLOEXEC, minfd);
5425#else
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005426 i = fcntl(fd, F_DUPFD, minfd);
Denys Vlasenko86584e12017-01-07 10:15:01 +01005427#endif
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005428 if (i == -1) {
5429 i = errno;
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005430 if (i != EBADF) {
5431 /* Strange error (e.g. "too many files" EMFILE?) */
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005432 if (newfd >= 0)
5433 close(newfd);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005434 errno = i;
5435 ash_msg_and_raise_error("%d: %m", fd);
5436 /* NOTREACHED */
5437 }
Denis Vlasenko5a867312008-07-24 19:46:38 +00005438 /* EBADF: it is not open - good, remember to close it */
5439 remember_to_close:
5440 i = CLOSED;
Denis Vlasenko22f74142008-07-24 22:34:43 +00005441 } else { /* fd is open, save its copy */
Denys Vlasenko86584e12017-01-07 10:15:01 +01005442#if !defined(F_DUPFD_CLOEXEC)
5443 fcntl(i, F_SETFD, FD_CLOEXEC);
5444#endif
Denis Vlasenko22f74142008-07-24 22:34:43 +00005445 /* "exec fd>&-" should not close fds
5446 * which point to script file(s).
5447 * Force them to be restored afterwards */
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005448 if (is_hidden_fd(sv, fd))
5449 i |= COPYFD_RESTORE;
Denis Vlasenko22f74142008-07-24 22:34:43 +00005450 }
Denis Vlasenko5a867312008-07-24 19:46:38 +00005451 if (fd == 2)
5452 copied_fd2 = i;
5453 sv->two_fd[sv_pos].orig = fd;
5454 sv->two_fd[sv_pos].copy = i;
5455 sv_pos++;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005456 }
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005457 if (newfd < 0) {
5458 /* NTOFD/NFROMFD: copy redir->ndup.dupfd to fd */
Denis Vlasenko22f74142008-07-24 22:34:43 +00005459 if (redir->ndup.dupfd < 0) { /* "fd>&-" */
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +00005460 /* Don't want to trigger debugging */
5461 if (fd != -1)
5462 close(fd);
Denis Vlasenko5a867312008-07-24 19:46:38 +00005463 } else {
Denys Vlasenko64774602016-10-26 15:24:30 +02005464 dup2_or_raise(redir->ndup.dupfd, fd);
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005465 }
Denis Vlasenko5a867312008-07-24 19:46:38 +00005466 } else if (fd != newfd) { /* move newfd to fd */
Denys Vlasenko64774602016-10-26 15:24:30 +02005467 dup2_or_raise(newfd, fd);
Denis Vlasenko559691a2008-10-05 18:39:31 +00005468#if ENABLE_ASH_BASH_COMPAT
5469 if (!(redir->nfile.type == NTO2 && fd == 2))
5470#endif
5471 close(newfd);
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005472 }
Denis Vlasenko559691a2008-10-05 18:39:31 +00005473#if ENABLE_ASH_BASH_COMPAT
5474 if (redir->nfile.type == NTO2 && fd == 1) {
5475 /* We already redirected it to fd 1, now copy it to 2 */
5476 newfd = 1;
5477 fd = 2;
5478 goto redirect_more;
5479 }
5480#endif
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00005481 } while ((redir = redir->nfile.next) != NULL);
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005482
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005483 INT_ON;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005484 if ((flags & REDIR_SAVEFD2) && copied_fd2 >= 0)
5485 preverrout_fd = copied_fd2;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005486}
5487
5488/*
5489 * Undo the effects of the last redirection.
5490 */
5491static void
Denis Vlasenko34c73c42008-08-16 11:48:02 +00005492popredir(int drop, int restore)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005493{
5494 struct redirtab *rp;
5495 int i;
5496
Denys Vlasenkoeaf94362016-10-25 21:46:03 +02005497 if (redirlist == NULL)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005498 return;
5499 INT_OFF;
5500 rp = redirlist;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005501 for (i = 0; i < rp->pair_count; i++) {
5502 int fd = rp->two_fd[i].orig;
Denis Vlasenko22f74142008-07-24 22:34:43 +00005503 int copy = rp->two_fd[i].copy;
5504 if (copy == CLOSED) {
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005505 if (!drop)
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005506 close(fd);
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005507 continue;
5508 }
Denis Vlasenko22f74142008-07-24 22:34:43 +00005509 if (copy != EMPTY) {
Denis Vlasenko34c73c42008-08-16 11:48:02 +00005510 if (!drop || (restore && (copy & COPYFD_RESTORE))) {
Denis Vlasenko22f74142008-07-24 22:34:43 +00005511 copy &= ~COPYFD_RESTORE;
Denis Vlasenko5a867312008-07-24 19:46:38 +00005512 /*close(fd);*/
Denys Vlasenko64774602016-10-26 15:24:30 +02005513 dup2_or_raise(copy, fd);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005514 }
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +00005515 close(copy & ~COPYFD_RESTORE);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005516 }
5517 }
5518 redirlist = rp->next;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005519 free(rp);
5520 INT_ON;
5521}
5522
5523/*
5524 * Undo all redirections. Called on error or interrupt.
5525 */
5526
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005527static int
5528redirectsafe(union node *redir, int flags)
5529{
5530 int err;
5531 volatile int saveint;
5532 struct jmploc *volatile savehandler = exception_handler;
5533 struct jmploc jmploc;
5534
5535 SAVE_INT(saveint);
Denis Vlasenko5a867312008-07-24 19:46:38 +00005536 /* "echo 9>/dev/null; echo >&9; echo result: $?" - result should be 1, not 2! */
5537 err = setjmp(jmploc.loc); // huh?? was = setjmp(jmploc.loc) * 2;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005538 if (!err) {
5539 exception_handler = &jmploc;
5540 redirect(redir, flags);
5541 }
5542 exception_handler = savehandler;
Denis Vlasenko7f88e342009-03-19 03:36:18 +00005543 if (err && exception_type != EXERROR)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005544 longjmp(exception_handler->loc, 1);
5545 RESTORE_INT(saveint);
5546 return err;
5547}
5548
5549
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005550/* ============ Routines to expand arguments to commands
5551 *
5552 * We have to deal with backquotes, shell variables, and file metacharacters.
5553 */
5554
Denys Vlasenko0b883582016-12-23 16:49:07 +01005555#if ENABLE_FEATURE_SH_MATH
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005556static arith_t
5557ash_arith(const char *s)
5558{
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005559 arith_state_t math_state;
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005560 arith_t result;
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005561
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005562 math_state.lookupvar = lookupvar;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02005563 math_state.setvar = setvar0;
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005564 //math_state.endofname = endofname;
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005565
5566 INT_OFF;
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005567 result = arith(&math_state, s);
Denys Vlasenko063847d2010-09-15 13:33:02 +02005568 if (math_state.errmsg)
5569 ash_msg_and_raise_error(math_state.errmsg);
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005570 INT_ON;
5571
5572 return result;
5573}
Denis Vlasenko448d30e2008-06-27 00:24:11 +00005574#endif
5575
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005576/*
5577 * expandarg flags
5578 */
5579#define EXP_FULL 0x1 /* perform word splitting & file globbing */
5580#define EXP_TILDE 0x2 /* do normal tilde expansion */
5581#define EXP_VARTILDE 0x4 /* expand tildes in an assignment */
5582#define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */
Denys Vlasenkodb74c6c2016-10-24 21:12:33 +02005583/* ^^^^^^^^^^^^^^ this is meant to support constructs such as "cmd >file*.txt"
5584 * POSIX says for this case:
5585 * Pathname expansion shall not be performed on the word by a
5586 * non-interactive shell; an interactive shell may perform it, but shall
5587 * do so only when the expansion would result in one word.
5588 * Currently, our code complies to the above rule by never globbing
5589 * redirection filenames.
5590 * Bash performs globbing, unless it is non-interactive and in POSIX mode.
5591 * (this means that on a typical Linux distro, bash almost always
5592 * performs globbing, and thus diverges from what we do).
5593 */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005594#define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */
Ron Yorston549deab2015-05-18 09:57:51 +02005595#define EXP_QPAT 0x20 /* pattern in quoted parameter expansion */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005596#define EXP_VARTILDE2 0x40 /* expand tildes after colons only */
5597#define EXP_WORD 0x80 /* expand word in parameter expansion */
Ron Yorston3df47f92015-05-18 09:53:26 +02005598#define EXP_QUOTED 0x100 /* expand word in double quotes */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005599/*
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005600 * rmescape() flags
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005601 */
5602#define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
5603#define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005604#define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */
5605#define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */
Ron Yorston417622c2015-05-18 09:59:14 +02005606#define RMESCAPE_SLASH 0x20 /* Stop globbing after slash */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005607
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005608/* Add CTLESC when necessary. */
Ron Yorston549deab2015-05-18 09:57:51 +02005609#define QUOTES_ESC (EXP_FULL | EXP_CASE | EXP_QPAT | EXP_REDIR)
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005610/* Do not skip NUL characters. */
5611#define QUOTES_KEEPNUL EXP_TILDE
5612
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005613/*
5614 * Structure specifying which parts of the string should be searched
5615 * for IFS characters.
5616 */
5617struct ifsregion {
5618 struct ifsregion *next; /* next region in list */
5619 int begoff; /* offset of start of region */
5620 int endoff; /* offset of end of region */
5621 int nulonly; /* search for nul bytes only */
5622};
5623
5624struct arglist {
5625 struct strlist *list;
5626 struct strlist **lastp;
5627};
5628
5629/* output of current string */
5630static char *expdest;
5631/* list of back quote expressions */
5632static struct nodelist *argbackq;
5633/* first struct in list of ifs regions */
5634static struct ifsregion ifsfirst;
5635/* last struct in list */
5636static struct ifsregion *ifslastp;
5637/* holds expanded arg list */
5638static struct arglist exparg;
5639
5640/*
5641 * Our own itoa().
5642 */
Denys Vlasenko0b883582016-12-23 16:49:07 +01005643#if !ENABLE_FEATURE_SH_MATH
Denys Vlasenko26777aa2010-11-22 23:49:10 +01005644/* cvtnum() is used even if math support is off (to prepare $? values and such) */
5645typedef long arith_t;
5646# define ARITH_FMT "%ld"
5647#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005648static int
5649cvtnum(arith_t num)
5650{
5651 int len;
5652
Denys Vlasenko9c541002015-10-07 15:44:36 +02005653 expdest = makestrspace(sizeof(arith_t)*3 + 2, expdest);
5654 len = fmtstr(expdest, sizeof(arith_t)*3 + 2, ARITH_FMT, num);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005655 STADJUST(len, expdest);
5656 return len;
5657}
5658
Denys Vlasenko455e4222016-10-27 14:45:13 +02005659/*
5660 * Break the argument string into pieces based upon IFS and add the
5661 * strings to the argument list. The regions of the string to be
5662 * searched for IFS characters have been stored by recordregion.
5663 */
5664static void
5665ifsbreakup(char *string, struct arglist *arglist)
5666{
5667 struct ifsregion *ifsp;
5668 struct strlist *sp;
5669 char *start;
5670 char *p;
5671 char *q;
5672 const char *ifs, *realifs;
5673 int ifsspc;
5674 int nulonly;
5675
5676 start = string;
5677 if (ifslastp != NULL) {
5678 ifsspc = 0;
5679 nulonly = 0;
5680 realifs = ifsset() ? ifsval() : defifs;
5681 ifsp = &ifsfirst;
5682 do {
5683 p = string + ifsp->begoff;
5684 nulonly = ifsp->nulonly;
5685 ifs = nulonly ? nullstr : realifs;
5686 ifsspc = 0;
5687 while (p < string + ifsp->endoff) {
5688 q = p;
5689 if ((unsigned char)*p == CTLESC)
5690 p++;
5691 if (!strchr(ifs, *p)) {
5692 p++;
5693 continue;
5694 }
5695 if (!nulonly)
5696 ifsspc = (strchr(defifs, *p) != NULL);
5697 /* Ignore IFS whitespace at start */
5698 if (q == start && ifsspc) {
5699 p++;
5700 start = p;
5701 continue;
5702 }
5703 *q = '\0';
5704 sp = stzalloc(sizeof(*sp));
5705 sp->text = start;
5706 *arglist->lastp = sp;
5707 arglist->lastp = &sp->next;
5708 p++;
5709 if (!nulonly) {
5710 for (;;) {
5711 if (p >= string + ifsp->endoff) {
5712 break;
5713 }
5714 q = p;
5715 if ((unsigned char)*p == CTLESC)
5716 p++;
5717 if (strchr(ifs, *p) == NULL) {
5718 p = q;
5719 break;
5720 }
5721 if (strchr(defifs, *p) == NULL) {
5722 if (ifsspc) {
5723 p++;
5724 ifsspc = 0;
5725 } else {
5726 p = q;
5727 break;
5728 }
5729 } else
5730 p++;
5731 }
5732 }
5733 start = p;
5734 } /* while */
5735 ifsp = ifsp->next;
5736 } while (ifsp != NULL);
5737 if (nulonly)
5738 goto add;
5739 }
5740
5741 if (!*start)
5742 return;
5743
5744 add:
5745 sp = stzalloc(sizeof(*sp));
5746 sp->text = start;
5747 *arglist->lastp = sp;
5748 arglist->lastp = &sp->next;
5749}
5750
5751static void
5752ifsfree(void)
5753{
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02005754 struct ifsregion *p = ifsfirst.next;
5755
5756 if (!p)
5757 goto out;
Denys Vlasenko455e4222016-10-27 14:45:13 +02005758
5759 INT_OFF;
Denys Vlasenko455e4222016-10-27 14:45:13 +02005760 do {
5761 struct ifsregion *ifsp;
5762 ifsp = p->next;
5763 free(p);
5764 p = ifsp;
5765 } while (p);
Denys Vlasenko455e4222016-10-27 14:45:13 +02005766 ifsfirst.next = NULL;
5767 INT_ON;
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02005768 out:
5769 ifslastp = NULL;
Denys Vlasenko455e4222016-10-27 14:45:13 +02005770}
5771
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005772static size_t
5773esclen(const char *start, const char *p)
5774{
5775 size_t esc = 0;
5776
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005777 while (p > start && (unsigned char)*--p == CTLESC) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005778 esc++;
5779 }
5780 return esc;
5781}
5782
5783/*
5784 * Remove any CTLESC characters from a string.
5785 */
5786static char *
Denys Vlasenkob6c84342009-08-29 20:23:20 +02005787rmescapes(char *str, int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005788{
Ron Yorston417622c2015-05-18 09:59:14 +02005789 static const char qchars[] ALIGN1 = {
5790 IF_ASH_BASH_COMPAT('/',) CTLESC, CTLQUOTEMARK, '\0' };
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00005791
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005792 char *p, *q, *r;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005793 unsigned inquotes;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005794 unsigned protect_against_glob;
5795 unsigned globbing;
Ron Yorston417622c2015-05-18 09:59:14 +02005796 IF_ASH_BASH_COMPAT(unsigned slash = flag & RMESCAPE_SLASH;)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005797
Ron Yorston417622c2015-05-18 09:59:14 +02005798 p = strpbrk(str, qchars IF_ASH_BASH_COMPAT(+ !slash));
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005799 if (!p)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005800 return str;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005801
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005802 q = p;
5803 r = str;
5804 if (flag & RMESCAPE_ALLOC) {
5805 size_t len = p - str;
5806 size_t fulllen = len + strlen(p) + 1;
5807
5808 if (flag & RMESCAPE_GROW) {
Colin Watson3963d942010-04-26 14:21:27 +02005809 int strloc = str - (char *)stackblock();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005810 r = makestrspace(fulllen, expdest);
Colin Watson3963d942010-04-26 14:21:27 +02005811 /* p and str may be invalidated by makestrspace */
5812 str = (char *)stackblock() + strloc;
5813 p = str + len;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005814 } else if (flag & RMESCAPE_HEAP) {
5815 r = ckmalloc(fulllen);
5816 } else {
5817 r = stalloc(fulllen);
5818 }
5819 q = r;
5820 if (len > 0) {
Denis Vlasenko29eb3592008-05-18 14:06:08 +00005821 q = (char *)memcpy(q, str, len) + len;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005822 }
5823 }
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005824
Ron Yorston549deab2015-05-18 09:57:51 +02005825 inquotes = 0;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005826 globbing = flag & RMESCAPE_GLOB;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005827 protect_against_glob = globbing;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005828 while (*p) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01005829 if ((unsigned char)*p == CTLQUOTEMARK) {
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005830// Note: both inquotes and protect_against_glob only affect whether
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005831 inquotes = ~inquotes;
5832 p++;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005833 protect_against_glob = globbing;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005834 continue;
5835 }
Ron Yorston549deab2015-05-18 09:57:51 +02005836 if ((unsigned char)*p == CTLESC) {
5837 p++;
Denys Vlasenko13f20912016-09-25 20:54:25 +02005838#if DEBUG
5839 if (*p == '\0')
5840 ash_msg_and_raise_error("CTLESC at EOL (shouldn't happen)");
5841#endif
Ron Yorston549deab2015-05-18 09:57:51 +02005842 if (protect_against_glob) {
5843 *q++ = '\\';
5844 }
5845 } else if (*p == '\\' && !inquotes) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005846 /* naked back slash */
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005847 protect_against_glob = 0;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005848 goto copy;
5849 }
Ron Yorston417622c2015-05-18 09:59:14 +02005850#if ENABLE_ASH_BASH_COMPAT
5851 else if (*p == '/' && slash) {
5852 /* stop handling globbing and mark location of slash */
5853 globbing = slash = 0;
5854 *p = CTLESC;
5855 }
5856#endif
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005857 protect_against_glob = globbing;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005858 copy:
5859 *q++ = *p++;
5860 }
5861 *q = '\0';
5862 if (flag & RMESCAPE_GROW) {
5863 expdest = r;
5864 STADJUST(q - r + 1, expdest);
5865 }
5866 return r;
5867}
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005868#define pmatch(a, b) !fnmatch((a), (b), 0)
5869
5870/*
5871 * Prepare a pattern for a expmeta (internal glob(3)) call.
5872 *
5873 * Returns an stalloced string.
5874 */
5875static char *
Ron Yorston549deab2015-05-18 09:57:51 +02005876preglob(const char *pattern, int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005877{
Ron Yorston549deab2015-05-18 09:57:51 +02005878 return rmescapes((char *)pattern, flag | RMESCAPE_GLOB);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005879}
5880
5881/*
5882 * Put a string on the stack.
5883 */
5884static void
5885memtodest(const char *p, size_t len, int syntax, int quotes)
5886{
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005887 char *q;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005888
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005889 if (!len)
5890 return;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005891
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005892 q = makestrspace((quotes & QUOTES_ESC) ? len * 2 : len, expdest);
5893
5894 do {
Denys Vlasenkocd716832009-11-28 22:14:02 +01005895 unsigned char c = *p++;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005896 if (c) {
Denys Vlasenko2fe66b12016-12-12 17:39:12 +01005897 if (quotes & QUOTES_ESC) {
5898 int n = SIT(c, syntax);
5899 if (n == CCTL
5900 || (((quotes & EXP_FULL) || syntax != BASESYNTAX)
5901 && n == CBACK
5902 )
5903 ) {
5904 USTPUTC(CTLESC, q);
5905 }
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02005906 }
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005907 } else if (!(quotes & QUOTES_KEEPNUL))
5908 continue;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005909 USTPUTC(c, q);
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005910 } while (--len);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005911
5912 expdest = q;
5913}
5914
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005915static size_t
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005916strtodest(const char *p, int syntax, int quotes)
5917{
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005918 size_t len = strlen(p);
5919 memtodest(p, len, syntax, quotes);
5920 return len;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005921}
5922
5923/*
5924 * Record the fact that we have to scan this region of the
5925 * string for IFS characters.
5926 */
5927static void
5928recordregion(int start, int end, int nulonly)
5929{
5930 struct ifsregion *ifsp;
5931
5932 if (ifslastp == NULL) {
5933 ifsp = &ifsfirst;
5934 } else {
5935 INT_OFF;
Denis Vlasenko597906c2008-02-20 16:38:54 +00005936 ifsp = ckzalloc(sizeof(*ifsp));
5937 /*ifsp->next = NULL; - ckzalloc did it */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005938 ifslastp->next = ifsp;
5939 INT_ON;
5940 }
5941 ifslastp = ifsp;
5942 ifslastp->begoff = start;
5943 ifslastp->endoff = end;
5944 ifslastp->nulonly = nulonly;
5945}
5946
5947static void
5948removerecordregions(int endoff)
5949{
5950 if (ifslastp == NULL)
5951 return;
5952
5953 if (ifsfirst.endoff > endoff) {
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02005954 while (ifsfirst.next) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005955 struct ifsregion *ifsp;
5956 INT_OFF;
5957 ifsp = ifsfirst.next->next;
5958 free(ifsfirst.next);
5959 ifsfirst.next = ifsp;
5960 INT_ON;
5961 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02005962 if (ifsfirst.begoff > endoff) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005963 ifslastp = NULL;
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02005964 } else {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005965 ifslastp = &ifsfirst;
5966 ifsfirst.endoff = endoff;
5967 }
5968 return;
5969 }
5970
5971 ifslastp = &ifsfirst;
5972 while (ifslastp->next && ifslastp->next->begoff < endoff)
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02005973 ifslastp = ifslastp->next;
5974 while (ifslastp->next) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005975 struct ifsregion *ifsp;
5976 INT_OFF;
5977 ifsp = ifslastp->next->next;
5978 free(ifslastp->next);
5979 ifslastp->next = ifsp;
5980 INT_ON;
5981 }
5982 if (ifslastp->endoff > endoff)
5983 ifslastp->endoff = endoff;
5984}
5985
5986static char *
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005987exptilde(char *startp, char *p, int flags)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005988{
Denys Vlasenkocd716832009-11-28 22:14:02 +01005989 unsigned char c;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005990 char *name;
5991 struct passwd *pw;
5992 const char *home;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005993 int quotes = flags & QUOTES_ESC;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005994
5995 name = p + 1;
5996
5997 while ((c = *++p) != '\0') {
5998 switch (c) {
5999 case CTLESC:
6000 return startp;
6001 case CTLQUOTEMARK:
6002 return startp;
6003 case ':':
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006004 if (flags & EXP_VARTILDE)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006005 goto done;
6006 break;
6007 case '/':
6008 case CTLENDVAR:
6009 goto done;
6010 }
6011 }
6012 done:
6013 *p = '\0';
6014 if (*name == '\0') {
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02006015 home = lookupvar("HOME");
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006016 } else {
6017 pw = getpwnam(name);
6018 if (pw == NULL)
6019 goto lose;
6020 home = pw->pw_dir;
6021 }
6022 if (!home || !*home)
6023 goto lose;
6024 *p = c;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006025 strtodest(home, SQSYNTAX, quotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006026 return p;
6027 lose:
6028 *p = c;
6029 return startp;
6030}
6031
6032/*
6033 * Execute a command inside back quotes. If it's a builtin command, we
6034 * want to save its output in a block obtained from malloc. Otherwise
6035 * we fork off a subprocess and get the output of the command via a pipe.
6036 * Should be called with interrupts off.
6037 */
6038struct backcmd { /* result of evalbackcmd */
6039 int fd; /* file descriptor to read from */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006040 int nleft; /* number of chars in buffer */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00006041 char *buf; /* buffer */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006042 struct job *jp; /* job structure for command */
6043};
6044
6045/* These forward decls are needed to use "eval" code for backticks handling: */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006046#define EV_EXIT 01 /* exit after evaluating tree */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02006047static int evaltree(union node *, int);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006048
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02006049static void FAST_FUNC
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006050evalbackcmd(union node *n, struct backcmd *result)
6051{
Denys Vlasenko579ad102016-10-25 21:10:20 +02006052 int pip[2];
6053 struct job *jp;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006054
6055 result->fd = -1;
6056 result->buf = NULL;
6057 result->nleft = 0;
6058 result->jp = NULL;
Denys Vlasenko579ad102016-10-25 21:10:20 +02006059 if (n == NULL) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006060 goto out;
Denys Vlasenko579ad102016-10-25 21:10:20 +02006061 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006062
Denys Vlasenko579ad102016-10-25 21:10:20 +02006063 if (pipe(pip) < 0)
6064 ash_msg_and_raise_error("pipe call failed");
6065 jp = makejob(/*n,*/ 1);
6066 if (forkshell(jp, n, FORK_NOJOB) == 0) {
Denys Vlasenko70392332016-10-27 02:31:55 +02006067 /* child */
Denys Vlasenko579ad102016-10-25 21:10:20 +02006068 FORCE_INT_ON;
6069 close(pip[0]);
6070 if (pip[1] != 1) {
6071 /*close(1);*/
Denys Vlasenko64774602016-10-26 15:24:30 +02006072 dup2_or_raise(pip[1], 1);
Denys Vlasenko579ad102016-10-25 21:10:20 +02006073 close(pip[1]);
6074 }
Denys Vlasenko960ca382016-10-25 18:12:15 +02006075/* TODO: eflag clearing makes the following not abort:
6076 * ash -c 'set -e; z=$(false;echo foo); echo $z'
6077 * which is what bash does (unless it is in POSIX mode).
6078 * dash deleted "eflag = 0" line in the commit
6079 * Date: Mon, 28 Jun 2010 17:11:58 +1000
6080 * [EVAL] Don't clear eflag in evalbackcmd
6081 * For now, preserve bash-like behavior, it seems to be somewhat more useful:
6082 */
Denys Vlasenko579ad102016-10-25 21:10:20 +02006083 eflag = 0;
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02006084 ifsfree();
Denys Vlasenko579ad102016-10-25 21:10:20 +02006085 evaltree(n, EV_EXIT); /* actually evaltreenr... */
6086 /* NOTREACHED */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006087 }
Denys Vlasenko70392332016-10-27 02:31:55 +02006088 /* parent */
Denys Vlasenko579ad102016-10-25 21:10:20 +02006089 close(pip[1]);
6090 result->fd = pip[0];
6091 result->jp = jp;
6092
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006093 out:
6094 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
6095 result->fd, result->buf, result->nleft, result->jp));
6096}
6097
6098/*
6099 * Expand stuff in backwards quotes.
6100 */
6101static void
Ron Yorston549deab2015-05-18 09:57:51 +02006102expbackq(union node *cmd, int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006103{
6104 struct backcmd in;
6105 int i;
6106 char buf[128];
6107 char *p;
6108 char *dest;
6109 int startloc;
Ron Yorston549deab2015-05-18 09:57:51 +02006110 int syntax = flag & EXP_QUOTED ? DQSYNTAX : BASESYNTAX;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006111 struct stackmark smark;
6112
6113 INT_OFF;
Denys Vlasenko60ca8342016-09-30 11:21:21 +02006114 startloc = expdest - (char *)stackblock();
6115 pushstackmark(&smark, startloc);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006116 evalbackcmd(cmd, &in);
6117 popstackmark(&smark);
6118
6119 p = in.buf;
6120 i = in.nleft;
6121 if (i == 0)
6122 goto read;
6123 for (;;) {
Ron Yorston549deab2015-05-18 09:57:51 +02006124 memtodest(p, i, syntax, flag & QUOTES_ESC);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006125 read:
6126 if (in.fd < 0)
6127 break;
Ron Yorston61d6ae22015-04-19 10:50:25 +01006128 i = nonblock_immune_read(in.fd, buf, sizeof(buf));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006129 TRACE(("expbackq: read returns %d\n", i));
6130 if (i <= 0)
6131 break;
6132 p = buf;
6133 }
6134
Denis Vlasenko60818682007-09-28 22:07:23 +00006135 free(in.buf);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006136 if (in.fd >= 0) {
6137 close(in.fd);
6138 back_exitstatus = waitforjob(in.jp);
6139 }
6140 INT_ON;
6141
6142 /* Eat all trailing newlines */
6143 dest = expdest;
6144 for (; dest > (char *)stackblock() && dest[-1] == '\n';)
6145 STUNPUTC(dest);
6146 expdest = dest;
6147
Ron Yorston549deab2015-05-18 09:57:51 +02006148 if (!(flag & EXP_QUOTED))
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006149 recordregion(startloc, dest - (char *)stackblock(), 0);
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006150 TRACE(("evalbackq: size:%d:'%.*s'\n",
6151 (int)((dest - (char *)stackblock()) - startloc),
6152 (int)((dest - (char *)stackblock()) - startloc),
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006153 stackblock() + startloc));
6154}
6155
Denys Vlasenko0b883582016-12-23 16:49:07 +01006156#if ENABLE_FEATURE_SH_MATH
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006157/*
6158 * Expand arithmetic expression. Backup to start of expression,
6159 * evaluate, place result in (backed up) result, adjust string position.
6160 */
6161static void
Ron Yorston549deab2015-05-18 09:57:51 +02006162expari(int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006163{
6164 char *p, *start;
6165 int begoff;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006166 int len;
6167
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006168 /* ifsfree(); */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006169
6170 /*
6171 * This routine is slightly over-complicated for
6172 * efficiency. Next we scan backwards looking for the
6173 * start of arithmetic.
6174 */
6175 start = stackblock();
6176 p = expdest - 1;
6177 *p = '\0';
6178 p--;
Denys Vlasenko940c7202011-03-02 04:07:14 +01006179 while (1) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006180 int esc;
6181
Denys Vlasenkocd716832009-11-28 22:14:02 +01006182 while ((unsigned char)*p != CTLARI) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006183 p--;
6184#if DEBUG
6185 if (p < start) {
6186 ash_msg_and_raise_error("missing CTLARI (shouldn't happen)");
6187 }
6188#endif
6189 }
6190
6191 esc = esclen(start, p);
6192 if (!(esc % 2)) {
6193 break;
6194 }
6195
6196 p -= esc + 1;
Denys Vlasenko940c7202011-03-02 04:07:14 +01006197 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006198
6199 begoff = p - start;
6200
6201 removerecordregions(begoff);
6202
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006203 expdest = p;
6204
Ron Yorston549deab2015-05-18 09:57:51 +02006205 if (flag & QUOTES_ESC)
6206 rmescapes(p + 1, 0);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006207
Ron Yorston549deab2015-05-18 09:57:51 +02006208 len = cvtnum(ash_arith(p + 1));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006209
Ron Yorston549deab2015-05-18 09:57:51 +02006210 if (!(flag & EXP_QUOTED))
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006211 recordregion(begoff, begoff + len, 0);
6212}
6213#endif
6214
6215/* argstr needs it */
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006216static char *evalvar(char *p, int flags, struct strlist *var_str_list);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006217
6218/*
6219 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
6220 * characters to allow for further processing. Otherwise treat
6221 * $@ like $* since no splitting will be performed.
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006222 *
6223 * var_str_list (can be NULL) is a list of "VAR=val" strings which take precedence
6224 * over shell varables. Needed for "A=a B=$A; echo $B" case - we use it
6225 * for correct expansion of "B=$A" word.
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006226 */
6227static void
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006228argstr(char *p, int flags, struct strlist *var_str_list)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006229{
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00006230 static const char spclchars[] ALIGN1 = {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006231 '=',
6232 ':',
6233 CTLQUOTEMARK,
6234 CTLENDVAR,
6235 CTLESC,
6236 CTLVAR,
6237 CTLBACKQ,
Denys Vlasenko0b883582016-12-23 16:49:07 +01006238#if ENABLE_FEATURE_SH_MATH
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006239 CTLENDARI,
6240#endif
Denys Vlasenkocd716832009-11-28 22:14:02 +01006241 '\0'
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006242 };
6243 const char *reject = spclchars;
Ron Yorston3df47f92015-05-18 09:53:26 +02006244 int breakall = (flags & (EXP_WORD | EXP_QUOTED)) == EXP_WORD;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006245 int inquotes;
6246 size_t length;
6247 int startloc;
6248
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006249 if (!(flags & EXP_VARTILDE)) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006250 reject += 2;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006251 } else if (flags & EXP_VARTILDE2) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006252 reject++;
6253 }
6254 inquotes = 0;
6255 length = 0;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006256 if (flags & EXP_TILDE) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006257 char *q;
6258
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006259 flags &= ~EXP_TILDE;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006260 tilde:
6261 q = p;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006262 if (*q == '~')
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006263 p = exptilde(p, q, flags);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006264 }
6265 start:
6266 startloc = expdest - (char *)stackblock();
6267 for (;;) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006268 unsigned char c;
6269
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006270 length += strcspn(p + length, reject);
Denys Vlasenkocd716832009-11-28 22:14:02 +01006271 c = p[length];
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006272 if (c) {
6273 if (!(c & 0x80)
Denys Vlasenko0b883582016-12-23 16:49:07 +01006274 IF_FEATURE_SH_MATH(|| c == CTLENDARI)
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006275 ) {
6276 /* c == '=' || c == ':' || c == CTLENDARI */
6277 length++;
6278 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006279 }
6280 if (length > 0) {
6281 int newloc;
6282 expdest = stack_nputstr(p, length, expdest);
6283 newloc = expdest - (char *)stackblock();
6284 if (breakall && !inquotes && newloc > startloc) {
6285 recordregion(startloc, newloc, 0);
6286 }
6287 startloc = newloc;
6288 }
6289 p += length + 1;
6290 length = 0;
6291
6292 switch (c) {
6293 case '\0':
6294 goto breakloop;
6295 case '=':
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006296 if (flags & EXP_VARTILDE2) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006297 p--;
6298 continue;
6299 }
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006300 flags |= EXP_VARTILDE2;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006301 reject++;
6302 /* fall through */
6303 case ':':
6304 /*
6305 * sort of a hack - expand tildes in variable
6306 * assignments (after the first '=' and after ':'s).
6307 */
6308 if (*--p == '~') {
6309 goto tilde;
6310 }
6311 continue;
6312 }
6313
6314 switch (c) {
6315 case CTLENDVAR: /* ??? */
6316 goto breakloop;
6317 case CTLQUOTEMARK:
Ron Yorston549deab2015-05-18 09:57:51 +02006318 inquotes ^= EXP_QUOTED;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006319 /* "$@" syntax adherence hack */
Ron Yorston549deab2015-05-18 09:57:51 +02006320 if (inquotes && !memcmp(p, dolatstr + 1, DOLATSTRLEN - 1)) {
6321 p = evalvar(p + 1, flags | inquotes, /* var_str_list: */ NULL) + 1;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006322 goto start;
6323 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006324 addquote:
Ron Yorston549deab2015-05-18 09:57:51 +02006325 if (flags & QUOTES_ESC) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006326 p--;
6327 length++;
6328 startloc++;
6329 }
6330 break;
6331 case CTLESC:
6332 startloc++;
6333 length++;
Ron Yorston549deab2015-05-18 09:57:51 +02006334
6335 /*
6336 * Quoted parameter expansion pattern: remove quote
6337 * unless inside inner quotes or we have a literal
6338 * backslash.
6339 */
6340 if (((flags | inquotes) & (EXP_QPAT | EXP_QUOTED)) ==
6341 EXP_QPAT && *p != '\\')
6342 break;
6343
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006344 goto addquote;
6345 case CTLVAR:
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02006346 TRACE(("argstr: evalvar('%s')\n", p));
Ron Yorston549deab2015-05-18 09:57:51 +02006347 p = evalvar(p, flags | inquotes, var_str_list);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02006348 TRACE(("argstr: evalvar:'%s'\n", (char *)stackblock()));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006349 goto start;
6350 case CTLBACKQ:
Ron Yorston549deab2015-05-18 09:57:51 +02006351 expbackq(argbackq->n, flags | inquotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006352 argbackq = argbackq->next;
6353 goto start;
Denys Vlasenko0b883582016-12-23 16:49:07 +01006354#if ENABLE_FEATURE_SH_MATH
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006355 case CTLENDARI:
6356 p--;
Ron Yorston549deab2015-05-18 09:57:51 +02006357 expari(flags | inquotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006358 goto start;
6359#endif
6360 }
6361 }
Denys Vlasenko958581a2010-09-12 15:04:27 +02006362 breakloop: ;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006363}
6364
6365static char *
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006366scanleft(char *startp, char *rmesc, char *rmescend UNUSED_PARAM,
6367 char *pattern, int quotes, int zero)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006368{
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006369 char *loc, *loc2;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006370 char c;
6371
6372 loc = startp;
6373 loc2 = rmesc;
6374 do {
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006375 int match;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006376 const char *s = loc2;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006377
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006378 c = *loc2;
6379 if (zero) {
6380 *loc2 = '\0';
6381 s = rmesc;
6382 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006383 match = pmatch(pattern, s);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006384
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006385 *loc2 = c;
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006386 if (match)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006387 return loc;
Denys Vlasenkocd716832009-11-28 22:14:02 +01006388 if (quotes && (unsigned char)*loc == CTLESC)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006389 loc++;
6390 loc++;
6391 loc2++;
6392 } while (c);
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006393 return NULL;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006394}
6395
6396static char *
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006397scanright(char *startp, char *rmesc, char *rmescend,
6398 char *pattern, int quotes, int match_at_start)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006399{
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006400#if !ENABLE_ASH_OPTIMIZE_FOR_SIZE
6401 int try2optimize = match_at_start;
6402#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006403 int esc = 0;
6404 char *loc;
6405 char *loc2;
6406
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006407 /* If we called by "${v/pattern/repl}" or "${v//pattern/repl}":
6408 * startp="escaped_value_of_v" rmesc="raw_value_of_v"
6409 * rmescend=""(ptr to NUL in rmesc) pattern="pattern" quotes=match_at_start=1
6410 * Logic:
6411 * loc starts at NUL at the end of startp, loc2 starts at the end of rmesc,
6412 * and on each iteration they go back two/one char until they reach the beginning.
6413 * We try to find a match in "raw_value_of_v", "raw_value_of_", "raw_value_of" etc.
6414 */
6415 /* TODO: document in what other circumstances we are called. */
6416
6417 for (loc = pattern - 1, loc2 = rmescend; loc >= startp; loc2--) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006418 int match;
6419 char c = *loc2;
6420 const char *s = loc2;
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006421 if (match_at_start) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006422 *loc2 = '\0';
6423 s = rmesc;
6424 }
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006425 match = pmatch(pattern, s);
6426 //bb_error_msg("pmatch(pattern:'%s',s:'%s'):%d", pattern, s, match);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006427 *loc2 = c;
6428 if (match)
6429 return loc;
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006430#if !ENABLE_ASH_OPTIMIZE_FOR_SIZE
6431 if (try2optimize) {
6432 /* Maybe we can optimize this:
6433 * if pattern ends with unescaped *, we can avoid checking
6434 * shorter strings: if "foo*" doesnt match "raw_value_of_v",
6435 * it wont match truncated "raw_value_of_" strings too.
6436 */
6437 unsigned plen = strlen(pattern);
6438 /* Does it end with "*"? */
6439 if (plen != 0 && pattern[--plen] == '*') {
6440 /* "xxxx*" is not escaped */
6441 /* "xxx\*" is escaped */
6442 /* "xx\\*" is not escaped */
6443 /* "x\\\*" is escaped */
6444 int slashes = 0;
6445 while (plen != 0 && pattern[--plen] == '\\')
6446 slashes++;
6447 if (!(slashes & 1))
6448 break; /* ends with unescaped "*" */
6449 }
6450 try2optimize = 0;
6451 }
6452#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006453 loc--;
6454 if (quotes) {
6455 if (--esc < 0) {
6456 esc = esclen(startp, loc);
6457 }
6458 if (esc % 2) {
6459 esc--;
6460 loc--;
6461 }
6462 }
6463 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006464 return NULL;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006465}
6466
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00006467static void varunset(const char *, const char *, const char *, int) NORETURN;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006468static void
6469varunset(const char *end, const char *var, const char *umsg, int varflags)
6470{
6471 const char *msg;
6472 const char *tail;
6473
6474 tail = nullstr;
6475 msg = "parameter not set";
6476 if (umsg) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006477 if ((unsigned char)*end == CTLENDVAR) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006478 if (varflags & VSNUL)
6479 tail = " or null";
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006480 } else {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006481 msg = umsg;
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006482 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006483 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006484 ash_msg_and_raise_error("%.*s: %s%s", (int)(end - var - 1), var, msg, tail);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006485}
6486
6487static const char *
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006488subevalvar(char *p, char *varname, int strloc, int subtype,
Ron Yorston549deab2015-05-18 09:57:51 +02006489 int startloc, int varflags, int flag, struct strlist *var_str_list)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006490{
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006491 struct nodelist *saveargbackq = argbackq;
Ron Yorston549deab2015-05-18 09:57:51 +02006492 int quotes = flag & QUOTES_ESC;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006493 char *startp;
6494 char *loc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006495 char *rmesc, *rmescend;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006496 char *str;
Ron Yorston417622c2015-05-18 09:59:14 +02006497 IF_ASH_BASH_COMPAT(char *repl = NULL;)
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00006498 IF_ASH_BASH_COMPAT(int pos, len, orig_len;)
Denys Vlasenko0b4980c2012-09-25 12:49:29 +02006499 int amount, resetloc;
6500 IF_ASH_BASH_COMPAT(int workloc;)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006501 int zero;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006502 char *(*scan)(char*, char*, char*, char*, int, int);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006503
Denys Vlasenko6040fe82010-09-12 15:03:16 +02006504 //bb_error_msg("subevalvar(p:'%s',varname:'%s',strloc:%d,subtype:%d,startloc:%d,varflags:%x,quotes:%d)",
6505 // p, varname, strloc, subtype, startloc, varflags, quotes);
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006506
Ron Yorstoneb6b48b2015-05-18 09:51:35 +02006507 argstr(p, EXP_TILDE | (subtype != VSASSIGN && subtype != VSQUESTION ?
Ron Yorston549deab2015-05-18 09:57:51 +02006508 (flag & (EXP_QUOTED | EXP_QPAT) ? EXP_QPAT : EXP_CASE) : 0),
6509 var_str_list);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006510 STPUTC('\0', expdest);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006511 argbackq = saveargbackq;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006512 startp = (char *)stackblock() + startloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006513
6514 switch (subtype) {
6515 case VSASSIGN:
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02006516 setvar0(varname, startp);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006517 amount = startp - expdest;
6518 STADJUST(amount, expdest);
6519 return startp;
6520
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006521 case VSQUESTION:
6522 varunset(p, varname, startp, varflags);
6523 /* NOTREACHED */
6524
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006525#if ENABLE_ASH_BASH_COMPAT
6526 case VSSUBSTR:
Denys Vlasenkof8ddbe12016-07-25 03:56:00 +02006527//TODO: support more general format ${v:EXPR:EXPR},
6528// where EXPR follows $(()) rules
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006529 loc = str = stackblock() + strloc;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006530 /* Read POS in ${var:POS:LEN} */
6531 pos = atoi(loc); /* number(loc) errors out on "1:4" */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006532 len = str - startp - 1;
6533
6534 /* *loc != '\0', guaranteed by parser */
6535 if (quotes) {
6536 char *ptr;
6537
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006538 /* Adjust the length by the number of escapes */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006539 for (ptr = startp; ptr < (str - 1); ptr++) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006540 if ((unsigned char)*ptr == CTLESC) {
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006541 len--;
6542 ptr++;
6543 }
6544 }
6545 }
6546 orig_len = len;
6547
6548 if (*loc++ == ':') {
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006549 /* ${var::LEN} */
6550 len = number(loc);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006551 } else {
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006552 /* Skip POS in ${var:POS:LEN} */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006553 len = orig_len;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006554 while (*loc && *loc != ':') {
6555 /* TODO?
6556 * bash complains on: var=qwe; echo ${var:1a:123}
6557 if (!isdigit(*loc))
6558 ash_msg_and_raise_error(msg_illnum, str);
6559 */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006560 loc++;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006561 }
6562 if (*loc++ == ':') {
6563 len = number(loc);
6564 }
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006565 }
Denys Vlasenko08a5dab2014-11-17 20:27:18 +01006566 if (pos < 0) {
6567 /* ${VAR:$((-n)):l} starts n chars from the end */
6568 pos = orig_len + pos;
6569 }
6570 if ((unsigned)pos >= orig_len) {
6571 /* apart from obvious ${VAR:999999:l},
6572 * covers ${VAR:$((-9999999)):l} - result is ""
6573 * (bash-compat)
6574 */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006575 pos = 0;
6576 len = 0;
6577 }
6578 if (len > (orig_len - pos))
6579 len = orig_len - pos;
6580
6581 for (str = startp; pos; str++, pos--) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006582 if (quotes && (unsigned char)*str == CTLESC)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006583 str++;
6584 }
6585 for (loc = startp; len; len--) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006586 if (quotes && (unsigned char)*str == CTLESC)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006587 *loc++ = *str++;
6588 *loc++ = *str++;
6589 }
6590 *loc = '\0';
6591 amount = loc - expdest;
6592 STADJUST(amount, expdest);
6593 return loc;
6594#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006595 }
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006596
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006597 resetloc = expdest - (char *)stackblock();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006598
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006599 /* We'll comeback here if we grow the stack while handling
6600 * a VSREPLACE or VSREPLACEALL, since our pointers into the
6601 * stack will need rebasing, and we'll need to remove our work
6602 * areas each time
6603 */
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00006604 IF_ASH_BASH_COMPAT(restart:)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006605
6606 amount = expdest - ((char *)stackblock() + resetloc);
6607 STADJUST(-amount, expdest);
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006608 startp = (char *)stackblock() + startloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006609
6610 rmesc = startp;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006611 rmescend = (char *)stackblock() + strloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006612 if (quotes) {
Denys Vlasenkob6c84342009-08-29 20:23:20 +02006613 rmesc = rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006614 if (rmesc != startp) {
6615 rmescend = expdest;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006616 startp = (char *)stackblock() + startloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006617 }
6618 }
6619 rmescend--;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006620 str = (char *)stackblock() + strloc;
Ron Yorston417622c2015-05-18 09:59:14 +02006621 /*
6622 * Example: v='a\bc'; echo ${v/\\b/_\\_\z_}
6623 * The result is a_\_z_c (not a\_\_z_c)!
6624 *
6625 * The search pattern and replace string treat backslashes differently!
6626 * RMESCAPE_SLASH causes preglob to work differently on the pattern
6627 * and string. It's only used on the first call.
6628 */
6629 preglob(str, IF_ASH_BASH_COMPAT(
6630 (subtype == VSREPLACE || subtype == VSREPLACEALL) && !repl ?
6631 RMESCAPE_SLASH :) 0);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006632
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006633#if ENABLE_ASH_BASH_COMPAT
Denys Vlasenko0b4980c2012-09-25 12:49:29 +02006634 workloc = expdest - (char *)stackblock();
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006635 if (subtype == VSREPLACE || subtype == VSREPLACEALL) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006636 char *idx, *end;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006637
Denis Vlasenkod6855d12008-09-27 14:03:25 +00006638 if (!repl) {
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02006639 repl = strchr(str, CTLESC);
6640 if (repl)
Ron Yorston417622c2015-05-18 09:59:14 +02006641 *repl++ = '\0';
6642 else
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006643 repl = nullstr;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006644 }
Ron Yorston417622c2015-05-18 09:59:14 +02006645 //bb_error_msg("str:'%s' repl:'%s'", str, repl);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006646
6647 /* If there's no pattern to match, return the expansion unmolested */
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006648 if (str[0] == '\0')
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006649 return NULL;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006650
6651 len = 0;
6652 idx = startp;
6653 end = str - 1;
6654 while (idx < end) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006655 try_to_match:
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006656 loc = scanright(idx, rmesc, rmescend, str, quotes, 1);
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006657 //bb_error_msg("scanright('%s'):'%s'", str, loc);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006658 if (!loc) {
6659 /* No match, advance */
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006660 char *restart_detect = stackblock();
6661 skip_matching:
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006662 STPUTC(*idx, expdest);
Denys Vlasenkocd716832009-11-28 22:14:02 +01006663 if (quotes && (unsigned char)*idx == CTLESC) {
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006664 idx++;
6665 len++;
6666 STPUTC(*idx, expdest);
6667 }
6668 if (stackblock() != restart_detect)
6669 goto restart;
6670 idx++;
6671 len++;
6672 rmesc++;
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006673 /* continue; - prone to quadratic behavior, smarter code: */
6674 if (idx >= end)
6675 break;
6676 if (str[0] == '*') {
6677 /* Pattern is "*foo". If "*foo" does not match "long_string",
6678 * it would never match "ong_string" etc, no point in trying.
6679 */
6680 goto skip_matching;
6681 }
6682 goto try_to_match;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006683 }
6684
6685 if (subtype == VSREPLACEALL) {
6686 while (idx < loc) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006687 if (quotes && (unsigned char)*idx == CTLESC)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006688 idx++;
6689 idx++;
6690 rmesc++;
6691 }
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006692 } else {
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006693 idx = loc;
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006694 }
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006695
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006696 //bb_error_msg("repl:'%s'", repl);
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006697 for (loc = (char*)repl; *loc; loc++) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006698 char *restart_detect = stackblock();
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006699 if (quotes && *loc == '\\') {
6700 STPUTC(CTLESC, expdest);
6701 len++;
6702 }
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006703 STPUTC(*loc, expdest);
6704 if (stackblock() != restart_detect)
6705 goto restart;
6706 len++;
6707 }
6708
6709 if (subtype == VSREPLACE) {
Denys Vlasenkof02c82f2010-08-06 19:14:47 +02006710 //bb_error_msg("tail:'%s', quotes:%x", idx, quotes);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006711 while (*idx) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006712 char *restart_detect = stackblock();
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006713 STPUTC(*idx, expdest);
6714 if (stackblock() != restart_detect)
6715 goto restart;
6716 len++;
6717 idx++;
6718 }
6719 break;
6720 }
6721 }
6722
6723 /* We've put the replaced text into a buffer at workloc, now
6724 * move it to the right place and adjust the stack.
6725 */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006726 STPUTC('\0', expdest);
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006727 startp = (char *)stackblock() + startloc;
6728 memmove(startp, (char *)stackblock() + workloc, len + 1);
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006729 //bb_error_msg("startp:'%s'", startp);
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006730 amount = expdest - (startp + len);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006731 STADJUST(-amount, expdest);
6732 return startp;
6733 }
6734#endif /* ENABLE_ASH_BASH_COMPAT */
6735
6736 subtype -= VSTRIMRIGHT;
6737#if DEBUG
6738 if (subtype < 0 || subtype > 7)
6739 abort();
6740#endif
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006741 /* zero = (subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX) */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006742 zero = subtype >> 1;
6743 /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */
6744 scan = (subtype & 1) ^ zero ? scanleft : scanright;
6745
6746 loc = scan(startp, rmesc, rmescend, str, quotes, zero);
6747 if (loc) {
6748 if (zero) {
6749 memmove(startp, loc, str - loc);
6750 loc = startp + (str - loc) - 1;
6751 }
6752 *loc = '\0';
6753 amount = loc - expdest;
6754 STADJUST(amount, expdest);
6755 }
6756 return loc;
6757}
6758
6759/*
6760 * Add the value of a specialized variable to the stack string.
Denys Vlasenko4d8873f2009-10-04 03:14:41 +02006761 * name parameter (examples):
6762 * ash -c 'echo $1' name:'1='
6763 * ash -c 'echo $qwe' name:'qwe='
6764 * ash -c 'echo $$' name:'$='
6765 * ash -c 'echo ${$}' name:'$='
6766 * ash -c 'echo ${$##q}' name:'$=q'
6767 * ash -c 'echo ${#$}' name:'$='
6768 * note: examples with bad shell syntax:
6769 * ash -c 'echo ${#$1}' name:'$=1'
6770 * ash -c 'echo ${#1#}' name:'1=#'
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006771 */
Denys Vlasenkoadf922e2009-10-08 14:35:37 +02006772static NOINLINE ssize_t
Denys Vlasenko0dd8e452016-10-01 21:02:06 +02006773varvalue(char *name, int varflags, int flags, struct strlist *var_str_list, int *quotedp)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006774{
Mike Frysinger98c52642009-04-02 10:02:37 +00006775 const char *p;
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006776 int num;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006777 int i;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006778 ssize_t len = 0;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006779 int sep;
Denys Vlasenko0dd8e452016-10-01 21:02:06 +02006780 int quoted = *quotedp;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006781 int subtype = varflags & VSTYPE;
6782 int discard = subtype == VSPLUS || subtype == VSLENGTH;
6783 int quotes = (discard ? 0 : (flags & QUOTES_ESC)) | QUOTES_KEEPNUL;
Denys Vlasenko0aaaa502016-10-02 02:46:56 +02006784 int syntax;
6785
6786 sep = (flags & EXP_FULL) << CHAR_BIT;
6787 syntax = quoted ? DQSYNTAX : BASESYNTAX;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006788
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006789 switch (*name) {
6790 case '$':
6791 num = rootpid;
6792 goto numvar;
6793 case '?':
6794 num = exitstatus;
6795 goto numvar;
6796 case '#':
6797 num = shellparam.nparam;
6798 goto numvar;
6799 case '!':
6800 num = backgndpid;
6801 if (num == 0)
6802 return -1;
6803 numvar:
6804 len = cvtnum(num);
Denys Vlasenko4d8873f2009-10-04 03:14:41 +02006805 goto check_1char_name;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006806 case '-':
Mike Frysinger98c52642009-04-02 10:02:37 +00006807 expdest = makestrspace(NOPTS, expdest);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006808 for (i = NOPTS - 1; i >= 0; i--) {
6809 if (optlist[i]) {
Mike Frysinger98c52642009-04-02 10:02:37 +00006810 USTPUTC(optletters(i), expdest);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006811 len++;
6812 }
6813 }
Denys Vlasenko4d8873f2009-10-04 03:14:41 +02006814 check_1char_name:
6815#if 0
6816 /* handles cases similar to ${#$1} */
6817 if (name[2] != '\0')
6818 raise_error_syntax("bad substitution");
6819#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006820 break;
Denys Vlasenko0aaaa502016-10-02 02:46:56 +02006821 case '@':
6822 if (quoted && sep)
6823 goto param;
6824 /* fall through */
6825 case '*': {
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006826 char **ap;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006827 char sepc;
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006828
Denys Vlasenko0aaaa502016-10-02 02:46:56 +02006829 if (quoted)
6830 sep = 0;
6831 sep |= ifsset() ? ifsval()[0] : ' ';
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006832 param:
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006833 sepc = sep;
Denys Vlasenko0dd8e452016-10-01 21:02:06 +02006834 *quotedp = !sepc;
6835 ap = shellparam.p;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006836 if (!ap)
6837 return -1;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006838 while ((p = *ap++) != NULL) {
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006839 len += strtodest(p, syntax, quotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006840
6841 if (*ap && sep) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006842 len++;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006843 memtodest(&sepc, 1, syntax, quotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006844 }
6845 }
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006846 break;
Denys Vlasenko0aaaa502016-10-02 02:46:56 +02006847 } /* case '*' */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006848 case '0':
6849 case '1':
6850 case '2':
6851 case '3':
6852 case '4':
6853 case '5':
6854 case '6':
6855 case '7':
6856 case '8':
6857 case '9':
Denys Vlasenkoa00329c2009-08-30 20:05:10 +02006858 num = atoi(name); /* number(name) fails on ${N#str} etc */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006859 if (num < 0 || num > shellparam.nparam)
6860 return -1;
6861 p = num ? shellparam.p[num - 1] : arg0;
6862 goto value;
6863 default:
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006864 /* NB: name has form "VAR=..." */
6865
6866 /* "A=a B=$A" case: var_str_list is a list of "A=a" strings
6867 * which should be considered before we check variables. */
6868 if (var_str_list) {
6869 unsigned name_len = (strchrnul(name, '=') - name) + 1;
6870 p = NULL;
6871 do {
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00006872 char *str, *eq;
6873 str = var_str_list->text;
6874 eq = strchr(str, '=');
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006875 if (!eq) /* stop at first non-assignment */
6876 break;
6877 eq++;
Denis Vlasenko6b06cb82008-05-15 21:30:45 +00006878 if (name_len == (unsigned)(eq - str)
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006879 && strncmp(str, name, name_len) == 0
6880 ) {
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006881 p = eq;
6882 /* goto value; - WRONG! */
6883 /* think "A=1 A=2 B=$A" */
6884 }
6885 var_str_list = var_str_list->next;
6886 } while (var_str_list);
6887 if (p)
6888 goto value;
6889 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006890 p = lookupvar(name);
6891 value:
6892 if (!p)
6893 return -1;
6894
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006895 len = strtodest(p, syntax, quotes);
Denys Vlasenkoc76236f2014-12-29 00:04:18 +01006896#if ENABLE_UNICODE_SUPPORT
6897 if (subtype == VSLENGTH && len > 0) {
6898 reinit_unicode_for_ash();
6899 if (unicode_status == UNICODE_ON) {
Ron Yorston3e3bfb82016-03-18 11:29:19 +00006900 STADJUST(-len, expdest);
6901 discard = 0;
Denys Vlasenkoc76236f2014-12-29 00:04:18 +01006902 len = unicode_strlen(p);
6903 }
6904 }
6905#endif
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006906 break;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006907 }
6908
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006909 if (discard)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006910 STADJUST(-len, expdest);
6911 return len;
6912}
6913
6914/*
6915 * Expand a variable, and return a pointer to the next character in the
6916 * input string.
6917 */
6918static char *
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02006919evalvar(char *p, int flag, struct strlist *var_str_list)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006920{
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006921 char varflags;
6922 char subtype;
Ron Yorston549deab2015-05-18 09:57:51 +02006923 int quoted;
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006924 char easy;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006925 char *var;
6926 int patloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006927 int startloc;
6928 ssize_t varlen;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006929
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006930 varflags = (unsigned char) *p++;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006931 subtype = varflags & VSTYPE;
Denys Vlasenko88e15702016-10-26 01:55:56 +02006932
6933 if (!subtype)
6934 raise_error_syntax("bad substitution");
6935
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02006936 quoted = flag & EXP_QUOTED;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006937 var = p;
6938 easy = (!quoted || (*var == '@' && shellparam.nparam));
6939 startloc = expdest - (char *)stackblock();
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02006940 p = strchr(p, '=') + 1; //TODO: use var_end(p)?
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006941
6942 again:
Denys Vlasenko0dd8e452016-10-01 21:02:06 +02006943 varlen = varvalue(var, varflags, flag, var_str_list, &quoted);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006944 if (varflags & VSNUL)
6945 varlen--;
6946
6947 if (subtype == VSPLUS) {
6948 varlen = -1 - varlen;
6949 goto vsplus;
6950 }
6951
6952 if (subtype == VSMINUS) {
6953 vsplus:
6954 if (varlen < 0) {
6955 argstr(
Denys Vlasenko6040fe82010-09-12 15:03:16 +02006956 p,
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02006957 flag | EXP_TILDE | EXP_WORD,
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006958 var_str_list
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006959 );
6960 goto end;
6961 }
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02006962 goto record;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006963 }
6964
6965 if (subtype == VSASSIGN || subtype == VSQUESTION) {
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02006966 if (varlen >= 0)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006967 goto record;
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02006968
6969 subevalvar(p, var, 0, subtype, startloc, varflags,
6970 flag & ~QUOTES_ESC, var_str_list);
6971 varflags &= ~VSNUL;
6972 /*
6973 * Remove any recorded regions beyond
6974 * start of variable
6975 */
6976 removerecordregions(startloc);
6977 goto again;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006978 }
6979
6980 if (varlen < 0 && uflag)
6981 varunset(p, var, 0, 0);
6982
6983 if (subtype == VSLENGTH) {
Denys Vlasenkoc76236f2014-12-29 00:04:18 +01006984 cvtnum(varlen > 0 ? varlen : 0);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006985 goto record;
6986 }
6987
6988 if (subtype == VSNORMAL) {
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02006989 record:
6990 if (!easy)
6991 goto end;
Denys Vlasenko0dd8e452016-10-01 21:02:06 +02006992 recordregion(startloc, expdest - (char *)stackblock(), quoted);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006993 goto end;
6994 }
6995
6996#if DEBUG
6997 switch (subtype) {
6998 case VSTRIMLEFT:
6999 case VSTRIMLEFTMAX:
7000 case VSTRIMRIGHT:
7001 case VSTRIMRIGHTMAX:
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007002#if ENABLE_ASH_BASH_COMPAT
7003 case VSSUBSTR:
7004 case VSREPLACE:
7005 case VSREPLACEALL:
7006#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007007 break;
7008 default:
7009 abort();
7010 }
7011#endif
7012
7013 if (varlen >= 0) {
7014 /*
7015 * Terminate the string and start recording the pattern
7016 * right after it
7017 */
7018 STPUTC('\0', expdest);
7019 patloc = expdest - (char *)stackblock();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02007020 if (NULL == subevalvar(p, /* varname: */ NULL, patloc, subtype,
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007021 startloc, varflags, flag, var_str_list)) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007022 int amount = expdest - (
7023 (char *)stackblock() + patloc - 1
7024 );
7025 STADJUST(-amount, expdest);
7026 }
7027 /* Remove any recorded regions beyond start of variable */
7028 removerecordregions(startloc);
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007029 goto record;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007030 }
7031
7032 end:
7033 if (subtype != VSNORMAL) { /* skip to end of alternative */
7034 int nesting = 1;
7035 for (;;) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01007036 unsigned char c = *p++;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007037 if (c == CTLESC)
7038 p++;
Ron Yorston549deab2015-05-18 09:57:51 +02007039 else if (c == CTLBACKQ) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007040 if (varlen >= 0)
7041 argbackq = argbackq->next;
7042 } else if (c == CTLVAR) {
7043 if ((*p++ & VSTYPE) != VSNORMAL)
7044 nesting++;
7045 } else if (c == CTLENDVAR) {
7046 if (--nesting == 0)
7047 break;
7048 }
7049 }
7050 }
7051 return p;
7052}
7053
7054/*
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007055 * Add a file name to the list.
7056 */
7057static void
7058addfname(const char *name)
7059{
7060 struct strlist *sp;
7061
Denis Vlasenko597906c2008-02-20 16:38:54 +00007062 sp = stzalloc(sizeof(*sp));
Denys Vlasenko8e2bc472016-09-28 23:02:57 +02007063 sp->text = sstrdup(name);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007064 *exparg.lastp = sp;
7065 exparg.lastp = &sp->next;
7066}
7067
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007068/* If we want to use glob() from libc... */
Denys Vlasenko514b51d2016-10-01 14:33:08 +02007069#if !ENABLE_ASH_INTERNAL_GLOB
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007070
7071/* Add the result of glob() to the list */
7072static void
7073addglob(const glob_t *pglob)
7074{
7075 char **p = pglob->gl_pathv;
7076
7077 do {
7078 addfname(*p);
7079 } while (*++p);
7080}
7081static void
7082expandmeta(struct strlist *str /*, int flag*/)
7083{
7084 /* TODO - EXP_REDIR */
7085
7086 while (str) {
7087 char *p;
7088 glob_t pglob;
7089 int i;
7090
7091 if (fflag)
7092 goto nometa;
Denys Vlasenkod4f3db92016-10-30 18:41:01 +01007093
7094 /* Avoid glob() (and thus, stat() et al) for words like "echo" */
7095 p = str->text;
7096 while (*p) {
7097 if (*p == '*')
7098 goto need_glob;
7099 if (*p == '?')
7100 goto need_glob;
7101 if (*p == '[')
7102 goto need_glob;
7103 p++;
7104 }
7105 goto nometa;
7106
7107 need_glob:
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007108 INT_OFF;
7109 p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP);
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007110// GLOB_NOMAGIC (GNU): if no *?[ chars in pattern, return it even if no match
7111// GLOB_NOCHECK: if no match, return unchanged pattern (sans \* escapes?)
7112//
7113// glibc 2.24.90 glob(GLOB_NOMAGIC) does not remove backslashes used for escaping:
7114// if you pass it "file\?", it returns "file\?", not "file?", if no match.
7115// Which means you need to unescape the string, right? Not so fast:
7116// if there _is_ a file named "file\?" (with backslash), it is returned
7117// as "file\?" too (whichever pattern you used to find it, say, "file*").
7118// You DONT KNOW by looking at the result whether you need to unescape it.
7119//
7120// Worse, globbing of "file\?" in a directory with two files, "file?" and "file\?",
7121// returns "file\?" - which is WRONG: "file\?" pattern matches "file?" file.
7122// Without GLOB_NOMAGIC, this works correctly ("file?" is returned as a match).
7123// With GLOB_NOMAGIC | GLOB_NOCHECK, this also works correctly.
7124// i = glob(p, GLOB_NOMAGIC | GLOB_NOCHECK, NULL, &pglob);
7125// i = glob(p, GLOB_NOMAGIC, NULL, &pglob);
7126 i = glob(p, 0, NULL, &pglob);
7127 //bb_error_msg("glob('%s'):%d '%s'...", p, i, pglob.gl_pathv ? pglob.gl_pathv[0] : "-");
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007128 if (p != str->text)
7129 free(p);
7130 switch (i) {
7131 case 0:
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007132#if 0 // glibc 2.24.90 bug? Patterns like "*/file", when match, don't set GLOB_MAGCHAR
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007133 /* GLOB_MAGCHAR is set if *?[ chars were seen (GNU) */
7134 if (!(pglob.gl_flags & GLOB_MAGCHAR))
7135 goto nometa2;
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007136#endif
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007137 addglob(&pglob);
7138 globfree(&pglob);
7139 INT_ON;
7140 break;
7141 case GLOB_NOMATCH:
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007142 //nometa2:
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007143 globfree(&pglob);
7144 INT_ON;
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007145 nometa:
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007146 *exparg.lastp = str;
7147 rmescapes(str->text, 0);
7148 exparg.lastp = &str->next;
7149 break;
7150 default: /* GLOB_NOSPACE */
7151 globfree(&pglob);
7152 INT_ON;
7153 ash_msg_and_raise_error(bb_msg_memory_exhausted);
7154 }
7155 str = str->next;
7156 }
7157}
7158
7159#else
Denys Vlasenko514b51d2016-10-01 14:33:08 +02007160/* ENABLE_ASH_INTERNAL_GLOB: Homegrown globbing code. (dash also has both, uses homegrown one.) */
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007161
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007162/*
7163 * Do metacharacter (i.e. *, ?, [...]) expansion.
7164 */
7165static void
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007166expmeta(char *expdir, char *enddir, char *name)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007167{
7168 char *p;
7169 const char *cp;
7170 char *start;
7171 char *endname;
7172 int metaflag;
7173 struct stat statb;
7174 DIR *dirp;
7175 struct dirent *dp;
7176 int atend;
7177 int matchdot;
Ron Yorstonca25af92015-09-04 10:32:41 +01007178 int esc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007179
7180 metaflag = 0;
7181 start = name;
Ron Yorstonca25af92015-09-04 10:32:41 +01007182 for (p = name; esc = 0, *p; p += esc + 1) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007183 if (*p == '*' || *p == '?')
7184 metaflag = 1;
7185 else if (*p == '[') {
7186 char *q = p + 1;
7187 if (*q == '!')
7188 q++;
7189 for (;;) {
7190 if (*q == '\\')
7191 q++;
7192 if (*q == '/' || *q == '\0')
7193 break;
7194 if (*++q == ']') {
7195 metaflag = 1;
7196 break;
7197 }
7198 }
Ron Yorstonca25af92015-09-04 10:32:41 +01007199 } else {
7200 if (*p == '\\')
7201 esc++;
7202 if (p[esc] == '/') {
7203 if (metaflag)
7204 break;
7205 start = p + esc + 1;
7206 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007207 }
7208 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007209 if (metaflag == 0) { /* we've reached the end of the file name */
7210 if (enddir != expdir)
7211 metaflag++;
7212 p = name;
7213 do {
7214 if (*p == '\\')
7215 p++;
7216 *enddir++ = *p;
7217 } while (*p++);
7218 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
7219 addfname(expdir);
7220 return;
7221 }
7222 endname = p;
7223 if (name < start) {
7224 p = name;
7225 do {
7226 if (*p == '\\')
7227 p++;
7228 *enddir++ = *p++;
7229 } while (p < start);
7230 }
7231 if (enddir == expdir) {
7232 cp = ".";
7233 } else if (enddir == expdir + 1 && *expdir == '/') {
7234 cp = "/";
7235 } else {
7236 cp = expdir;
7237 enddir[-1] = '\0';
7238 }
7239 dirp = opendir(cp);
7240 if (dirp == NULL)
7241 return;
7242 if (enddir != expdir)
7243 enddir[-1] = '/';
7244 if (*endname == 0) {
7245 atend = 1;
7246 } else {
7247 atend = 0;
Ron Yorstonca25af92015-09-04 10:32:41 +01007248 *endname = '\0';
7249 endname += esc + 1;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007250 }
7251 matchdot = 0;
7252 p = start;
7253 if (*p == '\\')
7254 p++;
7255 if (*p == '.')
7256 matchdot++;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02007257 while (!pending_int && (dp = readdir(dirp)) != NULL) {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00007258 if (dp->d_name[0] == '.' && !matchdot)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007259 continue;
7260 if (pmatch(start, dp->d_name)) {
7261 if (atend) {
7262 strcpy(enddir, dp->d_name);
7263 addfname(expdir);
7264 } else {
7265 for (p = enddir, cp = dp->d_name; (*p++ = *cp++) != '\0';)
7266 continue;
7267 p[-1] = '/';
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007268 expmeta(expdir, p, endname);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007269 }
7270 }
7271 }
7272 closedir(dirp);
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00007273 if (!atend)
Ron Yorstonca25af92015-09-04 10:32:41 +01007274 endname[-esc - 1] = esc ? '\\' : '/';
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007275}
7276
7277static struct strlist *
7278msort(struct strlist *list, int len)
7279{
7280 struct strlist *p, *q = NULL;
7281 struct strlist **lpp;
7282 int half;
7283 int n;
7284
7285 if (len <= 1)
7286 return list;
7287 half = len >> 1;
7288 p = list;
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +00007289 for (n = half; --n >= 0;) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007290 q = p;
7291 p = p->next;
7292 }
7293 q->next = NULL; /* terminate first half of list */
7294 q = msort(list, half); /* sort first half of list */
7295 p = msort(p, len - half); /* sort second half */
7296 lpp = &list;
7297 for (;;) {
7298#if ENABLE_LOCALE_SUPPORT
7299 if (strcoll(p->text, q->text) < 0)
7300#else
7301 if (strcmp(p->text, q->text) < 0)
7302#endif
7303 {
7304 *lpp = p;
7305 lpp = &p->next;
7306 p = *lpp;
7307 if (p == NULL) {
7308 *lpp = q;
7309 break;
7310 }
7311 } else {
7312 *lpp = q;
7313 lpp = &q->next;
7314 q = *lpp;
7315 if (q == NULL) {
7316 *lpp = p;
7317 break;
7318 }
7319 }
7320 }
7321 return list;
7322}
7323
7324/*
7325 * Sort the results of file name expansion. It calculates the number of
7326 * strings to sort and then calls msort (short for merge sort) to do the
7327 * work.
7328 */
7329static struct strlist *
7330expsort(struct strlist *str)
7331{
7332 int len;
7333 struct strlist *sp;
7334
7335 len = 0;
7336 for (sp = str; sp; sp = sp->next)
7337 len++;
7338 return msort(str, len);
7339}
7340
7341static void
Denis Vlasenko68404f12008-03-17 09:00:54 +00007342expandmeta(struct strlist *str /*, int flag*/)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007343{
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00007344 static const char metachars[] ALIGN1 = {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007345 '*', '?', '[', 0
7346 };
7347 /* TODO - EXP_REDIR */
7348
7349 while (str) {
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007350 char *expdir;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007351 struct strlist **savelastp;
7352 struct strlist *sp;
7353 char *p;
7354
7355 if (fflag)
7356 goto nometa;
7357 if (!strpbrk(str->text, metachars))
7358 goto nometa;
7359 savelastp = exparg.lastp;
7360
7361 INT_OFF;
Ron Yorston549deab2015-05-18 09:57:51 +02007362 p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007363 {
7364 int i = strlen(str->text);
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007365//BUGGY estimation of how long expanded name can be
7366 expdir = ckmalloc(i < 2048 ? 2048 : i+1);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007367 }
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007368 expmeta(expdir, expdir, p);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007369 free(expdir);
7370 if (p != str->text)
7371 free(p);
7372 INT_ON;
7373 if (exparg.lastp == savelastp) {
7374 /*
7375 * no matches
7376 */
7377 nometa:
7378 *exparg.lastp = str;
Denys Vlasenkob6c84342009-08-29 20:23:20 +02007379 rmescapes(str->text, 0);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007380 exparg.lastp = &str->next;
7381 } else {
7382 *exparg.lastp = NULL;
7383 *savelastp = sp = expsort(*savelastp);
7384 while (sp->next != NULL)
7385 sp = sp->next;
7386 exparg.lastp = &sp->next;
7387 }
7388 str = str->next;
7389 }
7390}
Denys Vlasenko514b51d2016-10-01 14:33:08 +02007391#endif /* ENABLE_ASH_INTERNAL_GLOB */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007392
7393/*
7394 * Perform variable substitution and command substitution on an argument,
7395 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
7396 * perform splitting and file name expansion. When arglist is NULL, perform
7397 * here document expansion.
7398 */
7399static void
7400expandarg(union node *arg, struct arglist *arglist, int flag)
7401{
7402 struct strlist *sp;
7403 char *p;
7404
7405 argbackq = arg->narg.backquote;
7406 STARTSTACKSTR(expdest);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02007407 TRACE(("expandarg: argstr('%s',flags:%x)\n", arg->narg.text, flag));
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00007408 argstr(arg->narg.text, flag,
7409 /* var_str_list: */ arglist ? arglist->list : NULL);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007410 p = _STPUTC('\0', expdest);
7411 expdest = p - 1;
7412 if (arglist == NULL) {
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02007413 /* here document expanded */
7414 goto out;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007415 }
7416 p = grabstackstr(p);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02007417 TRACE(("expandarg: p:'%s'\n", p));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007418 exparg.lastp = &exparg.list;
7419 /*
7420 * TODO - EXP_REDIR
7421 */
7422 if (flag & EXP_FULL) {
7423 ifsbreakup(p, &exparg);
7424 *exparg.lastp = NULL;
7425 exparg.lastp = &exparg.list;
Denis Vlasenko68404f12008-03-17 09:00:54 +00007426 expandmeta(exparg.list /*, flag*/);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007427 } else {
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02007428 if (flag & EXP_REDIR) { /*XXX - for now, just remove escapes */
Denys Vlasenkob6c84342009-08-29 20:23:20 +02007429 rmescapes(p, 0);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02007430 TRACE(("expandarg: rmescapes:'%s'\n", p));
7431 }
Denis Vlasenko597906c2008-02-20 16:38:54 +00007432 sp = stzalloc(sizeof(*sp));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007433 sp->text = p;
7434 *exparg.lastp = sp;
7435 exparg.lastp = &sp->next;
7436 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007437 *exparg.lastp = NULL;
7438 if (exparg.list) {
7439 *arglist->lastp = exparg.list;
7440 arglist->lastp = exparg.lastp;
7441 }
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02007442
7443 out:
7444 ifsfree();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007445}
7446
7447/*
7448 * Expand shell variables and backquotes inside a here document.
7449 */
7450static void
7451expandhere(union node *arg, int fd)
7452{
Ron Yorston549deab2015-05-18 09:57:51 +02007453 expandarg(arg, (struct arglist *)NULL, EXP_QUOTED);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007454 full_write(fd, stackblock(), expdest - (char *)stackblock());
7455}
7456
7457/*
7458 * Returns true if the pattern matches the string.
7459 */
7460static int
7461patmatch(char *pattern, const char *string)
7462{
Ron Yorston549deab2015-05-18 09:57:51 +02007463 return pmatch(preglob(pattern, 0), string);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007464}
7465
7466/*
7467 * See if a pattern matches in a case statement.
7468 */
7469static int
7470casematch(union node *pattern, char *val)
7471{
7472 struct stackmark smark;
7473 int result;
7474
7475 setstackmark(&smark);
7476 argbackq = pattern->narg.backquote;
7477 STARTSTACKSTR(expdest);
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00007478 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE,
7479 /* var_str_list: */ NULL);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007480 STACKSTRNUL(expdest);
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02007481 ifsfree();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007482 result = patmatch(stackblock(), val);
7483 popstackmark(&smark);
7484 return result;
7485}
7486
7487
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007488/* ============ find_command */
7489
7490struct builtincmd {
7491 const char *name;
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02007492 int (*builtin)(int, char **) FAST_FUNC;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007493 /* unsigned flags; */
7494};
7495#define IS_BUILTIN_SPECIAL(b) ((b)->name[0] & 1)
Denis Vlasenkoe26b2782008-02-12 07:40:29 +00007496/* "regular" builtins always take precedence over commands,
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007497 * regardless of PATH=....%builtin... position */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007498#define IS_BUILTIN_REGULAR(b) ((b)->name[0] & 2)
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007499#define IS_BUILTIN_ASSIGN(b) ((b)->name[0] & 4)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007500
7501struct cmdentry {
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00007502 smallint cmdtype; /* CMDxxx */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007503 union param {
7504 int index;
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00007505 /* index >= 0 for commands without path (slashes) */
7506 /* (TODO: what exactly does the value mean? PATH position?) */
7507 /* index == -1 for commands with slashes */
7508 /* index == (-2 - applet_no) for NOFORK applets */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007509 const struct builtincmd *cmd;
7510 struct funcnode *func;
7511 } u;
7512};
7513/* values of cmdtype */
7514#define CMDUNKNOWN -1 /* no entry in table for command */
7515#define CMDNORMAL 0 /* command is an executable program */
7516#define CMDFUNCTION 1 /* command is a shell function */
7517#define CMDBUILTIN 2 /* command is a shell builtin */
7518
7519/* action to find_command() */
7520#define DO_ERR 0x01 /* prints errors */
7521#define DO_ABS 0x02 /* checks absolute paths */
7522#define DO_NOFUNC 0x04 /* don't return shell functions, for command */
7523#define DO_ALTPATH 0x08 /* using alternate path */
7524#define DO_ALTBLTIN 0x20 /* %builtin in alt. path */
7525
7526static void find_command(char *, struct cmdentry *, int, const char *);
7527
7528
7529/* ============ Hashing commands */
7530
7531/*
7532 * When commands are first encountered, they are entered in a hash table.
7533 * This ensures that a full path search will not have to be done for them
7534 * on each invocation.
7535 *
7536 * We should investigate converting to a linear search, even though that
7537 * would make the command name "hash" a misnomer.
7538 */
7539
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007540struct tblentry {
7541 struct tblentry *next; /* next entry in hash chain */
7542 union param param; /* definition of builtin function */
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00007543 smallint cmdtype; /* CMDxxx */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007544 char rehash; /* if set, cd done since entry created */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00007545 char cmdname[1]; /* name of command */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007546};
7547
Denis Vlasenko01631112007-12-16 17:20:38 +00007548static struct tblentry **cmdtable;
7549#define INIT_G_cmdtable() do { \
7550 cmdtable = xzalloc(CMDTABLESIZE * sizeof(cmdtable[0])); \
7551} while (0)
7552
7553static int builtinloc = -1; /* index in path of %builtin, or -1 */
7554
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007555
7556static void
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00007557tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) char *cmd, char **argv, char **envp)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007558{
Denis Vlasenko80d14be2007-04-10 23:03:30 +00007559#if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007560 if (applet_no >= 0) {
Denis Vlasenkob7304742008-10-20 08:15:51 +00007561 if (APPLET_IS_NOEXEC(applet_no)) {
Denys Vlasenko7df28bb2010-06-18 14:23:47 +02007562 clearenv();
Denis Vlasenkob7304742008-10-20 08:15:51 +00007563 while (*envp)
7564 putenv(*envp++);
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007565 run_applet_no_and_exit(applet_no, argv);
Denis Vlasenkob7304742008-10-20 08:15:51 +00007566 }
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007567 /* re-exec ourselves with the new arguments */
7568 execve(bb_busybox_exec_path, argv, envp);
7569 /* If they called chroot or otherwise made the binary no longer
7570 * executable, fall through */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007571 }
7572#endif
7573
7574 repeat:
7575#ifdef SYSV
7576 do {
7577 execve(cmd, argv, envp);
7578 } while (errno == EINTR);
7579#else
7580 execve(cmd, argv, envp);
7581#endif
Denys Vlasenko65a8b852016-10-26 22:29:11 +02007582 if (cmd != (char*) bb_busybox_exec_path && errno == ENOEXEC) {
Denys Vlasenkoaefe1c22011-03-07 12:02:40 +01007583 /* Run "cmd" as a shell script:
7584 * http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html
7585 * "If the execve() function fails with ENOEXEC, the shell
7586 * shall execute a command equivalent to having a shell invoked
7587 * with the command name as its first operand,
7588 * with any remaining arguments passed to the new shell"
7589 *
7590 * That is, do not use $SHELL, user's shell, or /bin/sh;
7591 * just call ourselves.
Denys Vlasenko2bef5262011-12-16 00:25:17 +01007592 *
7593 * Note that bash reads ~80 chars of the file, and if it sees
7594 * a zero byte before it sees newline, it doesn't try to
7595 * interpret it, but fails with "cannot execute binary file"
Denys Vlasenkocda6ea92011-12-16 00:44:36 +01007596 * message and exit code 126. For one, this prevents attempts
7597 * to interpret foreign ELF binaries as shell scripts.
Denys Vlasenkoaefe1c22011-03-07 12:02:40 +01007598 */
Denys Vlasenko65a8b852016-10-26 22:29:11 +02007599 argv[0] = cmd;
Denys Vlasenkoaefe1c22011-03-07 12:02:40 +01007600 cmd = (char*) bb_busybox_exec_path;
Denys Vlasenko65a8b852016-10-26 22:29:11 +02007601 /* NB: this is only possible because all callers of shellexec()
7602 * ensure that the argv[-1] slot exists!
7603 */
7604 argv--;
7605 argv[0] = (char*) "ash";
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007606 goto repeat;
7607 }
7608}
7609
7610/*
7611 * Exec a program. Never returns. If you change this routine, you may
7612 * have to change the find_command routine as well.
Denys Vlasenko65a8b852016-10-26 22:29:11 +02007613 * argv[-1] must exist and be writable! See tryexec() for why.
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007614 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00007615static void shellexec(char **, const char *, int) NORETURN;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007616static void
7617shellexec(char **argv, const char *path, int idx)
7618{
7619 char *cmdname;
7620 int e;
7621 char **envp;
7622 int exerrno;
Denys Vlasenko83f103b2011-12-20 06:10:35 +01007623 int applet_no = -1; /* used only by FEATURE_SH_STANDALONE */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007624
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +02007625 envp = listvars(VEXPORT, VUNSET, /*end:*/ NULL);
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007626 if (strchr(argv[0], '/') != NULL
Denis Vlasenko80d14be2007-04-10 23:03:30 +00007627#if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007628 || (applet_no = find_applet_by_name(argv[0])) >= 0
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007629#endif
7630 ) {
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00007631 tryexec(IF_FEATURE_SH_STANDALONE(applet_no,) argv[0], argv, envp);
Denys Vlasenko83f103b2011-12-20 06:10:35 +01007632 if (applet_no >= 0) {
7633 /* We tried execing ourself, but it didn't work.
7634 * Maybe /proc/self/exe doesn't exist?
7635 * Try $PATH search.
7636 */
7637 goto try_PATH;
7638 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007639 e = errno;
7640 } else {
Denys Vlasenko83f103b2011-12-20 06:10:35 +01007641 try_PATH:
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007642 e = ENOENT;
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02007643 while ((cmdname = path_advance(&path, argv[0])) != NULL) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007644 if (--idx < 0 && pathopt == NULL) {
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00007645 tryexec(IF_FEATURE_SH_STANDALONE(-1,) cmdname, argv, envp);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007646 if (errno != ENOENT && errno != ENOTDIR)
7647 e = errno;
7648 }
7649 stunalloc(cmdname);
7650 }
7651 }
7652
7653 /* Map to POSIX errors */
7654 switch (e) {
7655 case EACCES:
7656 exerrno = 126;
7657 break;
7658 case ENOENT:
7659 exerrno = 127;
7660 break;
7661 default:
7662 exerrno = 2;
7663 break;
7664 }
7665 exitstatus = exerrno;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02007666 TRACE(("shellexec failed for %s, errno %d, suppress_int %d\n",
7667 argv[0], e, suppress_int));
Denys Vlasenko061a0902016-10-25 17:24:25 +02007668 ash_msg_and_raise(EXEXIT, "%s: %s", argv[0], errmsg(e, "not found"));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007669 /* NOTREACHED */
7670}
7671
7672static void
7673printentry(struct tblentry *cmdp)
7674{
7675 int idx;
7676 const char *path;
7677 char *name;
7678
7679 idx = cmdp->param.index;
7680 path = pathval();
7681 do {
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02007682 name = path_advance(&path, cmdp->cmdname);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007683 stunalloc(name);
7684 } while (--idx >= 0);
7685 out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr));
7686}
7687
7688/*
7689 * Clear out command entries. The argument specifies the first entry in
7690 * PATH which has changed.
7691 */
7692static void
7693clearcmdentry(int firstchange)
7694{
7695 struct tblentry **tblp;
7696 struct tblentry **pp;
7697 struct tblentry *cmdp;
7698
7699 INT_OFF;
7700 for (tblp = cmdtable; tblp < &cmdtable[CMDTABLESIZE]; tblp++) {
7701 pp = tblp;
7702 while ((cmdp = *pp) != NULL) {
7703 if ((cmdp->cmdtype == CMDNORMAL &&
7704 cmdp->param.index >= firstchange)
7705 || (cmdp->cmdtype == CMDBUILTIN &&
7706 builtinloc >= firstchange)
7707 ) {
7708 *pp = cmdp->next;
7709 free(cmdp);
7710 } else {
7711 pp = &cmdp->next;
7712 }
7713 }
7714 }
7715 INT_ON;
7716}
7717
7718/*
7719 * Locate a command in the command hash table. If "add" is nonzero,
7720 * add the command to the table if it is not already present. The
7721 * variable "lastcmdentry" is set to point to the address of the link
7722 * pointing to the entry, so that delete_cmd_entry can delete the
7723 * entry.
7724 *
7725 * Interrupts must be off if called with add != 0.
7726 */
7727static struct tblentry **lastcmdentry;
7728
7729static struct tblentry *
7730cmdlookup(const char *name, int add)
7731{
7732 unsigned int hashval;
7733 const char *p;
7734 struct tblentry *cmdp;
7735 struct tblentry **pp;
7736
7737 p = name;
7738 hashval = (unsigned char)*p << 4;
7739 while (*p)
7740 hashval += (unsigned char)*p++;
7741 hashval &= 0x7FFF;
7742 pp = &cmdtable[hashval % CMDTABLESIZE];
7743 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
7744 if (strcmp(cmdp->cmdname, name) == 0)
7745 break;
7746 pp = &cmdp->next;
7747 }
7748 if (add && cmdp == NULL) {
Denis Vlasenkob07a4962008-06-22 13:16:23 +00007749 cmdp = *pp = ckzalloc(sizeof(struct tblentry)
7750 + strlen(name)
7751 /* + 1 - already done because
7752 * tblentry::cmdname is char[1] */);
Denis Vlasenko597906c2008-02-20 16:38:54 +00007753 /*cmdp->next = NULL; - ckzalloc did it */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007754 cmdp->cmdtype = CMDUNKNOWN;
7755 strcpy(cmdp->cmdname, name);
7756 }
7757 lastcmdentry = pp;
7758 return cmdp;
7759}
7760
7761/*
7762 * Delete the command entry returned on the last lookup.
7763 */
7764static void
7765delete_cmd_entry(void)
7766{
7767 struct tblentry *cmdp;
7768
7769 INT_OFF;
7770 cmdp = *lastcmdentry;
7771 *lastcmdentry = cmdp->next;
7772 if (cmdp->cmdtype == CMDFUNCTION)
7773 freefunc(cmdp->param.func);
7774 free(cmdp);
7775 INT_ON;
7776}
7777
7778/*
7779 * Add a new command entry, replacing any existing command entry for
7780 * the same name - except special builtins.
7781 */
7782static void
7783addcmdentry(char *name, struct cmdentry *entry)
7784{
7785 struct tblentry *cmdp;
7786
7787 cmdp = cmdlookup(name, 1);
7788 if (cmdp->cmdtype == CMDFUNCTION) {
7789 freefunc(cmdp->param.func);
7790 }
7791 cmdp->cmdtype = entry->cmdtype;
7792 cmdp->param = entry->u;
7793 cmdp->rehash = 0;
7794}
7795
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02007796static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00007797hashcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007798{
7799 struct tblentry **pp;
7800 struct tblentry *cmdp;
7801 int c;
7802 struct cmdentry entry;
7803 char *name;
7804
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007805 if (nextopt("r") != '\0') {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007806 clearcmdentry(0);
7807 return 0;
7808 }
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007809
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007810 if (*argptr == NULL) {
7811 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
7812 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
7813 if (cmdp->cmdtype == CMDNORMAL)
7814 printentry(cmdp);
7815 }
7816 }
7817 return 0;
7818 }
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007819
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007820 c = 0;
7821 while ((name = *argptr) != NULL) {
7822 cmdp = cmdlookup(name, 0);
7823 if (cmdp != NULL
7824 && (cmdp->cmdtype == CMDNORMAL
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007825 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))
7826 ) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007827 delete_cmd_entry();
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007828 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007829 find_command(name, &entry, DO_ERR, pathval());
7830 if (entry.cmdtype == CMDUNKNOWN)
7831 c = 1;
7832 argptr++;
7833 }
7834 return c;
7835}
7836
7837/*
7838 * Called when a cd is done. Marks all commands so the next time they
7839 * are executed they will be rehashed.
7840 */
7841static void
7842hashcd(void)
7843{
7844 struct tblentry **pp;
7845 struct tblentry *cmdp;
7846
7847 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
7848 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007849 if (cmdp->cmdtype == CMDNORMAL
7850 || (cmdp->cmdtype == CMDBUILTIN
Denys Vlasenkoe4dcba12010-10-28 18:57:19 +02007851 && !IS_BUILTIN_REGULAR(cmdp->param.cmd)
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007852 && builtinloc > 0)
7853 ) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007854 cmdp->rehash = 1;
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007855 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007856 }
7857 }
7858}
7859
7860/*
7861 * Fix command hash table when PATH changed.
7862 * Called before PATH is changed. The argument is the new value of PATH;
7863 * pathval() still returns the old value at this point.
7864 * Called with interrupts off.
7865 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02007866static void FAST_FUNC
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007867changepath(const char *new)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007868{
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007869 const char *old;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007870 int firstchange;
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007871 int idx;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007872 int idx_bltin;
7873
7874 old = pathval();
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007875 firstchange = 9999; /* assume no change */
7876 idx = 0;
7877 idx_bltin = -1;
7878 for (;;) {
7879 if (*old != *new) {
7880 firstchange = idx;
7881 if ((*old == '\0' && *new == ':')
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +02007882 || (*old == ':' && *new == '\0')
7883 ) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007884 firstchange++;
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +02007885 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007886 old = new; /* ignore subsequent differences */
7887 }
7888 if (*new == '\0')
7889 break;
7890 if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin"))
7891 idx_bltin = idx;
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007892 if (*new == ':')
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007893 idx++;
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +02007894 new++;
7895 old++;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007896 }
7897 if (builtinloc < 0 && idx_bltin >= 0)
7898 builtinloc = idx_bltin; /* zap builtins */
7899 if (builtinloc >= 0 && idx_bltin < 0)
7900 firstchange = 0;
7901 clearcmdentry(firstchange);
7902 builtinloc = idx_bltin;
7903}
Ron Yorston95ebcf72015-11-03 09:42:23 +00007904enum {
7905 TEOF,
7906 TNL,
7907 TREDIR,
7908 TWORD,
7909 TSEMI,
7910 TBACKGND,
7911 TAND,
7912 TOR,
7913 TPIPE,
7914 TLP,
7915 TRP,
7916 TENDCASE,
7917 TENDBQUOTE,
7918 TNOT,
7919 TCASE,
7920 TDO,
7921 TDONE,
7922 TELIF,
7923 TELSE,
7924 TESAC,
7925 TFI,
7926 TFOR,
7927#if ENABLE_ASH_BASH_COMPAT
7928 TFUNCTION,
7929#endif
7930 TIF,
7931 TIN,
7932 TTHEN,
7933 TUNTIL,
7934 TWHILE,
7935 TBEGIN,
7936 TEND
7937};
Denis Vlasenkob07a4962008-06-22 13:16:23 +00007938typedef smallint token_id_t;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007939
Denys Vlasenko888527c2016-10-02 16:54:17 +02007940/* Nth bit indicates if token marks the end of a list */
7941enum {
7942 tokendlist = 0
7943 /* 0 */ | (1u << TEOF)
7944 /* 1 */ | (0u << TNL)
7945 /* 2 */ | (0u << TREDIR)
7946 /* 3 */ | (0u << TWORD)
7947 /* 4 */ | (0u << TSEMI)
7948 /* 5 */ | (0u << TBACKGND)
7949 /* 6 */ | (0u << TAND)
7950 /* 7 */ | (0u << TOR)
7951 /* 8 */ | (0u << TPIPE)
7952 /* 9 */ | (0u << TLP)
7953 /* 10 */ | (1u << TRP)
7954 /* 11 */ | (1u << TENDCASE)
7955 /* 12 */ | (1u << TENDBQUOTE)
7956 /* 13 */ | (0u << TNOT)
7957 /* 14 */ | (0u << TCASE)
7958 /* 15 */ | (1u << TDO)
7959 /* 16 */ | (1u << TDONE)
7960 /* 17 */ | (1u << TELIF)
7961 /* 18 */ | (1u << TELSE)
7962 /* 19 */ | (1u << TESAC)
7963 /* 20 */ | (1u << TFI)
7964 /* 21 */ | (0u << TFOR)
7965#if ENABLE_ASH_BASH_COMPAT
7966 /* 22 */ | (0u << TFUNCTION)
Denys Vlasenko80729a42016-10-02 22:33:15 +02007967#endif
Denys Vlasenko888527c2016-10-02 16:54:17 +02007968 /* 23 */ | (0u << TIF)
7969 /* 24 */ | (0u << TIN)
7970 /* 25 */ | (1u << TTHEN)
7971 /* 26 */ | (0u << TUNTIL)
7972 /* 27 */ | (0u << TWHILE)
7973 /* 28 */ | (0u << TBEGIN)
7974 /* 29 */ | (1u << TEND)
7975 , /* thus far 29 bits used */
7976};
7977
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007978static const char *const tokname_array[] = {
Denys Vlasenko888527c2016-10-02 16:54:17 +02007979 "end of file",
7980 "newline",
7981 "redirection",
7982 "word",
7983 ";",
7984 "&",
7985 "&&",
7986 "||",
7987 "|",
7988 "(",
7989 ")",
7990 ";;",
7991 "`",
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007992#define KWDOFFSET 13
7993 /* the following are keywords */
Denys Vlasenko888527c2016-10-02 16:54:17 +02007994 "!",
7995 "case",
7996 "do",
7997 "done",
7998 "elif",
7999 "else",
8000 "esac",
8001 "fi",
8002 "for",
Ron Yorston95ebcf72015-11-03 09:42:23 +00008003#if ENABLE_ASH_BASH_COMPAT
Denys Vlasenko888527c2016-10-02 16:54:17 +02008004 "function",
Ron Yorston95ebcf72015-11-03 09:42:23 +00008005#endif
Denys Vlasenko888527c2016-10-02 16:54:17 +02008006 "if",
8007 "in",
8008 "then",
8009 "until",
8010 "while",
8011 "{",
8012 "}",
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008013};
8014
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008015/* Wrapper around strcmp for qsort/bsearch/... */
8016static int
8017pstrcmp(const void *a, const void *b)
8018{
Denys Vlasenko888527c2016-10-02 16:54:17 +02008019 return strcmp((char*)a, *(char**)b);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008020}
8021
8022static const char *const *
8023findkwd(const char *s)
8024{
8025 return bsearch(s, tokname_array + KWDOFFSET,
Denis Vlasenko80b8b392007-06-25 10:55:35 +00008026 ARRAY_SIZE(tokname_array) - KWDOFFSET,
8027 sizeof(tokname_array[0]), pstrcmp);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008028}
8029
8030/*
8031 * Locate and print what a word is...
8032 */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008033static int
Ron Yorston3f221112015-08-03 13:47:33 +01008034describe_command(char *command, const char *path, int describe_command_verbose)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008035{
8036 struct cmdentry entry;
8037 struct tblentry *cmdp;
8038#if ENABLE_ASH_ALIAS
8039 const struct alias *ap;
8040#endif
Ron Yorston3f221112015-08-03 13:47:33 +01008041
8042 path = path ? path : pathval();
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008043
8044 if (describe_command_verbose) {
8045 out1str(command);
8046 }
8047
8048 /* First look at the keywords */
8049 if (findkwd(command)) {
8050 out1str(describe_command_verbose ? " is a shell keyword" : command);
8051 goto out;
8052 }
8053
8054#if ENABLE_ASH_ALIAS
8055 /* Then look at the aliases */
8056 ap = lookupalias(command, 0);
8057 if (ap != NULL) {
Denis Vlasenko46846e22007-05-20 13:08:31 +00008058 if (!describe_command_verbose) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008059 out1str("alias ");
8060 printalias(ap);
8061 return 0;
8062 }
Denis Vlasenko46846e22007-05-20 13:08:31 +00008063 out1fmt(" is an alias for %s", ap->val);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008064 goto out;
8065 }
8066#endif
8067 /* Then check if it is a tracked alias */
8068 cmdp = cmdlookup(command, 0);
8069 if (cmdp != NULL) {
8070 entry.cmdtype = cmdp->cmdtype;
8071 entry.u = cmdp->param;
8072 } else {
8073 /* Finally use brute force */
8074 find_command(command, &entry, DO_ABS, path);
8075 }
8076
8077 switch (entry.cmdtype) {
8078 case CMDNORMAL: {
8079 int j = entry.u.index;
8080 char *p;
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00008081 if (j < 0) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008082 p = command;
8083 } else {
8084 do {
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02008085 p = path_advance(&path, command);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008086 stunalloc(p);
8087 } while (--j >= 0);
8088 }
8089 if (describe_command_verbose) {
8090 out1fmt(" is%s %s",
8091 (cmdp ? " a tracked alias for" : nullstr), p
8092 );
8093 } else {
8094 out1str(p);
8095 }
8096 break;
8097 }
8098
8099 case CMDFUNCTION:
8100 if (describe_command_verbose) {
8101 out1str(" is a shell function");
8102 } else {
8103 out1str(command);
8104 }
8105 break;
8106
8107 case CMDBUILTIN:
8108 if (describe_command_verbose) {
8109 out1fmt(" is a %sshell builtin",
8110 IS_BUILTIN_SPECIAL(entry.u.cmd) ?
8111 "special " : nullstr
8112 );
8113 } else {
8114 out1str(command);
8115 }
8116 break;
8117
8118 default:
8119 if (describe_command_verbose) {
8120 out1str(": not found\n");
8121 }
8122 return 127;
8123 }
8124 out:
Denys Vlasenko285ad152009-12-04 23:02:27 +01008125 out1str("\n");
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008126 return 0;
8127}
8128
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02008129static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00008130typecmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008131{
Denis Vlasenko46846e22007-05-20 13:08:31 +00008132 int i = 1;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008133 int err = 0;
Denis Vlasenko46846e22007-05-20 13:08:31 +00008134 int verbose = 1;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008135
Denis Vlasenko46846e22007-05-20 13:08:31 +00008136 /* type -p ... ? (we don't bother checking for 'p') */
Denis Vlasenko1fc62382007-06-25 22:55:34 +00008137 if (argv[1] && argv[1][0] == '-') {
Denis Vlasenko46846e22007-05-20 13:08:31 +00008138 i++;
8139 verbose = 0;
8140 }
Denis Vlasenko68404f12008-03-17 09:00:54 +00008141 while (argv[i]) {
Ron Yorston3f221112015-08-03 13:47:33 +01008142 err |= describe_command(argv[i++], NULL, verbose);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008143 }
8144 return err;
8145}
8146
8147#if ENABLE_ASH_CMDCMD
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008148/* Is it "command [-p] PROG ARGS" bltin, no other opts? Return ptr to "PROG" if yes */
8149static char **
8150parse_command_args(char **argv, const char **path)
8151{
8152 char *cp, c;
8153
8154 for (;;) {
8155 cp = *++argv;
8156 if (!cp)
8157 return NULL;
8158 if (*cp++ != '-')
8159 break;
8160 c = *cp++;
8161 if (!c)
8162 break;
8163 if (c == '-' && !*cp) {
8164 if (!*++argv)
8165 return NULL;
8166 break;
8167 }
8168 do {
8169 switch (c) {
8170 case 'p':
8171 *path = bb_default_path;
8172 break;
8173 default:
8174 /* run 'typecmd' for other options */
8175 return NULL;
8176 }
8177 c = *cp++;
8178 } while (c);
8179 }
8180 return argv;
8181}
8182
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02008183static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00008184commandcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008185{
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008186 char *cmd;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008187 int c;
8188 enum {
8189 VERIFY_BRIEF = 1,
8190 VERIFY_VERBOSE = 2,
8191 } verify = 0;
Ron Yorston3f221112015-08-03 13:47:33 +01008192 const char *path = NULL;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008193
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008194 /* "command [-p] PROG ARGS" (that is, without -V or -v)
8195 * never reaches this function.
8196 */
8197
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008198 while ((c = nextopt("pvV")) != '\0')
8199 if (c == 'V')
8200 verify |= VERIFY_VERBOSE;
8201 else if (c == 'v')
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008202 /*verify |= VERIFY_BRIEF*/;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008203#if DEBUG
8204 else if (c != 'p')
8205 abort();
8206#endif
Ron Yorston3f221112015-08-03 13:47:33 +01008207 else
8208 path = bb_default_path;
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008209
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00008210 /* Mimic bash: just "command -v" doesn't complain, it's a nop */
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008211 cmd = *argptr;
8212 if (/*verify && */ cmd)
8213 return describe_command(cmd, path, verify /* - VERIFY_BRIEF*/);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008214
8215 return 0;
8216}
8217#endif
8218
8219
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008220/*static int funcblocksize; // size of structures in function */
8221/*static int funcstringsize; // size of strings in node */
Denis Vlasenko340299a2008-11-21 10:36:36 +00008222static void *funcblock; /* block to allocate function from */
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008223static char *funcstring_end; /* end of block to allocate strings from */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008224
Eric Andersencb57d552001-06-28 07:25:16 +00008225/* flags in argument to evaltree */
Denis Vlasenko340299a2008-11-21 10:36:36 +00008226#define EV_EXIT 01 /* exit after evaluating tree */
8227#define EV_TESTED 02 /* exit status is checked; ignore -e flag */
Eric Andersencb57d552001-06-28 07:25:16 +00008228
Denys Vlasenko3e134eb2016-04-22 18:09:21 +02008229static const uint8_t nodesize[N_NUMBER] ALIGN1 = {
Denis Vlasenko340299a2008-11-21 10:36:36 +00008230 [NCMD ] = SHELL_ALIGN(sizeof(struct ncmd)),
8231 [NPIPE ] = SHELL_ALIGN(sizeof(struct npipe)),
8232 [NREDIR ] = SHELL_ALIGN(sizeof(struct nredir)),
8233 [NBACKGND ] = SHELL_ALIGN(sizeof(struct nredir)),
8234 [NSUBSHELL] = SHELL_ALIGN(sizeof(struct nredir)),
8235 [NAND ] = SHELL_ALIGN(sizeof(struct nbinary)),
8236 [NOR ] = SHELL_ALIGN(sizeof(struct nbinary)),
8237 [NSEMI ] = SHELL_ALIGN(sizeof(struct nbinary)),
8238 [NIF ] = SHELL_ALIGN(sizeof(struct nif)),
8239 [NWHILE ] = SHELL_ALIGN(sizeof(struct nbinary)),
8240 [NUNTIL ] = SHELL_ALIGN(sizeof(struct nbinary)),
8241 [NFOR ] = SHELL_ALIGN(sizeof(struct nfor)),
8242 [NCASE ] = SHELL_ALIGN(sizeof(struct ncase)),
8243 [NCLIST ] = SHELL_ALIGN(sizeof(struct nclist)),
8244 [NDEFUN ] = SHELL_ALIGN(sizeof(struct narg)),
8245 [NARG ] = SHELL_ALIGN(sizeof(struct narg)),
8246 [NTO ] = SHELL_ALIGN(sizeof(struct nfile)),
Denis Vlasenkocc5feab2008-11-22 01:32:40 +00008247#if ENABLE_ASH_BASH_COMPAT
Denis Vlasenko340299a2008-11-21 10:36:36 +00008248 [NTO2 ] = SHELL_ALIGN(sizeof(struct nfile)),
Denis Vlasenkocc5feab2008-11-22 01:32:40 +00008249#endif
Denis Vlasenko340299a2008-11-21 10:36:36 +00008250 [NCLOBBER ] = SHELL_ALIGN(sizeof(struct nfile)),
8251 [NFROM ] = SHELL_ALIGN(sizeof(struct nfile)),
8252 [NFROMTO ] = SHELL_ALIGN(sizeof(struct nfile)),
8253 [NAPPEND ] = SHELL_ALIGN(sizeof(struct nfile)),
8254 [NTOFD ] = SHELL_ALIGN(sizeof(struct ndup)),
8255 [NFROMFD ] = SHELL_ALIGN(sizeof(struct ndup)),
8256 [NHERE ] = SHELL_ALIGN(sizeof(struct nhere)),
8257 [NXHERE ] = SHELL_ALIGN(sizeof(struct nhere)),
8258 [NNOT ] = SHELL_ALIGN(sizeof(struct nnot)),
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008259};
8260
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008261static int calcsize(int funcblocksize, union node *n);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008262
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008263static int
8264sizenodelist(int funcblocksize, struct nodelist *lp)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008265{
8266 while (lp) {
8267 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008268 funcblocksize = calcsize(funcblocksize, lp->n);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008269 lp = lp->next;
8270 }
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008271 return funcblocksize;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008272}
8273
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008274static int
8275calcsize(int funcblocksize, union node *n)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008276{
8277 if (n == NULL)
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008278 return funcblocksize;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008279 funcblocksize += nodesize[n->type];
8280 switch (n->type) {
8281 case NCMD:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008282 funcblocksize = calcsize(funcblocksize, n->ncmd.redirect);
8283 funcblocksize = calcsize(funcblocksize, n->ncmd.args);
8284 funcblocksize = calcsize(funcblocksize, n->ncmd.assign);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008285 break;
8286 case NPIPE:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008287 funcblocksize = sizenodelist(funcblocksize, n->npipe.cmdlist);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008288 break;
8289 case NREDIR:
8290 case NBACKGND:
8291 case NSUBSHELL:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008292 funcblocksize = calcsize(funcblocksize, n->nredir.redirect);
8293 funcblocksize = calcsize(funcblocksize, n->nredir.n);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008294 break;
8295 case NAND:
8296 case NOR:
8297 case NSEMI:
8298 case NWHILE:
8299 case NUNTIL:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008300 funcblocksize = calcsize(funcblocksize, n->nbinary.ch2);
8301 funcblocksize = calcsize(funcblocksize, n->nbinary.ch1);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008302 break;
8303 case NIF:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008304 funcblocksize = calcsize(funcblocksize, n->nif.elsepart);
8305 funcblocksize = calcsize(funcblocksize, n->nif.ifpart);
8306 funcblocksize = calcsize(funcblocksize, n->nif.test);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008307 break;
8308 case NFOR:
Denys Vlasenko561639a2016-10-07 04:28:33 +02008309 funcblocksize += SHELL_ALIGN(strlen(n->nfor.var) + 1); /* was funcstringsize += ... */
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008310 funcblocksize = calcsize(funcblocksize, n->nfor.body);
8311 funcblocksize = calcsize(funcblocksize, n->nfor.args);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008312 break;
8313 case NCASE:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008314 funcblocksize = calcsize(funcblocksize, n->ncase.cases);
8315 funcblocksize = calcsize(funcblocksize, n->ncase.expr);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008316 break;
8317 case NCLIST:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008318 funcblocksize = calcsize(funcblocksize, n->nclist.body);
8319 funcblocksize = calcsize(funcblocksize, n->nclist.pattern);
8320 funcblocksize = calcsize(funcblocksize, n->nclist.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008321 break;
8322 case NDEFUN:
8323 case NARG:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008324 funcblocksize = sizenodelist(funcblocksize, n->narg.backquote);
Denys Vlasenko561639a2016-10-07 04:28:33 +02008325 funcblocksize += SHELL_ALIGN(strlen(n->narg.text) + 1); /* was funcstringsize += ... */
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008326 funcblocksize = calcsize(funcblocksize, n->narg.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008327 break;
8328 case NTO:
Denis Vlasenko559691a2008-10-05 18:39:31 +00008329#if ENABLE_ASH_BASH_COMPAT
8330 case NTO2:
8331#endif
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008332 case NCLOBBER:
8333 case NFROM:
8334 case NFROMTO:
8335 case NAPPEND:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008336 funcblocksize = calcsize(funcblocksize, n->nfile.fname);
8337 funcblocksize = calcsize(funcblocksize, n->nfile.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008338 break;
8339 case NTOFD:
8340 case NFROMFD:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008341 funcblocksize = calcsize(funcblocksize, n->ndup.vname);
8342 funcblocksize = calcsize(funcblocksize, n->ndup.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008343 break;
8344 case NHERE:
8345 case NXHERE:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008346 funcblocksize = calcsize(funcblocksize, n->nhere.doc);
8347 funcblocksize = calcsize(funcblocksize, n->nhere.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008348 break;
8349 case NNOT:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008350 funcblocksize = calcsize(funcblocksize, n->nnot.com);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008351 break;
8352 };
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008353 return funcblocksize;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008354}
8355
8356static char *
8357nodeckstrdup(char *s)
8358{
Denys Vlasenko561639a2016-10-07 04:28:33 +02008359 funcstring_end -= SHELL_ALIGN(strlen(s) + 1);
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008360 return strcpy(funcstring_end, s);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008361}
8362
8363static union node *copynode(union node *);
8364
8365static struct nodelist *
8366copynodelist(struct nodelist *lp)
8367{
8368 struct nodelist *start;
8369 struct nodelist **lpp;
8370
8371 lpp = &start;
8372 while (lp) {
8373 *lpp = funcblock;
8374 funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist));
8375 (*lpp)->n = copynode(lp->n);
8376 lp = lp->next;
8377 lpp = &(*lpp)->next;
8378 }
8379 *lpp = NULL;
8380 return start;
8381}
8382
8383static union node *
8384copynode(union node *n)
8385{
8386 union node *new;
8387
8388 if (n == NULL)
8389 return NULL;
8390 new = funcblock;
8391 funcblock = (char *) funcblock + nodesize[n->type];
8392
8393 switch (n->type) {
8394 case NCMD:
8395 new->ncmd.redirect = copynode(n->ncmd.redirect);
8396 new->ncmd.args = copynode(n->ncmd.args);
8397 new->ncmd.assign = copynode(n->ncmd.assign);
8398 break;
8399 case NPIPE:
8400 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00008401 new->npipe.pipe_backgnd = n->npipe.pipe_backgnd;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008402 break;
8403 case NREDIR:
8404 case NBACKGND:
8405 case NSUBSHELL:
8406 new->nredir.redirect = copynode(n->nredir.redirect);
8407 new->nredir.n = copynode(n->nredir.n);
8408 break;
8409 case NAND:
8410 case NOR:
8411 case NSEMI:
8412 case NWHILE:
8413 case NUNTIL:
8414 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8415 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8416 break;
8417 case NIF:
8418 new->nif.elsepart = copynode(n->nif.elsepart);
8419 new->nif.ifpart = copynode(n->nif.ifpart);
8420 new->nif.test = copynode(n->nif.test);
8421 break;
8422 case NFOR:
8423 new->nfor.var = nodeckstrdup(n->nfor.var);
8424 new->nfor.body = copynode(n->nfor.body);
8425 new->nfor.args = copynode(n->nfor.args);
8426 break;
8427 case NCASE:
8428 new->ncase.cases = copynode(n->ncase.cases);
8429 new->ncase.expr = copynode(n->ncase.expr);
8430 break;
8431 case NCLIST:
8432 new->nclist.body = copynode(n->nclist.body);
8433 new->nclist.pattern = copynode(n->nclist.pattern);
8434 new->nclist.next = copynode(n->nclist.next);
8435 break;
8436 case NDEFUN:
8437 case NARG:
8438 new->narg.backquote = copynodelist(n->narg.backquote);
8439 new->narg.text = nodeckstrdup(n->narg.text);
8440 new->narg.next = copynode(n->narg.next);
8441 break;
8442 case NTO:
Denis Vlasenko559691a2008-10-05 18:39:31 +00008443#if ENABLE_ASH_BASH_COMPAT
8444 case NTO2:
8445#endif
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008446 case NCLOBBER:
8447 case NFROM:
8448 case NFROMTO:
8449 case NAPPEND:
8450 new->nfile.fname = copynode(n->nfile.fname);
8451 new->nfile.fd = n->nfile.fd;
8452 new->nfile.next = copynode(n->nfile.next);
8453 break;
8454 case NTOFD:
8455 case NFROMFD:
8456 new->ndup.vname = copynode(n->ndup.vname);
8457 new->ndup.dupfd = n->ndup.dupfd;
8458 new->ndup.fd = n->ndup.fd;
8459 new->ndup.next = copynode(n->ndup.next);
8460 break;
8461 case NHERE:
8462 case NXHERE:
8463 new->nhere.doc = copynode(n->nhere.doc);
8464 new->nhere.fd = n->nhere.fd;
8465 new->nhere.next = copynode(n->nhere.next);
8466 break;
8467 case NNOT:
8468 new->nnot.com = copynode(n->nnot.com);
8469 break;
8470 };
8471 new->type = n->type;
8472 return new;
8473}
8474
8475/*
8476 * Make a copy of a parse tree.
8477 */
8478static struct funcnode *
8479copyfunc(union node *n)
8480{
8481 struct funcnode *f;
8482 size_t blocksize;
8483
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008484 /*funcstringsize = 0;*/
8485 blocksize = offsetof(struct funcnode, n) + calcsize(0, n);
8486 f = ckzalloc(blocksize /* + funcstringsize */);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008487 funcblock = (char *) f + offsetof(struct funcnode, n);
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008488 funcstring_end = (char *) f + blocksize;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008489 copynode(n);
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008490 /* f->count = 0; - ckzalloc did it */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008491 return f;
8492}
8493
8494/*
8495 * Define a shell function.
8496 */
8497static void
Denys Vlasenko7aec8682016-10-25 20:26:02 +02008498defun(union node *func)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008499{
8500 struct cmdentry entry;
8501
8502 INT_OFF;
8503 entry.cmdtype = CMDFUNCTION;
8504 entry.u.func = copyfunc(func);
Denys Vlasenko7aec8682016-10-25 20:26:02 +02008505 addcmdentry(func->narg.text, &entry);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008506 INT_ON;
8507}
8508
Denis Vlasenko4b875702009-03-19 13:30:04 +00008509/* Reasons for skipping commands (see comment on breakcmd routine) */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008510#define SKIPBREAK (1 << 0)
8511#define SKIPCONT (1 << 1)
8512#define SKIPFUNC (1 << 2)
Denis Vlasenko4b875702009-03-19 13:30:04 +00008513static smallint evalskip; /* set to SKIPxxx if we are skipping commands */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008514static int skipcount; /* number of levels to skip */
8515static int funcnest; /* depth of function calls */
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +00008516static int loopnest; /* current loop nesting level */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008517
Denis Vlasenko4b875702009-03-19 13:30:04 +00008518/* Forward decl way out to parsing code - dotrap needs it */
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02008519static int evalstring(char *s, int flags);
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008520
Denis Vlasenko4b875702009-03-19 13:30:04 +00008521/* Called to execute a trap.
8522 * Single callsite - at the end of evaltree().
Denys Vlasenkob563f622010-09-25 17:15:13 +02008523 * If we return non-zero, evaltree raises EXEXIT exception.
Denis Vlasenko4b875702009-03-19 13:30:04 +00008524 *
8525 * Perhaps we should avoid entering new trap handlers
8526 * while we are executing a trap handler. [is it a TODO?]
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008527 */
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008528static void
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008529dotrap(void)
8530{
Denis Vlasenko4b875702009-03-19 13:30:04 +00008531 uint8_t *g;
8532 int sig;
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008533 uint8_t last_status;
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008534
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008535 if (!pending_sig)
8536 return;
8537
8538 last_status = exitstatus;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02008539 pending_sig = 0;
Denys Vlasenkode892052016-10-02 01:49:13 +02008540 barrier();
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008541
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008542 TRACE(("dotrap entered\n"));
Denis Vlasenko4b875702009-03-19 13:30:04 +00008543 for (sig = 1, g = gotsig; sig < NSIG; sig++, g++) {
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008544 char *p;
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008545
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008546 if (!*g)
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008547 continue;
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008548
8549 if (evalskip) {
8550 pending_sig = sig;
8551 break;
8552 }
8553
8554 p = trap[sig];
Denis Vlasenko4b875702009-03-19 13:30:04 +00008555 /* non-trapped SIGINT is handled separately by raise_interrupt,
8556 * don't upset it by resetting gotsig[SIGINT-1] */
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008557 if (sig == SIGINT && !p)
Denis Vlasenko4b875702009-03-19 13:30:04 +00008558 continue;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008559
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008560 TRACE(("sig %d is active, will run handler '%s'\n", sig, p));
Denis Vlasenko4b875702009-03-19 13:30:04 +00008561 *g = 0;
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008562 if (!p)
Denis Vlasenko4b875702009-03-19 13:30:04 +00008563 continue;
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008564 evalstring(p, 0);
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008565 }
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008566 exitstatus = last_status;
8567 TRACE(("dotrap returns\n"));
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008568}
8569
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00008570/* forward declarations - evaluation is fairly recursive business... */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008571static int evalloop(union node *, int);
8572static int evalfor(union node *, int);
8573static int evalcase(union node *, int);
8574static int evalsubshell(union node *, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008575static void expredir(union node *);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008576static int evalpipe(union node *, int);
8577static int evalcommand(union node *, int);
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02008578static int evalbltin(const struct builtincmd *, int, char **, int);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008579static void prehash(union node *);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008580
Eric Andersen62483552001-07-10 06:09:16 +00008581/*
Eric Andersenc470f442003-07-28 09:56:35 +00008582 * Evaluate a parse tree. The value is left in the global variable
8583 * exitstatus.
Eric Andersen62483552001-07-10 06:09:16 +00008584 */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008585static int
Eric Andersenc470f442003-07-28 09:56:35 +00008586evaltree(union node *n, int flags)
Eric Andersen62483552001-07-10 06:09:16 +00008587{
Eric Andersenc470f442003-07-28 09:56:35 +00008588 int checkexit = 0;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008589 int (*evalfn)(union node *, int);
8590 int status = 0;
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008591
Eric Andersenc470f442003-07-28 09:56:35 +00008592 if (n == NULL) {
8593 TRACE(("evaltree(NULL) called\n"));
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02008594 goto out;
Eric Andersen62483552001-07-10 06:09:16 +00008595 }
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008596 TRACE(("evaltree(%p: %d, %d) called\n", n, n->type, flags));
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008597
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008598 dotrap();
8599
Eric Andersenc470f442003-07-28 09:56:35 +00008600 switch (n->type) {
8601 default:
Denis Vlasenkoa7189f02006-11-17 20:29:00 +00008602#if DEBUG
Eric Andersenc470f442003-07-28 09:56:35 +00008603 out1fmt("Node type = %d\n", n->type);
Denys Vlasenko8131eea2009-11-02 14:19:51 +01008604 fflush_all();
Eric Andersenc470f442003-07-28 09:56:35 +00008605 break;
8606#endif
8607 case NNOT:
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008608 status = !evaltree(n->nnot.com, EV_TESTED);
Eric Andersenc470f442003-07-28 09:56:35 +00008609 goto setstatus;
8610 case NREDIR:
8611 expredir(n->nredir.redirect);
8612 status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
8613 if (!status) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008614 status = evaltree(n->nredir.n, flags & EV_TESTED);
Eric Andersenc470f442003-07-28 09:56:35 +00008615 }
Denys Vlasenkoeaf94362016-10-25 21:46:03 +02008616 if (n->nredir.redirect)
8617 popredir(/*drop:*/ 0, /*restore:*/ 0 /* not sure */);
Eric Andersenc470f442003-07-28 09:56:35 +00008618 goto setstatus;
8619 case NCMD:
8620 evalfn = evalcommand;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008621 checkexit:
Eric Andersenc470f442003-07-28 09:56:35 +00008622 if (eflag && !(flags & EV_TESTED))
8623 checkexit = ~0;
8624 goto calleval;
8625 case NFOR:
8626 evalfn = evalfor;
8627 goto calleval;
8628 case NWHILE:
8629 case NUNTIL:
8630 evalfn = evalloop;
8631 goto calleval;
8632 case NSUBSHELL:
8633 case NBACKGND:
8634 evalfn = evalsubshell;
Denys Vlasenkocf98b0c2016-10-25 18:19:39 +02008635 goto checkexit;
Eric Andersenc470f442003-07-28 09:56:35 +00008636 case NPIPE:
8637 evalfn = evalpipe;
8638 goto checkexit;
8639 case NCASE:
8640 evalfn = evalcase;
8641 goto calleval;
8642 case NAND:
8643 case NOR:
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008644 case NSEMI: {
8645
Eric Andersenc470f442003-07-28 09:56:35 +00008646#if NAND + 1 != NOR
8647#error NAND + 1 != NOR
8648#endif
8649#if NOR + 1 != NSEMI
8650#error NOR + 1 != NSEMI
8651#endif
Denis Vlasenko87d5fd92008-07-26 13:48:35 +00008652 unsigned is_or = n->type - NAND;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008653 status = evaltree(
Eric Andersenc470f442003-07-28 09:56:35 +00008654 n->nbinary.ch1,
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008655 (flags | ((is_or >> 1) - 1)) & EV_TESTED
Eric Andersenc470f442003-07-28 09:56:35 +00008656 );
Denys Vlasenkobc1a0082016-10-02 15:31:33 +02008657 if ((!status) == is_or || evalskip)
Eric Andersenc470f442003-07-28 09:56:35 +00008658 break;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008659 n = n->nbinary.ch2;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008660 evaln:
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008661 evalfn = evaltree;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008662 calleval:
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008663 status = evalfn(n, flags);
8664 goto setstatus;
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008665 }
Eric Andersenc470f442003-07-28 09:56:35 +00008666 case NIF:
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008667 status = evaltree(n->nif.test, EV_TESTED);
Eric Andersenc470f442003-07-28 09:56:35 +00008668 if (evalskip)
8669 break;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008670 if (!status) {
Eric Andersenc470f442003-07-28 09:56:35 +00008671 n = n->nif.ifpart;
8672 goto evaln;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008673 }
8674 if (n->nif.elsepart) {
Eric Andersenc470f442003-07-28 09:56:35 +00008675 n = n->nif.elsepart;
8676 goto evaln;
8677 }
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008678 status = 0;
8679 goto setstatus;
Eric Andersenc470f442003-07-28 09:56:35 +00008680 case NDEFUN:
Denys Vlasenko7aec8682016-10-25 20:26:02 +02008681 defun(n);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008682 /* Not necessary. To test it:
8683 * "false; f() { qwerty; }; echo $?" should print 0.
8684 */
8685 /* status = 0; */
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008686 setstatus:
Eric Andersenc470f442003-07-28 09:56:35 +00008687 exitstatus = status;
8688 break;
8689 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008690 out:
Denys Vlasenkob563f622010-09-25 17:15:13 +02008691 /* Order of checks below is important:
8692 * signal handlers trigger before exit caused by "set -e".
8693 */
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008694 dotrap();
8695
8696 if (checkexit & status)
Denis Vlasenkob012b102007-02-19 22:43:01 +00008697 raise_exception(EXEXIT);
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008698 if (flags & EV_EXIT)
8699 raise_exception(EXEXIT);
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008700
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008701 TRACE(("leaving evaltree (no interrupts)\n"));
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008702 return exitstatus;
Eric Andersen62483552001-07-10 06:09:16 +00008703}
8704
Eric Andersenc470f442003-07-28 09:56:35 +00008705#if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3)
8706static
8707#endif
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008708int evaltreenr(union node *, int) __attribute__ ((alias("evaltree"),__noreturn__));
Eric Andersenc470f442003-07-28 09:56:35 +00008709
Denys Vlasenko37dc08b2016-10-02 04:38:07 +02008710static int
8711skiploop(void)
Denys Vlasenko35ec8182016-10-01 19:56:52 +02008712{
8713 int skip = evalskip;
8714
8715 switch (skip) {
8716 case 0:
8717 break;
8718 case SKIPBREAK:
8719 case SKIPCONT:
8720 if (--skipcount <= 0) {
8721 evalskip = 0;
8722 break;
8723 }
8724 skip = SKIPBREAK;
8725 break;
8726 }
8727 return skip;
8728}
8729
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008730static int
Eric Andersenc470f442003-07-28 09:56:35 +00008731evalloop(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00008732{
Denys Vlasenko35ec8182016-10-01 19:56:52 +02008733 int skip;
Eric Andersencb57d552001-06-28 07:25:16 +00008734 int status;
8735
8736 loopnest++;
8737 status = 0;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008738 flags &= EV_TESTED;
Denys Vlasenko35ec8182016-10-01 19:56:52 +02008739 do {
Eric Andersenc470f442003-07-28 09:56:35 +00008740 int i;
8741
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008742 i = evaltree(n->nbinary.ch1, EV_TESTED);
Denys Vlasenko35ec8182016-10-01 19:56:52 +02008743 skip = skiploop();
8744 if (skip == SKIPFUNC)
8745 status = i;
8746 if (skip)
8747 continue;
Eric Andersenc470f442003-07-28 09:56:35 +00008748 if (n->type != NWHILE)
8749 i = !i;
8750 if (i != 0)
8751 break;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008752 status = evaltree(n->nbinary.ch2, flags);
Denys Vlasenko35ec8182016-10-01 19:56:52 +02008753 skip = skiploop();
8754 } while (!(skip & ~SKIPCONT));
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008755 loopnest--;
8756
8757 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00008758}
8759
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008760static int
Eric Andersenc470f442003-07-28 09:56:35 +00008761evalfor(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00008762{
8763 struct arglist arglist;
8764 union node *argp;
8765 struct strlist *sp;
8766 struct stackmark smark;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008767 int status = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00008768
8769 setstackmark(&smark);
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00008770 arglist.list = NULL;
Eric Andersencb57d552001-06-28 07:25:16 +00008771 arglist.lastp = &arglist.list;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008772 for (argp = n->nfor.args; argp; argp = argp->narg.next) {
Ron Yorston549deab2015-05-18 09:57:51 +02008773 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
Eric Andersencb57d552001-06-28 07:25:16 +00008774 }
8775 *arglist.lastp = NULL;
8776
Eric Andersencb57d552001-06-28 07:25:16 +00008777 loopnest++;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008778 flags &= EV_TESTED;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008779 for (sp = arglist.list; sp; sp = sp->next) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02008780 setvar0(n->nfor.var, sp->text);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008781 status = evaltree(n->nfor.body, flags);
Denys Vlasenko35ec8182016-10-01 19:56:52 +02008782 if (skiploop() & ~SKIPCONT)
Eric Andersencb57d552001-06-28 07:25:16 +00008783 break;
Eric Andersencb57d552001-06-28 07:25:16 +00008784 }
8785 loopnest--;
Eric Andersencb57d552001-06-28 07:25:16 +00008786 popstackmark(&smark);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008787
8788 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00008789}
8790
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008791static int
Eric Andersenc470f442003-07-28 09:56:35 +00008792evalcase(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00008793{
8794 union node *cp;
8795 union node *patp;
8796 struct arglist arglist;
8797 struct stackmark smark;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008798 int status = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00008799
8800 setstackmark(&smark);
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00008801 arglist.list = NULL;
Eric Andersencb57d552001-06-28 07:25:16 +00008802 arglist.lastp = &arglist.list;
Eric Andersencb57d552001-06-28 07:25:16 +00008803 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008804 for (cp = n->ncase.cases; cp && evalskip == 0; cp = cp->nclist.next) {
8805 for (patp = cp->nclist.pattern; patp; patp = patp->narg.next) {
Eric Andersencb57d552001-06-28 07:25:16 +00008806 if (casematch(patp, arglist.list->text)) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008807 /* Ensure body is non-empty as otherwise
8808 * EV_EXIT may prevent us from setting the
8809 * exit status.
8810 */
8811 if (evalskip == 0 && cp->nclist.body) {
8812 status = evaltree(cp->nclist.body, flags);
Eric Andersencb57d552001-06-28 07:25:16 +00008813 }
8814 goto out;
8815 }
8816 }
8817 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008818 out:
Eric Andersencb57d552001-06-28 07:25:16 +00008819 popstackmark(&smark);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008820
8821 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00008822}
8823
Eric Andersenc470f442003-07-28 09:56:35 +00008824/*
8825 * Kick off a subshell to evaluate a tree.
8826 */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008827static int
Eric Andersenc470f442003-07-28 09:56:35 +00008828evalsubshell(union node *n, int flags)
8829{
8830 struct job *jp;
8831 int backgnd = (n->type == NBACKGND);
8832 int status;
8833
8834 expredir(n->nredir.redirect);
Denys Vlasenko238bf182010-05-18 15:49:07 +02008835 if (!backgnd && (flags & EV_EXIT) && !may_have_traps)
Eric Andersenc470f442003-07-28 09:56:35 +00008836 goto nofork;
Denis Vlasenkob012b102007-02-19 22:43:01 +00008837 INT_OFF;
Denis Vlasenko68404f12008-03-17 09:00:54 +00008838 jp = makejob(/*n,*/ 1);
Eric Andersenc470f442003-07-28 09:56:35 +00008839 if (forkshell(jp, n, backgnd) == 0) {
Denys Vlasenko238bf182010-05-18 15:49:07 +02008840 /* child */
Denis Vlasenkob012b102007-02-19 22:43:01 +00008841 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +00008842 flags |= EV_EXIT;
8843 if (backgnd)
Denys Vlasenko238bf182010-05-18 15:49:07 +02008844 flags &= ~EV_TESTED;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00008845 nofork:
Eric Andersenc470f442003-07-28 09:56:35 +00008846 redirect(n->nredir.redirect, 0);
8847 evaltreenr(n->nredir.n, flags);
8848 /* never returns */
8849 }
Denys Vlasenko70392332016-10-27 02:31:55 +02008850 /* parent */
Eric Andersenc470f442003-07-28 09:56:35 +00008851 status = 0;
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00008852 if (!backgnd)
Eric Andersenc470f442003-07-28 09:56:35 +00008853 status = waitforjob(jp);
Denis Vlasenkob012b102007-02-19 22:43:01 +00008854 INT_ON;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008855 return status;
Eric Andersenc470f442003-07-28 09:56:35 +00008856}
8857
Eric Andersenc470f442003-07-28 09:56:35 +00008858/*
8859 * Compute the names of the files in a redirection list.
8860 */
Denis Vlasenko99eb8502007-02-23 21:09:49 +00008861static void fixredir(union node *, const char *, int);
Eric Andersenc470f442003-07-28 09:56:35 +00008862static void
8863expredir(union node *n)
8864{
8865 union node *redir;
8866
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008867 for (redir = n; redir; redir = redir->nfile.next) {
Eric Andersenc470f442003-07-28 09:56:35 +00008868 struct arglist fn;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008869
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00008870 fn.list = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00008871 fn.lastp = &fn.list;
8872 switch (redir->type) {
8873 case NFROMTO:
8874 case NFROM:
8875 case NTO:
Denis Vlasenko559691a2008-10-05 18:39:31 +00008876#if ENABLE_ASH_BASH_COMPAT
8877 case NTO2:
8878#endif
Eric Andersenc470f442003-07-28 09:56:35 +00008879 case NCLOBBER:
8880 case NAPPEND:
8881 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02008882 TRACE(("expredir expanded to '%s'\n", fn.list->text));
Denis Vlasenko559691a2008-10-05 18:39:31 +00008883#if ENABLE_ASH_BASH_COMPAT
8884 store_expfname:
8885#endif
Denys Vlasenko7c4b13e2013-01-17 13:02:27 +01008886#if 0
8887// By the design of stack allocator, the loop of this kind:
8888// while true; do while true; do break; done </dev/null; done
8889// will look like a memory leak: ash plans to free expfname's
8890// of "/dev/null" as soon as it finishes running the loop
8891// (in this case, never).
8892// This "fix" is wrong:
Jon Tollefson4ba6c5d2012-11-13 19:26:53 +01008893 if (redir->nfile.expfname)
8894 stunalloc(redir->nfile.expfname);
Denys Vlasenko7c4b13e2013-01-17 13:02:27 +01008895// It results in corrupted state of stacked allocations.
8896#endif
Eric Andersenc470f442003-07-28 09:56:35 +00008897 redir->nfile.expfname = fn.list->text;
8898 break;
8899 case NFROMFD:
Denis Vlasenko559691a2008-10-05 18:39:31 +00008900 case NTOFD: /* >& */
Eric Andersenc470f442003-07-28 09:56:35 +00008901 if (redir->ndup.vname) {
8902 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008903 if (fn.list == NULL)
Denis Vlasenkob012b102007-02-19 22:43:01 +00008904 ash_msg_and_raise_error("redir error");
Denis Vlasenko559691a2008-10-05 18:39:31 +00008905#if ENABLE_ASH_BASH_COMPAT
8906//FIXME: we used expandarg with different args!
8907 if (!isdigit_str9(fn.list->text)) {
8908 /* >&file, not >&fd */
8909 if (redir->nfile.fd != 1) /* 123>&file - BAD */
8910 ash_msg_and_raise_error("redir error");
8911 redir->type = NTO2;
8912 goto store_expfname;
8913 }
8914#endif
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008915 fixredir(redir, fn.list->text, 1);
Eric Andersenc470f442003-07-28 09:56:35 +00008916 }
8917 break;
8918 }
8919 }
8920}
8921
Eric Andersencb57d552001-06-28 07:25:16 +00008922/*
Eric Andersencb57d552001-06-28 07:25:16 +00008923 * Evaluate a pipeline. All the processes in the pipeline are children
8924 * of the process creating the pipeline. (This differs from some versions
8925 * of the shell, which make the last process in a pipeline the parent
8926 * of all the rest.)
8927 */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008928static int
Eric Andersenc470f442003-07-28 09:56:35 +00008929evalpipe(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00008930{
8931 struct job *jp;
8932 struct nodelist *lp;
8933 int pipelen;
8934 int prevfd;
8935 int pip[2];
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008936 int status = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00008937
Eric Andersenc470f442003-07-28 09:56:35 +00008938 TRACE(("evalpipe(0x%lx) called\n", (long)n));
Eric Andersencb57d552001-06-28 07:25:16 +00008939 pipelen = 0;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008940 for (lp = n->npipe.cmdlist; lp; lp = lp->next)
Eric Andersencb57d552001-06-28 07:25:16 +00008941 pipelen++;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008942 flags |= EV_EXIT;
Denis Vlasenkob012b102007-02-19 22:43:01 +00008943 INT_OFF;
Denis Vlasenko68404f12008-03-17 09:00:54 +00008944 jp = makejob(/*n,*/ pipelen);
Eric Andersencb57d552001-06-28 07:25:16 +00008945 prevfd = -1;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008946 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008947 prehash(lp->n);
Eric Andersencb57d552001-06-28 07:25:16 +00008948 pip[1] = -1;
8949 if (lp->next) {
8950 if (pipe(pip) < 0) {
8951 close(prevfd);
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00008952 ash_msg_and_raise_error("pipe call failed");
Eric Andersencb57d552001-06-28 07:25:16 +00008953 }
8954 }
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00008955 if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) {
Denys Vlasenko70392332016-10-27 02:31:55 +02008956 /* child */
Denis Vlasenkob012b102007-02-19 22:43:01 +00008957 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +00008958 if (pip[1] >= 0) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008959 close(pip[0]);
Eric Andersencb57d552001-06-28 07:25:16 +00008960 }
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008961 if (prevfd > 0) {
8962 dup2(prevfd, 0);
8963 close(prevfd);
8964 }
8965 if (pip[1] > 1) {
8966 dup2(pip[1], 1);
8967 close(pip[1]);
8968 }
Eric Andersenc470f442003-07-28 09:56:35 +00008969 evaltreenr(lp->n, flags);
8970 /* never returns */
Eric Andersencb57d552001-06-28 07:25:16 +00008971 }
Denys Vlasenko70392332016-10-27 02:31:55 +02008972 /* parent */
Eric Andersencb57d552001-06-28 07:25:16 +00008973 if (prevfd >= 0)
8974 close(prevfd);
8975 prevfd = pip[0];
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +00008976 /* Don't want to trigger debugging */
8977 if (pip[1] != -1)
8978 close(pip[1]);
Eric Andersencb57d552001-06-28 07:25:16 +00008979 }
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00008980 if (n->npipe.pipe_backgnd == 0) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008981 status = waitforjob(jp);
8982 TRACE(("evalpipe: job done exit status %d\n", status));
Eric Andersencb57d552001-06-28 07:25:16 +00008983 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00008984 INT_ON;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008985
8986 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00008987}
8988
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00008989/*
8990 * Controls whether the shell is interactive or not.
8991 */
8992static void
8993setinteractive(int on)
8994{
Denis Vlasenkob07a4962008-06-22 13:16:23 +00008995 static smallint is_interactive;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00008996
8997 if (++on == is_interactive)
8998 return;
8999 is_interactive = on;
9000 setsignal(SIGINT);
9001 setsignal(SIGQUIT);
9002 setsignal(SIGTERM);
9003#if !ENABLE_FEATURE_SH_EXTRA_QUIET
9004 if (is_interactive > 1) {
9005 /* Looks like they want an interactive shell */
Denis Vlasenkoca525b42007-06-13 12:27:17 +00009006 static smallint did_banner;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009007
Denis Vlasenkoca525b42007-06-13 12:27:17 +00009008 if (!did_banner) {
Denys Vlasenkoc34c0332009-09-29 12:25:30 +02009009 /* note: ash and hush share this string */
9010 out1fmt("\n\n%s %s\n"
Denys Vlasenko2ec34962014-09-08 16:52:39 +02009011 IF_ASH_HELP("Enter 'help' for a list of built-in commands.\n")
9012 "\n",
Denys Vlasenkoc34c0332009-09-29 12:25:30 +02009013 bb_banner,
9014 "built-in shell (ash)"
9015 );
Denis Vlasenkoca525b42007-06-13 12:27:17 +00009016 did_banner = 1;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009017 }
9018 }
9019#endif
9020}
9021
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009022static void
9023optschanged(void)
9024{
9025#if DEBUG
9026 opentrace();
9027#endif
9028 setinteractive(iflag);
9029 setjobctl(mflag);
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009030#if ENABLE_FEATURE_EDITING_VI
9031 if (viflag)
9032 line_input_state->flags |= VI_MODE;
9033 else
9034 line_input_state->flags &= ~VI_MODE;
9035#else
9036 viflag = 0; /* forcibly keep the option off */
9037#endif
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009038}
9039
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009040static struct localvar *localvars;
9041
9042/*
9043 * Called after a function returns.
9044 * Interrupts must be off.
9045 */
9046static void
9047poplocalvars(void)
9048{
9049 struct localvar *lvp;
9050 struct var *vp;
9051
9052 while ((lvp = localvars) != NULL) {
9053 localvars = lvp->next;
9054 vp = lvp->vp;
Denys Vlasenkob563f622010-09-25 17:15:13 +02009055 TRACE(("poplocalvar %s\n", vp ? vp->var_text : "-"));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009056 if (vp == NULL) { /* $- saved */
9057 memcpy(optlist, lvp->text, sizeof(optlist));
9058 free((char*)lvp->text);
9059 optschanged();
9060 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009061 unsetvar(vp->var_text);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009062 } else {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009063 if (vp->var_func)
9064 vp->var_func(var_end(lvp->text));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009065 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009066 free((char*)vp->var_text);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009067 vp->flags = lvp->flags;
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009068 vp->var_text = lvp->text;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009069 }
9070 free(lvp);
9071 }
9072}
9073
9074static int
9075evalfun(struct funcnode *func, int argc, char **argv, int flags)
9076{
9077 volatile struct shparam saveparam;
9078 struct localvar *volatile savelocalvars;
9079 struct jmploc *volatile savehandler;
9080 struct jmploc jmploc;
9081 int e;
9082
9083 saveparam = shellparam;
9084 savelocalvars = localvars;
Denys Vlasenkoa2d121c2016-09-30 11:30:11 +02009085 savehandler = exception_handler;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009086 e = setjmp(jmploc.loc);
9087 if (e) {
9088 goto funcdone;
9089 }
9090 INT_OFF;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009091 exception_handler = &jmploc;
9092 localvars = NULL;
Denis Vlasenko01631112007-12-16 17:20:38 +00009093 shellparam.malloced = 0;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009094 func->count++;
9095 funcnest++;
9096 INT_ON;
9097 shellparam.nparam = argc - 1;
9098 shellparam.p = argv + 1;
9099#if ENABLE_ASH_GETOPTS
9100 shellparam.optind = 1;
9101 shellparam.optoff = -1;
9102#endif
Denys Vlasenko7aec8682016-10-25 20:26:02 +02009103 evaltree(func->n.narg.next, flags & EV_TESTED);
Denis Vlasenko01631112007-12-16 17:20:38 +00009104 funcdone:
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009105 INT_OFF;
9106 funcnest--;
9107 freefunc(func);
9108 poplocalvars();
9109 localvars = savelocalvars;
9110 freeparam(&shellparam);
9111 shellparam = saveparam;
9112 exception_handler = savehandler;
9113 INT_ON;
9114 evalskip &= ~SKIPFUNC;
9115 return e;
9116}
9117
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009118/*
9119 * Make a variable a local variable. When a variable is made local, it's
9120 * value and flags are saved in a localvar structure. The saved values
9121 * will be restored when the shell function returns. We handle the name
Denys Vlasenkoe0a4e102015-05-13 02:20:14 +02009122 * "-" as a special case: it makes changes to "set +-options" local
9123 * (options will be restored on return from the function).
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009124 */
9125static void
9126mklocal(char *name)
9127{
9128 struct localvar *lvp;
9129 struct var **vpp;
9130 struct var *vp;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009131 char *eq = strchr(name, '=');
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009132
9133 INT_OFF;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009134 /* Cater for duplicate "local". Examples:
9135 * x=0; f() { local x=1; echo $x; local x; echo $x; }; f; echo $x
9136 * x=0; f() { local x=1; echo $x; local x=2; echo $x; }; f; echo $x
9137 */
9138 lvp = localvars;
9139 while (lvp) {
Eugene Rudoy1285aa62015-04-26 23:32:00 +02009140 if (lvp->vp && varcmp(lvp->vp->var_text, name) == 0) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009141 if (eq)
9142 setvareq(name, 0);
9143 /* else:
9144 * it's a duplicate "local VAR" declaration, do nothing
9145 */
Denys Vlasenko06b11492016-11-04 16:43:18 +01009146 goto ret;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009147 }
9148 lvp = lvp->next;
9149 }
9150
9151 lvp = ckzalloc(sizeof(*lvp));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009152 if (LONE_DASH(name)) {
9153 char *p;
9154 p = ckmalloc(sizeof(optlist));
9155 lvp->text = memcpy(p, optlist, sizeof(optlist));
9156 vp = NULL;
9157 } else {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009158 vpp = hashvar(name);
9159 vp = *findvar(vpp, name);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009160 if (vp == NULL) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009161 /* variable did not exist yet */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009162 if (eq)
9163 setvareq(name, VSTRFIXED);
9164 else
9165 setvar(name, NULL, VSTRFIXED);
9166 vp = *vpp; /* the new variable */
9167 lvp->flags = VUNSET;
9168 } else {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009169 lvp->text = vp->var_text;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009170 lvp->flags = vp->flags;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009171 /* make sure neither "struct var" nor string gets freed
9172 * during (un)setting:
9173 */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009174 vp->flags |= VSTRFIXED|VTEXTFIXED;
9175 if (eq)
9176 setvareq(name, 0);
Denys Vlasenko109ee5d2014-03-16 18:41:11 +01009177 else
9178 /* "local VAR" unsets VAR: */
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009179 setvar0(name, NULL);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009180 }
9181 }
9182 lvp->vp = vp;
9183 lvp->next = localvars;
9184 localvars = lvp;
Denys Vlasenko06b11492016-11-04 16:43:18 +01009185 ret:
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009186 INT_ON;
9187}
9188
9189/*
9190 * The "local" command.
9191 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009192static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009193localcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009194{
9195 char *name;
9196
Ron Yorstonef2386b2015-10-29 16:19:14 +00009197 if (!funcnest)
9198 ash_msg_and_raise_error("not in a function");
9199
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009200 argv = argptr;
9201 while ((name = *argv++) != NULL) {
9202 mklocal(name);
9203 }
9204 return 0;
9205}
9206
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009207static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009208falsecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009209{
9210 return 1;
9211}
9212
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009213static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009214truecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009215{
9216 return 0;
9217}
9218
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009219static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009220execcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009221{
Denis Vlasenko68404f12008-03-17 09:00:54 +00009222 if (argv[1]) {
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009223 iflag = 0; /* exit on error */
9224 mflag = 0;
9225 optschanged();
Denys Vlasenkoe5814a52016-07-16 18:33:55 +02009226 /* We should set up signals for "exec CMD"
9227 * the same way as for "CMD" without "exec".
9228 * But optschanged->setinteractive->setsignal
9229 * still thought we are a root shell. Therefore, for example,
9230 * SIGQUIT is still set to IGN. Fix it:
9231 */
9232 shlvl++;
9233 setsignal(SIGQUIT);
9234 /*setsignal(SIGTERM); - unnecessary because of iflag=0 */
9235 /*setsignal(SIGTSTP); - unnecessary because of mflag=0 */
9236 /*setsignal(SIGTTOU); - unnecessary because of mflag=0 */
9237
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009238 shellexec(argv + 1, pathval(), 0);
Denys Vlasenkoe5814a52016-07-16 18:33:55 +02009239 /* NOTREACHED */
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009240 }
9241 return 0;
9242}
9243
9244/*
9245 * The return command.
9246 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009247static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009248returncmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009249{
9250 /*
9251 * If called outside a function, do what ksh does;
9252 * skip the rest of the file.
9253 */
Denys Vlasenko6a0710e2016-09-30 14:18:34 +02009254 evalskip = SKIPFUNC;
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009255 return argv[1] ? number(argv[1]) : exitstatus;
9256}
9257
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009258/* Forward declarations for builtintab[] */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009259static int breakcmd(int, char **) FAST_FUNC;
9260static int dotcmd(int, char **) FAST_FUNC;
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009261static int evalcmd(int, char **, int) FAST_FUNC;
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009262static int exitcmd(int, char **) FAST_FUNC;
9263static int exportcmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009264#if ENABLE_ASH_GETOPTS
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009265static int getoptscmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009266#endif
Denys Vlasenko2ec34962014-09-08 16:52:39 +02009267#if ENABLE_ASH_HELP
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009268static int helpcmd(int, char **) FAST_FUNC;
Denis Vlasenko52764022007-02-24 13:42:56 +00009269#endif
Flemming Madsend96ffda2013-04-07 18:47:24 +02009270#if MAX_HISTORY
9271static int historycmd(int, char **) FAST_FUNC;
9272#endif
Denys Vlasenko0b883582016-12-23 16:49:07 +01009273#if ENABLE_FEATURE_SH_MATH
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009274static int letcmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009275#endif
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009276static int readcmd(int, char **) FAST_FUNC;
9277static int setcmd(int, char **) FAST_FUNC;
9278static int shiftcmd(int, char **) FAST_FUNC;
9279static int timescmd(int, char **) FAST_FUNC;
9280static int trapcmd(int, char **) FAST_FUNC;
9281static int umaskcmd(int, char **) FAST_FUNC;
9282static int unsetcmd(int, char **) FAST_FUNC;
9283static int ulimitcmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009284
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009285#define BUILTIN_NOSPEC "0"
9286#define BUILTIN_SPECIAL "1"
9287#define BUILTIN_REGULAR "2"
9288#define BUILTIN_SPEC_REG "3"
9289#define BUILTIN_ASSIGN "4"
9290#define BUILTIN_SPEC_ASSG "5"
9291#define BUILTIN_REG_ASSG "6"
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009292#define BUILTIN_SPEC_REG_ASSG "7"
9293
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009294/* Stubs for calling non-FAST_FUNC's */
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009295#if ENABLE_ASH_BUILTIN_ECHO
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009296static int FAST_FUNC echocmd(int argc, char **argv) { return echo_main(argc, argv); }
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009297#endif
9298#if ENABLE_ASH_BUILTIN_PRINTF
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009299static int FAST_FUNC printfcmd(int argc, char **argv) { return printf_main(argc, argv); }
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009300#endif
9301#if ENABLE_ASH_BUILTIN_TEST
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009302static int FAST_FUNC testcmd(int argc, char **argv) { return test_main(argc, argv); }
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009303#endif
Denis Vlasenko468aea22008-04-01 14:47:57 +00009304
Denis Vlasenkof7d56652008-03-25 05:51:41 +00009305/* Keep these in proper order since it is searched via bsearch() */
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009306static const struct builtincmd builtintab[] = {
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009307 { BUILTIN_SPEC_REG "." , dotcmd },
9308 { BUILTIN_SPEC_REG ":" , truecmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009309#if ENABLE_ASH_BUILTIN_TEST
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009310 { BUILTIN_REGULAR "[" , testcmd },
Denys Vlasenko15fb91c2016-11-23 18:31:48 +01009311# if ENABLE_ASH_BASH_COMPAT
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009312 { BUILTIN_REGULAR "[[" , testcmd },
Denys Vlasenko15fb91c2016-11-23 18:31:48 +01009313# endif
Denis Vlasenko80591b02008-03-25 07:49:43 +00009314#endif
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009315#if ENABLE_ASH_ALIAS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009316 { BUILTIN_REG_ASSG "alias" , aliascmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009317#endif
9318#if JOBS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009319 { BUILTIN_REGULAR "bg" , fg_bgcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009320#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009321 { BUILTIN_SPEC_REG "break" , breakcmd },
9322 { BUILTIN_REGULAR "cd" , cdcmd },
9323 { BUILTIN_NOSPEC "chdir" , cdcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009324#if ENABLE_ASH_CMDCMD
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009325 { BUILTIN_REGULAR "command" , commandcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009326#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009327 { BUILTIN_SPEC_REG "continue", breakcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009328#if ENABLE_ASH_BUILTIN_ECHO
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009329 { BUILTIN_REGULAR "echo" , echocmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009330#endif
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009331 { BUILTIN_SPEC_REG "eval" , NULL }, /*evalcmd() has a differing prototype*/
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009332 { BUILTIN_SPEC_REG "exec" , execcmd },
9333 { BUILTIN_SPEC_REG "exit" , exitcmd },
9334 { BUILTIN_SPEC_REG_ASSG "export" , exportcmd },
9335 { BUILTIN_REGULAR "false" , falsecmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009336#if JOBS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009337 { BUILTIN_REGULAR "fg" , fg_bgcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009338#endif
9339#if ENABLE_ASH_GETOPTS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009340 { BUILTIN_REGULAR "getopts" , getoptscmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009341#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009342 { BUILTIN_NOSPEC "hash" , hashcmd },
Denys Vlasenko2ec34962014-09-08 16:52:39 +02009343#if ENABLE_ASH_HELP
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009344 { BUILTIN_NOSPEC "help" , helpcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009345#endif
Flemming Madsend96ffda2013-04-07 18:47:24 +02009346#if MAX_HISTORY
9347 { BUILTIN_NOSPEC "history" , historycmd },
9348#endif
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009349#if JOBS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009350 { BUILTIN_REGULAR "jobs" , jobscmd },
9351 { BUILTIN_REGULAR "kill" , killcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009352#endif
Denys Vlasenko0b883582016-12-23 16:49:07 +01009353#if ENABLE_FEATURE_SH_MATH
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009354 { BUILTIN_NOSPEC "let" , letcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009355#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009356 { BUILTIN_ASSIGN "local" , localcmd },
Denis Vlasenkocd2663f2008-06-01 22:36:39 +00009357#if ENABLE_ASH_BUILTIN_PRINTF
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009358 { BUILTIN_REGULAR "printf" , printfcmd },
Denis Vlasenkocd2663f2008-06-01 22:36:39 +00009359#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009360 { BUILTIN_NOSPEC "pwd" , pwdcmd },
9361 { BUILTIN_REGULAR "read" , readcmd },
9362 { BUILTIN_SPEC_REG_ASSG "readonly", exportcmd },
9363 { BUILTIN_SPEC_REG "return" , returncmd },
9364 { BUILTIN_SPEC_REG "set" , setcmd },
9365 { BUILTIN_SPEC_REG "shift" , shiftcmd },
Denys Vlasenko82731b42010-05-17 17:49:52 +02009366#if ENABLE_ASH_BASH_COMPAT
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009367 { BUILTIN_SPEC_REG "source" , dotcmd },
Denys Vlasenko82731b42010-05-17 17:49:52 +02009368#endif
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009369#if ENABLE_ASH_BUILTIN_TEST
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009370 { BUILTIN_REGULAR "test" , testcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009371#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009372 { BUILTIN_SPEC_REG "times" , timescmd },
9373 { BUILTIN_SPEC_REG "trap" , trapcmd },
9374 { BUILTIN_REGULAR "true" , truecmd },
9375 { BUILTIN_NOSPEC "type" , typecmd },
9376 { BUILTIN_NOSPEC "ulimit" , ulimitcmd },
9377 { BUILTIN_REGULAR "umask" , umaskcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009378#if ENABLE_ASH_ALIAS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009379 { BUILTIN_REGULAR "unalias" , unaliascmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009380#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009381 { BUILTIN_SPEC_REG "unset" , unsetcmd },
9382 { BUILTIN_REGULAR "wait" , waitcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009383};
9384
Denis Vlasenko80591b02008-03-25 07:49:43 +00009385/* Should match the above table! */
9386#define COMMANDCMD (builtintab + \
Denys Vlasenko928e2a72016-09-29 00:30:31 +02009387 /* . : */ 2 + \
9388 /* [ */ 1 * ENABLE_ASH_BUILTIN_TEST + \
9389 /* [[ */ 1 * ENABLE_ASH_BUILTIN_TEST * ENABLE_ASH_BASH_COMPAT + \
9390 /* alias */ 1 * ENABLE_ASH_ALIAS + \
9391 /* bg */ 1 * ENABLE_ASH_JOB_CONTROL + \
9392 /* break cd cddir */ 3)
9393#define EVALCMD (COMMANDCMD + \
9394 /* command */ 1 * ENABLE_ASH_CMDCMD + \
9395 /* continue */ 1 + \
9396 /* echo */ 1 * ENABLE_ASH_BUILTIN_ECHO + \
9397 0)
9398#define EXECCMD (EVALCMD + \
9399 /* eval */ 1)
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009400
9401/*
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009402 * Search the table of builtin commands.
9403 */
Denys Vlasenko888527c2016-10-02 16:54:17 +02009404static int
9405pstrcmp1(const void *a, const void *b)
9406{
9407 return strcmp((char*)a, *(char**)b + 1);
9408}
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009409static struct builtincmd *
9410find_builtin(const char *name)
9411{
9412 struct builtincmd *bp;
9413
9414 bp = bsearch(
Denis Vlasenko80b8b392007-06-25 10:55:35 +00009415 name, builtintab, ARRAY_SIZE(builtintab), sizeof(builtintab[0]),
Denys Vlasenko888527c2016-10-02 16:54:17 +02009416 pstrcmp1
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009417 );
9418 return bp;
9419}
9420
9421/*
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009422 * Execute a simple command.
9423 */
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009424static int
9425isassignment(const char *p)
Paul Foxc3850c82005-07-20 18:23:39 +00009426{
9427 const char *q = endofname(p);
9428 if (p == q)
9429 return 0;
9430 return *q == '=';
9431}
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009432static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009433bltincmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009434{
9435 /* Preserve exitstatus of a previous possible redirection
9436 * as POSIX mandates */
9437 return back_exitstatus;
9438}
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009439static int
Eric Andersenc470f442003-07-28 09:56:35 +00009440evalcommand(union node *cmd, int flags)
9441{
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00009442 static const struct builtincmd null_bltin = {
9443 "\0\0", bltincmd /* why three NULs? */
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009444 };
Eric Andersenc470f442003-07-28 09:56:35 +00009445 struct stackmark smark;
9446 union node *argp;
9447 struct arglist arglist;
9448 struct arglist varlist;
9449 char **argv;
9450 int argc;
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009451 const struct strlist *sp;
Eric Andersenc470f442003-07-28 09:56:35 +00009452 struct cmdentry cmdentry;
9453 struct job *jp;
9454 char *lastarg;
9455 const char *path;
9456 int spclbltin;
Eric Andersenc470f442003-07-28 09:56:35 +00009457 int status;
9458 char **nargv;
Paul Foxc3850c82005-07-20 18:23:39 +00009459 struct builtincmd *bcmd;
Denis Vlasenko34c73c42008-08-16 11:48:02 +00009460 smallint cmd_is_exec;
9461 smallint pseudovarflag = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00009462
9463 /* First expand the arguments. */
9464 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
9465 setstackmark(&smark);
9466 back_exitstatus = 0;
9467
9468 cmdentry.cmdtype = CMDBUILTIN;
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00009469 cmdentry.u.cmd = &null_bltin;
Eric Andersenc470f442003-07-28 09:56:35 +00009470 varlist.lastp = &varlist.list;
9471 *varlist.lastp = NULL;
9472 arglist.lastp = &arglist.list;
9473 *arglist.lastp = NULL;
9474
9475 argc = 0;
Denis Vlasenkob012b102007-02-19 22:43:01 +00009476 if (cmd->ncmd.args) {
Paul Foxc3850c82005-07-20 18:23:39 +00009477 bcmd = find_builtin(cmd->ncmd.args->narg.text);
9478 pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd);
9479 }
9480
Eric Andersenc470f442003-07-28 09:56:35 +00009481 for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) {
9482 struct strlist **spp;
9483
9484 spp = arglist.lastp;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00009485 if (pseudovarflag && isassignment(argp->narg.text))
Paul Foxc3850c82005-07-20 18:23:39 +00009486 expandarg(argp, &arglist, EXP_VARTILDE);
9487 else
9488 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
9489
Eric Andersenc470f442003-07-28 09:56:35 +00009490 for (sp = *spp; sp; sp = sp->next)
9491 argc++;
9492 }
9493
Denys Vlasenko65a8b852016-10-26 22:29:11 +02009494 /* Reserve one extra spot at the front for shellexec. */
9495 nargv = stalloc(sizeof(char *) * (argc + 2));
9496 argv = ++nargv;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009497 for (sp = arglist.list; sp; sp = sp->next) {
Eric Andersenc470f442003-07-28 09:56:35 +00009498 TRACE(("evalcommand arg: %s\n", sp->text));
9499 *nargv++ = sp->text;
9500 }
9501 *nargv = NULL;
9502
9503 lastarg = NULL;
9504 if (iflag && funcnest == 0 && argc > 0)
9505 lastarg = nargv[-1];
9506
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009507 preverrout_fd = 2;
Eric Andersenc470f442003-07-28 09:56:35 +00009508 expredir(cmd->ncmd.redirect);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009509 status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH | REDIR_SAVEFD2);
Eric Andersenc470f442003-07-28 09:56:35 +00009510
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009511 path = vpath.var_text;
Eric Andersenc470f442003-07-28 09:56:35 +00009512 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
9513 struct strlist **spp;
9514 char *p;
9515
9516 spp = varlist.lastp;
9517 expandarg(argp, &varlist, EXP_VARTILDE);
9518
9519 /*
9520 * Modify the command lookup path, if a PATH= assignment
9521 * is present
9522 */
9523 p = (*spp)->text;
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009524 if (varcmp(p, path) == 0)
Eric Andersenc470f442003-07-28 09:56:35 +00009525 path = p;
9526 }
9527
9528 /* Print the command if xflag is set. */
9529 if (xflag) {
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009530 int n;
Denys Vlasenkofd33e172010-06-26 22:55:44 +02009531 const char *p = " %s" + 1;
Eric Andersenc470f442003-07-28 09:56:35 +00009532
Denis Vlasenko0de37e12007-10-17 11:08:53 +00009533 fdprintf(preverrout_fd, p, expandstr(ps4val()));
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009534 sp = varlist.list;
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +00009535 for (n = 0; n < 2; n++) {
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009536 while (sp) {
Denis Vlasenko0de37e12007-10-17 11:08:53 +00009537 fdprintf(preverrout_fd, p, sp->text);
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009538 sp = sp->next;
Denys Vlasenkofd33e172010-06-26 22:55:44 +02009539 p = " %s";
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009540 }
9541 sp = arglist.list;
9542 }
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00009543 safe_write(preverrout_fd, "\n", 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009544 }
9545
9546 cmd_is_exec = 0;
9547 spclbltin = -1;
9548
9549 /* Now locate the command. */
9550 if (argc) {
Eric Andersenc470f442003-07-28 09:56:35 +00009551 int cmd_flag = DO_ERR;
Denys Vlasenko0b4980c2012-09-25 12:49:29 +02009552#if ENABLE_ASH_CMDCMD
9553 const char *oldpath = path + 5;
9554#endif
Eric Andersenc470f442003-07-28 09:56:35 +00009555 path += 5;
Eric Andersenc470f442003-07-28 09:56:35 +00009556 for (;;) {
9557 find_command(argv[0], &cmdentry, cmd_flag, path);
9558 if (cmdentry.cmdtype == CMDUNKNOWN) {
Denys Vlasenko8131eea2009-11-02 14:19:51 +01009559 flush_stdout_stderr();
Denis Vlasenko6514c5e2008-07-24 13:41:37 +00009560 status = 127;
Eric Andersenc470f442003-07-28 09:56:35 +00009561 goto bail;
9562 }
9563
9564 /* implement bltin and command here */
9565 if (cmdentry.cmdtype != CMDBUILTIN)
9566 break;
9567 if (spclbltin < 0)
9568 spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd);
9569 if (cmdentry.u.cmd == EXECCMD)
Denis Vlasenko34c73c42008-08-16 11:48:02 +00009570 cmd_is_exec = 1;
Denis Vlasenko131ae172007-02-18 13:00:19 +00009571#if ENABLE_ASH_CMDCMD
Eric Andersenc470f442003-07-28 09:56:35 +00009572 if (cmdentry.u.cmd == COMMANDCMD) {
Eric Andersenc470f442003-07-28 09:56:35 +00009573 path = oldpath;
9574 nargv = parse_command_args(argv, &path);
9575 if (!nargv)
9576 break;
Denys Vlasenkocac4d002016-10-01 03:02:25 +02009577 /* It's "command [-p] PROG ARGS" (that is, no -Vv).
9578 * nargv => "PROG". path is updated if -p.
9579 */
Eric Andersenc470f442003-07-28 09:56:35 +00009580 argc -= nargv - argv;
9581 argv = nargv;
9582 cmd_flag |= DO_NOFUNC;
9583 } else
9584#endif
9585 break;
9586 }
9587 }
9588
9589 if (status) {
Ron Yorstonea7d2f62017-01-03 11:18:23 +01009590 bail:
9591 exitstatus = status;
9592
Eric Andersenc470f442003-07-28 09:56:35 +00009593 /* We have a redirection error. */
9594 if (spclbltin > 0)
Denis Vlasenkob012b102007-02-19 22:43:01 +00009595 raise_exception(EXERROR);
Ron Yorstonea7d2f62017-01-03 11:18:23 +01009596
Eric Andersenc470f442003-07-28 09:56:35 +00009597 goto out;
9598 }
9599
9600 /* Execute the command. */
9601 switch (cmdentry.cmdtype) {
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009602 default: {
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +00009603
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009604#if ENABLE_FEATURE_SH_NOFORK
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009605/* (1) BUG: if variables are set, we need to fork, or save/restore them
9606 * around run_nofork_applet() call.
9607 * (2) Should this check also be done in forkshell()?
9608 * (perhaps it should, so that "VAR=VAL nofork" at least avoids exec...)
9609 */
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00009610 /* find_command() encodes applet_no as (-2 - applet_no) */
9611 int applet_no = (- cmdentry.u.index - 2);
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009612 if (applet_no >= 0 && APPLET_IS_NOFORK(applet_no)) {
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009613 listsetvar(varlist.list, VEXPORT|VSTACK);
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00009614 /* run <applet>_main() */
Ron Yorston5ccb0e92016-10-20 12:24:02 +01009615 status = run_nofork_applet(applet_no, argv);
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009616 break;
9617 }
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009618#endif
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009619 /* Can we avoid forking off? For example, very last command
9620 * in a script or a subshell does not need forking,
9621 * we can just exec it.
9622 */
Denys Vlasenko238bf182010-05-18 15:49:07 +02009623 if (!(flags & EV_EXIT) || may_have_traps) {
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009624 /* No, forking off a child is necessary */
Denis Vlasenkob012b102007-02-19 22:43:01 +00009625 INT_OFF;
Denis Vlasenko68404f12008-03-17 09:00:54 +00009626 jp = makejob(/*cmd,*/ 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009627 if (forkshell(jp, cmd, FORK_FG) != 0) {
Denys Vlasenko238bf182010-05-18 15:49:07 +02009628 /* parent */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009629 status = waitforjob(jp);
Denis Vlasenkob012b102007-02-19 22:43:01 +00009630 INT_ON;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009631 TRACE(("forked child exited with %d\n", status));
Eric Andersenc470f442003-07-28 09:56:35 +00009632 break;
9633 }
Denys Vlasenko238bf182010-05-18 15:49:07 +02009634 /* child */
Denis Vlasenkob012b102007-02-19 22:43:01 +00009635 FORCE_INT_ON;
Denys Vlasenkoc7f95d22010-05-18 15:52:23 +02009636 /* fall through to exec'ing external program */
Eric Andersenc470f442003-07-28 09:56:35 +00009637 }
9638 listsetvar(varlist.list, VEXPORT|VSTACK);
9639 shellexec(argv, path, cmdentry.u.index);
9640 /* NOTREACHED */
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009641 } /* default */
Eric Andersenc470f442003-07-28 09:56:35 +00009642 case CMDBUILTIN:
9643 cmdenviron = varlist.list;
9644 if (cmdenviron) {
9645 struct strlist *list = cmdenviron;
9646 int i = VNOSET;
9647 if (spclbltin > 0 || argc == 0) {
9648 i = 0;
9649 if (cmd_is_exec && argc > 1)
9650 i = VEXPORT;
9651 }
9652 listsetvar(list, i);
9653 }
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +00009654 /* Tight loop with builtins only:
9655 * "while kill -0 $child; do true; done"
9656 * will never exit even if $child died, unless we do this
9657 * to reap the zombie and make kill detect that it's gone: */
9658 dowait(DOWAIT_NONBLOCK, NULL);
9659
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009660 if (evalbltin(cmdentry.u.cmd, argc, argv, flags)) {
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02009661 if (exception_type == EXERROR && spclbltin <= 0) {
9662 FORCE_INT_ON;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +02009663 goto readstatus;
Eric Andersenc470f442003-07-28 09:56:35 +00009664 }
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02009665 raise:
9666 longjmp(exception_handler->loc, 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009667 }
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009668 goto readstatus;
Eric Andersenc470f442003-07-28 09:56:35 +00009669
9670 case CMDFUNCTION:
9671 listsetvar(varlist.list, 0);
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +00009672 /* See above for the rationale */
9673 dowait(DOWAIT_NONBLOCK, NULL);
Eric Andersenc470f442003-07-28 09:56:35 +00009674 if (evalfun(cmdentry.u.func, argc, argv, flags))
9675 goto raise;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009676 readstatus:
9677 status = exitstatus;
Eric Andersenc470f442003-07-28 09:56:35 +00009678 break;
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009679 } /* switch */
Eric Andersenc470f442003-07-28 09:56:35 +00009680
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009681 out:
Denys Vlasenkoeaf94362016-10-25 21:46:03 +02009682 if (cmd->ncmd.redirect)
9683 popredir(/*drop:*/ cmd_is_exec, /*restore:*/ cmd_is_exec);
Denis Vlasenko6514c5e2008-07-24 13:41:37 +00009684 if (lastarg) {
Eric Andersenc470f442003-07-28 09:56:35 +00009685 /* dsl: I think this is intended to be used to support
9686 * '_' in 'vi' command mode during line editing...
9687 * However I implemented that within libedit itself.
9688 */
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009689 setvar0("_", lastarg);
Denis Vlasenko6514c5e2008-07-24 13:41:37 +00009690 }
Eric Andersenc470f442003-07-28 09:56:35 +00009691 popstackmark(&smark);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009692
9693 return status;
Eric Andersenc470f442003-07-28 09:56:35 +00009694}
9695
9696static int
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009697evalbltin(const struct builtincmd *cmd, int argc, char **argv, int flags)
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009698{
Eric Andersenc470f442003-07-28 09:56:35 +00009699 char *volatile savecmdname;
9700 struct jmploc *volatile savehandler;
9701 struct jmploc jmploc;
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009702 int status;
Eric Andersenc470f442003-07-28 09:56:35 +00009703 int i;
9704
9705 savecmdname = commandname;
Denys Vlasenkoa2d121c2016-09-30 11:30:11 +02009706 savehandler = exception_handler;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009707 i = setjmp(jmploc.loc);
9708 if (i)
Eric Andersenc470f442003-07-28 09:56:35 +00009709 goto cmddone;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009710 exception_handler = &jmploc;
Eric Andersenc470f442003-07-28 09:56:35 +00009711 commandname = argv[0];
9712 argptr = argv + 1;
9713 optptr = NULL; /* initialize nextopt */
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009714 if (cmd == EVALCMD)
9715 status = evalcmd(argc, argv, flags);
9716 else
9717 status = (*cmd->builtin)(argc, argv);
Denis Vlasenkob012b102007-02-19 22:43:01 +00009718 flush_stdout_stderr();
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009719 status |= ferror(stdout);
9720 exitstatus = status;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009721 cmddone:
Rob Landleyf296f0b2006-07-06 01:09:21 +00009722 clearerr(stdout);
Eric Andersenc470f442003-07-28 09:56:35 +00009723 commandname = savecmdname;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009724 exception_handler = savehandler;
Eric Andersenc470f442003-07-28 09:56:35 +00009725
9726 return i;
9727}
9728
Denis Vlasenkoaa744452007-02-23 01:04:22 +00009729static int
9730goodname(const char *p)
Glenn L McGrath16e45d72004-02-04 08:24:39 +00009731{
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02009732 return endofname(p)[0] == '\0';
Glenn L McGrath16e45d72004-02-04 08:24:39 +00009733}
9734
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009735
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009736/*
9737 * Search for a command. This is called before we fork so that the
9738 * location of the command will be available in the parent as well as
Glenn L McGrath16e45d72004-02-04 08:24:39 +00009739 * the child. The check for "goodname" is an overly conservative
9740 * check that the name will not be subject to expansion.
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009741 */
Eric Andersenc470f442003-07-28 09:56:35 +00009742static void
9743prehash(union node *n)
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009744{
9745 struct cmdentry entry;
9746
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +00009747 if (n->type == NCMD && n->ncmd.args && goodname(n->ncmd.args->narg.text))
9748 find_command(n->ncmd.args->narg.text, &entry, 0, pathval());
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009749}
9750
Eric Andersencb57d552001-06-28 07:25:16 +00009751
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009752/* ============ Builtin commands
9753 *
9754 * Builtin commands whose functions are closely tied to evaluation
9755 * are implemented here.
Eric Andersencb57d552001-06-28 07:25:16 +00009756 */
9757
9758/*
Eric Andersencb57d552001-06-28 07:25:16 +00009759 * Handle break and continue commands. Break, continue, and return are
9760 * all handled by setting the evalskip flag. The evaluation routines
9761 * above all check this flag, and if it is set they start skipping
9762 * commands rather than executing them. The variable skipcount is
9763 * the number of loops to break/continue, or the number of function
9764 * levels to return. (The latter is always 1.) It should probably
9765 * be an error to break out of more loops than exist, but it isn't
9766 * in the standard shell so we don't make it one here.
9767 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009768static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009769breakcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00009770{
Denis Vlasenko68404f12008-03-17 09:00:54 +00009771 int n = argv[1] ? number(argv[1]) : 1;
Eric Andersencb57d552001-06-28 07:25:16 +00009772
Aaron Lehmann2aef3a62001-12-31 06:03:12 +00009773 if (n <= 0)
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02009774 ash_msg_and_raise_error(msg_illnum, argv[1]);
Eric Andersencb57d552001-06-28 07:25:16 +00009775 if (n > loopnest)
9776 n = loopnest;
9777 if (n > 0) {
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009778 evalskip = (**argv == 'c') ? SKIPCONT : SKIPBREAK;
Eric Andersencb57d552001-06-28 07:25:16 +00009779 skipcount = n;
9780 }
9781 return 0;
9782}
9783
Eric Andersenc470f442003-07-28 09:56:35 +00009784
Denys Vlasenko70392332016-10-27 02:31:55 +02009785/*
Eric Andersen90898442003-08-06 11:20:52 +00009786 * This implements the input routines used by the parser.
Eric Andersencb57d552001-06-28 07:25:16 +00009787 */
Denis Vlasenko99eb8502007-02-23 21:09:49 +00009788
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009789enum {
9790 INPUT_PUSH_FILE = 1,
9791 INPUT_NOFILE_OK = 2,
9792};
Eric Andersencb57d552001-06-28 07:25:16 +00009793
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009794static smallint checkkwd;
Denis Vlasenko99eb8502007-02-23 21:09:49 +00009795/* values of checkkwd variable */
9796#define CHKALIAS 0x1
9797#define CHKKWD 0x2
9798#define CHKNL 0x4
9799
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009800/*
9801 * Push a string back onto the input at this current parsefile level.
9802 * We handle aliases this way.
9803 */
9804#if !ENABLE_ASH_ALIAS
9805#define pushstring(s, ap) pushstring(s)
9806#endif
9807static void
9808pushstring(char *s, struct alias *ap)
9809{
9810 struct strpush *sp;
9811 int len;
9812
9813 len = strlen(s);
9814 INT_OFF;
9815 if (g_parsefile->strpush) {
9816 sp = ckzalloc(sizeof(*sp));
9817 sp->prev = g_parsefile->strpush;
9818 } else {
9819 sp = &(g_parsefile->basestrpush);
9820 }
9821 g_parsefile->strpush = sp;
9822 sp->prev_string = g_parsefile->next_to_pgetc;
9823 sp->prev_left_in_line = g_parsefile->left_in_line;
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02009824 sp->unget = g_parsefile->unget;
9825 memcpy(sp->lastc, g_parsefile->lastc, sizeof(sp->lastc));
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009826#if ENABLE_ASH_ALIAS
9827 sp->ap = ap;
9828 if (ap) {
9829 ap->flag |= ALIASINUSE;
9830 sp->string = s;
9831 }
9832#endif
9833 g_parsefile->next_to_pgetc = s;
9834 g_parsefile->left_in_line = len;
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02009835 g_parsefile->unget = 0;
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009836 INT_ON;
9837}
9838
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009839static void
9840popstring(void)
Eric Andersenc470f442003-07-28 09:56:35 +00009841{
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009842 struct strpush *sp = g_parsefile->strpush;
Eric Andersenc470f442003-07-28 09:56:35 +00009843
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009844 INT_OFF;
Denis Vlasenko131ae172007-02-18 13:00:19 +00009845#if ENABLE_ASH_ALIAS
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009846 if (sp->ap) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009847 if (g_parsefile->next_to_pgetc[-1] == ' '
9848 || g_parsefile->next_to_pgetc[-1] == '\t'
9849 ) {
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009850 checkkwd |= CHKALIAS;
Glenn L McGrath28939ad2004-07-21 10:20:19 +00009851 }
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009852 if (sp->string != sp->ap->val) {
9853 free(sp->string);
9854 }
9855 sp->ap->flag &= ~ALIASINUSE;
9856 if (sp->ap->flag & ALIASDEAD) {
9857 unalias(sp->ap->name);
9858 }
Glenn L McGrath28939ad2004-07-21 10:20:19 +00009859 }
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00009860#endif
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009861 g_parsefile->next_to_pgetc = sp->prev_string;
9862 g_parsefile->left_in_line = sp->prev_left_in_line;
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02009863 g_parsefile->unget = sp->unget;
9864 memcpy(g_parsefile->lastc, sp->lastc, sizeof(sp->lastc));
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009865 g_parsefile->strpush = sp->prev;
9866 if (sp != &(g_parsefile->basestrpush))
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009867 free(sp);
9868 INT_ON;
9869}
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00009870
Denis Vlasenkoaa744452007-02-23 01:04:22 +00009871static int
9872preadfd(void)
Eric Andersencb57d552001-06-28 07:25:16 +00009873{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009874 int nr;
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00009875 char *buf = g_parsefile->buf;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009876
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009877 g_parsefile->next_to_pgetc = buf;
Denis Vlasenko38f63192007-01-22 09:03:07 +00009878#if ENABLE_FEATURE_EDITING
Denis Vlasenko85c24712008-03-17 09:04:04 +00009879 retry:
Denys Vlasenko79b3d422010-06-03 04:29:08 +02009880 if (!iflag || g_parsefile->pf_fd != STDIN_FILENO)
Ron Yorston61d6ae22015-04-19 10:50:25 +01009881 nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009882 else {
Denys Vlasenko66c5b122011-02-08 05:07:02 +01009883 int timeout = -1;
9884# if ENABLE_ASH_IDLE_TIMEOUT
9885 if (iflag) {
9886 const char *tmout_var = lookupvar("TMOUT");
9887 if (tmout_var) {
9888 timeout = atoi(tmout_var) * 1000;
9889 if (timeout <= 0)
9890 timeout = -1;
9891 }
9892 }
9893# endif
Denys Vlasenko8c52f802011-02-04 17:36:21 +01009894# if ENABLE_FEATURE_TAB_COMPLETION
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00009895 line_input_state->path_lookup = pathval();
Denys Vlasenko8c52f802011-02-04 17:36:21 +01009896# endif
Denys Vlasenkoe9ab07c2014-08-13 18:00:08 +02009897 reinit_unicode_for_ash();
Denys Vlasenko66c5b122011-02-08 05:07:02 +01009898 nr = read_line_input(line_input_state, cmdedit_prompt, buf, IBUFSIZ, timeout);
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00009899 if (nr == 0) {
Denys Vlasenko4b89d512016-11-25 03:41:03 +01009900 /* ^C pressed, "convert" to SIGINT */
9901 write(STDOUT_FILENO, "^C", 2);
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00009902 if (trap[SIGINT]) {
Glenn L McGrath16e45d72004-02-04 08:24:39 +00009903 buf[0] = '\n';
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00009904 buf[1] = '\0';
Glenn L McGrath16e45d72004-02-04 08:24:39 +00009905 raise(SIGINT);
9906 return 1;
9907 }
Denys Vlasenko8660aeb2016-11-24 17:44:02 +01009908 exitstatus = 128 + SIGINT;
Denys Vlasenko4b89d512016-11-25 03:41:03 +01009909 bb_putchar('\n');
Eric Andersenc470f442003-07-28 09:56:35 +00009910 goto retry;
9911 }
Denys Vlasenko66c5b122011-02-08 05:07:02 +01009912 if (nr < 0) {
9913 if (errno == 0) {
9914 /* Ctrl+D pressed */
9915 nr = 0;
9916 }
9917# if ENABLE_ASH_IDLE_TIMEOUT
9918 else if (errno == EAGAIN && timeout > 0) {
Denys Vlasenkod60752f2015-10-07 22:42:45 +02009919 puts("\007timed out waiting for input: auto-logout");
Denys Vlasenko66c5b122011-02-08 05:07:02 +01009920 exitshell();
9921 }
9922# endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009923 }
Eric Andersencb57d552001-06-28 07:25:16 +00009924 }
9925#else
Ron Yorston61d6ae22015-04-19 10:50:25 +01009926 nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1);
Eric Andersencb57d552001-06-28 07:25:16 +00009927#endif
9928
Denys Vlasenko80c5b682011-05-08 21:21:10 +02009929#if 0 /* disabled: nonblock_immune_read() handles this problem */
Eric Andersencb57d552001-06-28 07:25:16 +00009930 if (nr < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00009931 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
Denis Vlasenkod37f2222007-08-19 13:42:08 +00009932 int flags = fcntl(0, F_GETFL);
Denis Vlasenko9cb220b2007-12-09 10:03:28 +00009933 if (flags >= 0 && (flags & O_NONBLOCK)) {
9934 flags &= ~O_NONBLOCK;
Eric Andersencb57d552001-06-28 07:25:16 +00009935 if (fcntl(0, F_SETFL, flags) >= 0) {
9936 out2str("sh: turning off NDELAY mode\n");
9937 goto retry;
9938 }
9939 }
9940 }
9941 }
Denis Vlasenkoe376d452008-02-20 22:23:24 +00009942#endif
Eric Andersencb57d552001-06-28 07:25:16 +00009943 return nr;
9944}
9945
9946/*
9947 * Refill the input buffer and return the next input character:
9948 *
9949 * 1) If a string was pushed back on the input, pop it;
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009950 * 2) If an EOF was pushed back (g_parsefile->left_in_line < -BIGNUM)
9951 * or we are reading from a string so we can't refill the buffer,
9952 * return EOF.
Denys Vlasenko883cea42009-07-11 15:31:59 +02009953 * 3) If there is more stuff in this buffer, use it else call read to fill it.
Eric Andersencb57d552001-06-28 07:25:16 +00009954 * 4) Process input up to the next newline, deleting nul characters.
9955 */
Denis Vlasenko727752d2008-11-28 03:41:47 +00009956//#define pgetc_debug(...) bb_error_msg(__VA_ARGS__)
9957#define pgetc_debug(...) ((void)0)
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02009958static int pgetc(void);
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009959static int
Eric Andersenc470f442003-07-28 09:56:35 +00009960preadbuffer(void)
Eric Andersencb57d552001-06-28 07:25:16 +00009961{
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009962 char *q;
Eric Andersencb57d552001-06-28 07:25:16 +00009963 int more;
Eric Andersencb57d552001-06-28 07:25:16 +00009964
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02009965 if (g_parsefile->strpush) {
Denis Vlasenko131ae172007-02-18 13:00:19 +00009966#if ENABLE_ASH_ALIAS
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009967 if (g_parsefile->left_in_line == -1
9968 && g_parsefile->strpush->ap
9969 && g_parsefile->next_to_pgetc[-1] != ' '
9970 && g_parsefile->next_to_pgetc[-1] != '\t'
Denis Vlasenko16898402008-11-25 01:34:52 +00009971 ) {
Denis Vlasenko727752d2008-11-28 03:41:47 +00009972 pgetc_debug("preadbuffer PEOA");
Eric Andersencb57d552001-06-28 07:25:16 +00009973 return PEOA;
9974 }
Eric Andersen2870d962001-07-02 17:27:21 +00009975#endif
Eric Andersencb57d552001-06-28 07:25:16 +00009976 popstring();
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02009977 return pgetc();
Eric Andersencb57d552001-06-28 07:25:16 +00009978 }
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009979 /* on both branches above g_parsefile->left_in_line < 0.
Denis Vlasenko727752d2008-11-28 03:41:47 +00009980 * "pgetc" needs refilling.
9981 */
9982
Denis Vlasenkoe27dafd2008-11-28 04:01:03 +00009983 /* -90 is our -BIGNUM. Below we use -99 to mark "EOF on read",
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009984 * pungetc() may increment it a few times.
Denis Vlasenkoe27dafd2008-11-28 04:01:03 +00009985 * Assuming it won't increment it to less than -90.
Denis Vlasenko727752d2008-11-28 03:41:47 +00009986 */
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009987 if (g_parsefile->left_in_line < -90 || g_parsefile->buf == NULL) {
Denis Vlasenko727752d2008-11-28 03:41:47 +00009988 pgetc_debug("preadbuffer PEOF1");
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009989 /* even in failure keep left_in_line and next_to_pgetc
9990 * in lock step, for correct multi-layer pungetc.
9991 * left_in_line was decremented before preadbuffer(),
9992 * must inc next_to_pgetc: */
9993 g_parsefile->next_to_pgetc++;
Eric Andersencb57d552001-06-28 07:25:16 +00009994 return PEOF;
Denis Vlasenko727752d2008-11-28 03:41:47 +00009995 }
Eric Andersencb57d552001-06-28 07:25:16 +00009996
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009997 more = g_parsefile->left_in_buffer;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009998 if (more <= 0) {
Denis Vlasenko727752d2008-11-28 03:41:47 +00009999 flush_stdout_stderr();
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010000 again:
10001 more = preadfd();
10002 if (more <= 0) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010003 /* don't try reading again */
10004 g_parsefile->left_in_line = -99;
Denis Vlasenko727752d2008-11-28 03:41:47 +000010005 pgetc_debug("preadbuffer PEOF2");
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010006 g_parsefile->next_to_pgetc++;
Eric Andersencb57d552001-06-28 07:25:16 +000010007 return PEOF;
10008 }
10009 }
10010
Denis Vlasenko727752d2008-11-28 03:41:47 +000010011 /* Find out where's the end of line.
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010012 * Set g_parsefile->left_in_line
10013 * and g_parsefile->left_in_buffer acordingly.
Denis Vlasenko727752d2008-11-28 03:41:47 +000010014 * NUL chars are deleted.
10015 */
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010016 q = g_parsefile->next_to_pgetc;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010017 for (;;) {
Denis Vlasenko727752d2008-11-28 03:41:47 +000010018 char c;
Eric Andersencb57d552001-06-28 07:25:16 +000010019
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010020 more--;
Eric Andersenc470f442003-07-28 09:56:35 +000010021
Denis Vlasenko727752d2008-11-28 03:41:47 +000010022 c = *q;
10023 if (c == '\0') {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010024 memmove(q, q + 1, more);
Denis Vlasenko727752d2008-11-28 03:41:47 +000010025 } else {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010026 q++;
10027 if (c == '\n') {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010028 g_parsefile->left_in_line = q - g_parsefile->next_to_pgetc - 1;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010029 break;
10030 }
Eric Andersencb57d552001-06-28 07:25:16 +000010031 }
10032
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010033 if (more <= 0) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010034 g_parsefile->left_in_line = q - g_parsefile->next_to_pgetc - 1;
10035 if (g_parsefile->left_in_line < 0)
Eric Andersencb57d552001-06-28 07:25:16 +000010036 goto again;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010037 break;
Eric Andersencb57d552001-06-28 07:25:16 +000010038 }
10039 }
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010040 g_parsefile->left_in_buffer = more;
Eric Andersencb57d552001-06-28 07:25:16 +000010041
Eric Andersencb57d552001-06-28 07:25:16 +000010042 if (vflag) {
Denis Vlasenko727752d2008-11-28 03:41:47 +000010043 char save = *q;
10044 *q = '\0';
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010045 out2str(g_parsefile->next_to_pgetc);
Denis Vlasenko727752d2008-11-28 03:41:47 +000010046 *q = save;
Eric Andersencb57d552001-06-28 07:25:16 +000010047 }
10048
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010049 pgetc_debug("preadbuffer at %d:%p'%s'",
10050 g_parsefile->left_in_line,
10051 g_parsefile->next_to_pgetc,
10052 g_parsefile->next_to_pgetc);
Denys Vlasenkocd716832009-11-28 22:14:02 +010010053 return (unsigned char)*g_parsefile->next_to_pgetc++;
Eric Andersencb57d552001-06-28 07:25:16 +000010054}
10055
Denys Vlasenkoce332a22016-10-02 23:47:34 +020010056static void
10057nlprompt(void)
10058{
10059 g_parsefile->linno++;
10060 setprompt_if(doprompt, 2);
10061}
10062static void
10063nlnoprompt(void)
10064{
10065 g_parsefile->linno++;
10066 needprompt = doprompt;
10067}
10068
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010069static int
10070pgetc(void)
10071{
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010072 int c;
10073
10074 pgetc_debug("pgetc at %d:%p'%s'",
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010075 g_parsefile->left_in_line,
10076 g_parsefile->next_to_pgetc,
10077 g_parsefile->next_to_pgetc);
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010078 if (g_parsefile->unget)
10079 return g_parsefile->lastc[--g_parsefile->unget];
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010080
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010081 if (--g_parsefile->left_in_line >= 0)
Denys Vlasenko2fe66b12016-12-12 17:39:12 +010010082 c = (unsigned char)*g_parsefile->next_to_pgetc++;
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010083 else
10084 c = preadbuffer();
10085
10086 g_parsefile->lastc[1] = g_parsefile->lastc[0];
10087 g_parsefile->lastc[0] = c;
10088
10089 return c;
10090}
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010091
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010092#if ENABLE_ASH_ALIAS
10093static int
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010010094pgetc_without_PEOA(void)
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010095{
10096 int c;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010097 do {
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010098 pgetc_debug("pgetc at %d:%p'%s'",
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010099 g_parsefile->left_in_line,
10100 g_parsefile->next_to_pgetc,
10101 g_parsefile->next_to_pgetc);
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010102 c = pgetc();
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010103 } while (c == PEOA);
10104 return c;
10105}
10106#else
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010010107# define pgetc_without_PEOA() pgetc()
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010108#endif
10109
10110/*
10111 * Read a line from the script.
10112 */
10113static char *
10114pfgets(char *line, int len)
10115{
10116 char *p = line;
10117 int nleft = len;
10118 int c;
10119
10120 while (--nleft > 0) {
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010010121 c = pgetc_without_PEOA();
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010122 if (c == PEOF) {
10123 if (p == line)
10124 return NULL;
10125 break;
10126 }
10127 *p++ = c;
10128 if (c == '\n')
10129 break;
10130 }
10131 *p = '\0';
10132 return line;
10133}
10134
Eric Andersenc470f442003-07-28 09:56:35 +000010135/*
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010136 * Undo a call to pgetc. Only two characters may be pushed back.
Eric Andersenc470f442003-07-28 09:56:35 +000010137 * PEOF may be pushed back.
10138 */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010139static void
Eric Andersenc470f442003-07-28 09:56:35 +000010140pungetc(void)
10141{
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010142 g_parsefile->unget++;
Eric Andersencb57d552001-06-28 07:25:16 +000010143}
10144
Denys Vlasenko73c3e072016-09-29 17:17:04 +020010145/* This one eats backslash+newline */
10146static int
10147pgetc_eatbnl(void)
10148{
10149 int c;
10150
10151 while ((c = pgetc()) == '\\') {
10152 if (pgetc() != '\n') {
10153 pungetc();
10154 break;
10155 }
10156
Denys Vlasenkoce332a22016-10-02 23:47:34 +020010157 nlprompt();
Denys Vlasenko73c3e072016-09-29 17:17:04 +020010158 }
10159
10160 return c;
10161}
10162
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010163/*
10164 * To handle the "." command, a stack of input files is used. Pushfile
10165 * adds a new entry to the stack and popfile restores the previous level.
10166 */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010167static void
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010168pushfile(void)
Eric Andersenc470f442003-07-28 09:56:35 +000010169{
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010170 struct parsefile *pf;
10171
Denis Vlasenko597906c2008-02-20 16:38:54 +000010172 pf = ckzalloc(sizeof(*pf));
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010173 pf->prev = g_parsefile;
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010174 pf->pf_fd = -1;
Denis Vlasenko597906c2008-02-20 16:38:54 +000010175 /*pf->strpush = NULL; - ckzalloc did it */
10176 /*pf->basestrpush.prev = NULL;*/
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010177 /*pf->unget = 0;*/
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010178 g_parsefile = pf;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010179}
10180
10181static void
10182popfile(void)
10183{
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010184 struct parsefile *pf = g_parsefile;
Eric Andersenc470f442003-07-28 09:56:35 +000010185
Denys Vlasenko493b9ca2016-10-30 18:27:14 +010010186 if (pf == &basepf)
10187 return;
10188
Denis Vlasenkob012b102007-02-19 22:43:01 +000010189 INT_OFF;
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010190 if (pf->pf_fd >= 0)
10191 close(pf->pf_fd);
Denis Vlasenko60818682007-09-28 22:07:23 +000010192 free(pf->buf);
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010193 while (pf->strpush)
10194 popstring();
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010195 g_parsefile = pf->prev;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010196 free(pf);
Denis Vlasenkob012b102007-02-19 22:43:01 +000010197 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +000010198}
10199
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010200/*
10201 * Return to top level.
10202 */
10203static void
10204popallfiles(void)
10205{
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010206 while (g_parsefile != &basepf)
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010207 popfile();
10208}
10209
10210/*
10211 * Close the file(s) that the shell is reading commands from. Called
10212 * after a fork is done.
10213 */
10214static void
10215closescript(void)
10216{
10217 popallfiles();
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010218 if (g_parsefile->pf_fd > 0) {
10219 close(g_parsefile->pf_fd);
10220 g_parsefile->pf_fd = 0;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010221 }
10222}
10223
10224/*
10225 * Like setinputfile, but takes an open file descriptor. Call this with
10226 * interrupts off.
10227 */
10228static void
10229setinputfd(int fd, int push)
10230{
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010231 if (push) {
10232 pushfile();
Denis Vlasenko727752d2008-11-28 03:41:47 +000010233 g_parsefile->buf = NULL;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010234 }
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010235 g_parsefile->pf_fd = fd;
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010236 if (g_parsefile->buf == NULL)
10237 g_parsefile->buf = ckmalloc(IBUFSIZ);
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010238 g_parsefile->left_in_buffer = 0;
10239 g_parsefile->left_in_line = 0;
10240 g_parsefile->linno = 1;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010241}
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010242
Eric Andersenc470f442003-07-28 09:56:35 +000010243/*
10244 * Set the input to take input from a file. If push is set, push the
10245 * old input onto the stack first.
10246 */
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010247static int
10248setinputfile(const char *fname, int flags)
Eric Andersenc470f442003-07-28 09:56:35 +000010249{
10250 int fd;
Eric Andersenc470f442003-07-28 09:56:35 +000010251
Denis Vlasenkob012b102007-02-19 22:43:01 +000010252 INT_OFF;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010253 fd = open(fname, O_RDONLY);
10254 if (fd < 0) {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010255 if (flags & INPUT_NOFILE_OK)
10256 goto out;
Denys Vlasenkob7adf7a2016-10-25 17:00:13 +020010257 exitstatus = 127;
Denis Vlasenko9604e1b2009-03-03 18:47:56 +000010258 ash_msg_and_raise_error("can't open '%s'", fname);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010259 }
Denys Vlasenko64774602016-10-26 15:24:30 +020010260 if (fd < 10)
10261 fd = savefd(fd);
Denys Vlasenkoe19923f2016-10-26 15:38:44 +020010262 else
10263 close_on_exec_on(fd);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010264 setinputfd(fd, flags & INPUT_PUSH_FILE);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010265 out:
Denis Vlasenkob012b102007-02-19 22:43:01 +000010266 INT_ON;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010267 return fd;
Eric Andersenc470f442003-07-28 09:56:35 +000010268}
10269
Eric Andersencb57d552001-06-28 07:25:16 +000010270/*
10271 * Like setinputfile, but takes input from a string.
10272 */
Eric Andersenc470f442003-07-28 09:56:35 +000010273static void
10274setinputstring(char *string)
Eric Andersen62483552001-07-10 06:09:16 +000010275{
Denis Vlasenkob012b102007-02-19 22:43:01 +000010276 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +000010277 pushfile();
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010278 g_parsefile->next_to_pgetc = string;
10279 g_parsefile->left_in_line = strlen(string);
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010280 g_parsefile->buf = NULL;
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010281 g_parsefile->linno = 1;
Denis Vlasenkob012b102007-02-19 22:43:01 +000010282 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +000010283}
10284
10285
Denys Vlasenko70392332016-10-27 02:31:55 +020010286/*
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010287 * Routines to check for mail.
Eric Andersencb57d552001-06-28 07:25:16 +000010288 */
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010289
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010290#if ENABLE_ASH_MAIL
Eric Andersencb57d552001-06-28 07:25:16 +000010291
Denys Vlasenko23841622015-10-09 15:52:03 +020010292/* Hash of mtimes of mailboxes */
10293static unsigned mailtime_hash;
Eric Andersenc470f442003-07-28 09:56:35 +000010294/* Set if MAIL or MAILPATH is changed. */
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010295static smallint mail_var_path_changed;
Eric Andersencb57d552001-06-28 07:25:16 +000010296
Eric Andersencb57d552001-06-28 07:25:16 +000010297/*
Eric Andersenc470f442003-07-28 09:56:35 +000010298 * Print appropriate message(s) if mail has arrived.
10299 * If mail_var_path_changed is set,
10300 * then the value of MAIL has mail_var_path_changed,
10301 * so we just update the values.
Eric Andersencb57d552001-06-28 07:25:16 +000010302 */
Eric Andersenc470f442003-07-28 09:56:35 +000010303static void
10304chkmail(void)
Eric Andersencb57d552001-06-28 07:25:16 +000010305{
Eric Andersencb57d552001-06-28 07:25:16 +000010306 const char *mpath;
10307 char *p;
10308 char *q;
Denys Vlasenko23841622015-10-09 15:52:03 +020010309 unsigned new_hash;
Eric Andersencb57d552001-06-28 07:25:16 +000010310 struct stackmark smark;
10311 struct stat statb;
10312
Eric Andersencb57d552001-06-28 07:25:16 +000010313 setstackmark(&smark);
Eric Andersenc470f442003-07-28 09:56:35 +000010314 mpath = mpathset() ? mpathval() : mailval();
Denys Vlasenko23841622015-10-09 15:52:03 +020010315 new_hash = 0;
10316 for (;;) {
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020010317 p = path_advance(&mpath, nullstr);
Eric Andersencb57d552001-06-28 07:25:16 +000010318 if (p == NULL)
10319 break;
10320 if (*p == '\0')
10321 continue;
Denis Vlasenkof7d56652008-03-25 05:51:41 +000010322 for (q = p; *q; q++)
10323 continue;
Denis Vlasenkoa7189f02006-11-17 20:29:00 +000010324#if DEBUG
Eric Andersencb57d552001-06-28 07:25:16 +000010325 if (q[-1] != '/')
10326 abort();
10327#endif
Eric Andersenc470f442003-07-28 09:56:35 +000010328 q[-1] = '\0'; /* delete trailing '/' */
10329 if (stat(p, &statb) < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +000010330 continue;
Eric Andersencb57d552001-06-28 07:25:16 +000010331 }
Denys Vlasenko23841622015-10-09 15:52:03 +020010332 /* Very simplistic "hash": just a sum of all mtimes */
10333 new_hash += (unsigned)statb.st_mtime;
10334 }
10335 if (!mail_var_path_changed && mailtime_hash != new_hash) {
Denys Vlasenko4cd99e72015-10-09 16:02:53 +020010336 if (mailtime_hash != 0)
10337 out2str("you have mail\n");
Denys Vlasenko23841622015-10-09 15:52:03 +020010338 mailtime_hash = new_hash;
Eric Andersencb57d552001-06-28 07:25:16 +000010339 }
Eric Andersenc470f442003-07-28 09:56:35 +000010340 mail_var_path_changed = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010341 popstackmark(&smark);
10342}
Eric Andersencb57d552001-06-28 07:25:16 +000010343
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010344static void FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010345changemail(const char *val UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000010346{
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010347 mail_var_path_changed = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000010348}
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010349
Denis Vlasenko131ae172007-02-18 13:00:19 +000010350#endif /* ASH_MAIL */
Eric Andersenc470f442003-07-28 09:56:35 +000010351
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010352
10353/* ============ ??? */
10354
Eric Andersencb57d552001-06-28 07:25:16 +000010355/*
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010356 * Set the shell parameters.
Eric Andersencb57d552001-06-28 07:25:16 +000010357 */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010358static void
10359setparam(char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000010360{
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010361 char **newparam;
10362 char **ap;
10363 int nparam;
Eric Andersencb57d552001-06-28 07:25:16 +000010364
Denis Vlasenkof7d56652008-03-25 05:51:41 +000010365 for (nparam = 0; argv[nparam]; nparam++)
10366 continue;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010367 ap = newparam = ckmalloc((nparam + 1) * sizeof(*ap));
10368 while (*argv) {
10369 *ap++ = ckstrdup(*argv++);
Eric Andersencb57d552001-06-28 07:25:16 +000010370 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010371 *ap = NULL;
10372 freeparam(&shellparam);
Denis Vlasenko01631112007-12-16 17:20:38 +000010373 shellparam.malloced = 1;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010374 shellparam.nparam = nparam;
10375 shellparam.p = newparam;
10376#if ENABLE_ASH_GETOPTS
10377 shellparam.optind = 1;
10378 shellparam.optoff = -1;
10379#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010380}
10381
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010382/*
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010383 * Process shell options. The global variable argptr contains a pointer
10384 * to the argument list; we advance it past the options.
Denis Vlasenko94e87bc2008-02-14 16:51:58 +000010385 *
10386 * SUSv3 section 2.8.1 "Consequences of Shell Errors" says:
10387 * For a non-interactive shell, an error condition encountered
10388 * by a special built-in ... shall cause the shell to write a diagnostic message
10389 * to standard error and exit as shown in the following table:
Denis Vlasenko56244732008-02-17 15:14:04 +000010390 * Error Special Built-In
Denis Vlasenko94e87bc2008-02-14 16:51:58 +000010391 * ...
10392 * Utility syntax error (option or operand error) Shall exit
10393 * ...
10394 * However, in bug 1142 (http://busybox.net/bugs/view.php?id=1142)
10395 * we see that bash does not do that (set "finishes" with error code 1 instead,
10396 * and shell continues), and people rely on this behavior!
10397 * Testcase:
10398 * set -o barfoo 2>/dev/null
10399 * echo $?
10400 *
10401 * Oh well. Let's mimic that.
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010402 */
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010403static int
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010404plus_minus_o(char *name, int val)
Eric Andersen62483552001-07-10 06:09:16 +000010405{
10406 int i;
10407
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010408 if (name) {
10409 for (i = 0; i < NOPTS; i++) {
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000010410 if (strcmp(name, optnames(i)) == 0) {
Eric Andersenc470f442003-07-28 09:56:35 +000010411 optlist[i] = val;
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010412 return 0;
Eric Andersen62483552001-07-10 06:09:16 +000010413 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010414 }
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010415 ash_msg("illegal option %co %s", val ? '-' : '+', name);
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010416 return 1;
Eric Andersen62483552001-07-10 06:09:16 +000010417 }
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000010418 for (i = 0; i < NOPTS; i++) {
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010419 if (val) {
10420 out1fmt("%-16s%s\n", optnames(i), optlist[i] ? "on" : "off");
10421 } else {
10422 out1fmt("set %co %s\n", optlist[i] ? '-' : '+', optnames(i));
10423 }
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000010424 }
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010425 return 0;
Eric Andersen62483552001-07-10 06:09:16 +000010426}
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010427static void
10428setoption(int flag, int val)
10429{
10430 int i;
10431
10432 for (i = 0; i < NOPTS; i++) {
10433 if (optletters(i) == flag) {
10434 optlist[i] = val;
10435 return;
10436 }
10437 }
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010438 ash_msg_and_raise_error("illegal option %c%c", val ? '-' : '+', flag);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010439 /* NOTREACHED */
10440}
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010441static int
Eric Andersenc470f442003-07-28 09:56:35 +000010442options(int cmdline)
Eric Andersencb57d552001-06-28 07:25:16 +000010443{
10444 char *p;
10445 int val;
10446 int c;
10447
10448 if (cmdline)
10449 minusc = NULL;
10450 while ((p = *argptr) != NULL) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010451 c = *p++;
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010452 if (c != '-' && c != '+')
10453 break;
10454 argptr++;
10455 val = 0; /* val = 0 if c == '+' */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010456 if (c == '-') {
Eric Andersencb57d552001-06-28 07:25:16 +000010457 val = 1;
Denis Vlasenko9f739442006-12-16 23:49:13 +000010458 if (p[0] == '\0' || LONE_DASH(p)) {
Eric Andersen2870d962001-07-02 17:27:21 +000010459 if (!cmdline) {
10460 /* "-" means turn off -x and -v */
10461 if (p[0] == '\0')
10462 xflag = vflag = 0;
10463 /* "--" means reset params */
10464 else if (*argptr == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +000010465 setparam(argptr);
Eric Andersen2870d962001-07-02 17:27:21 +000010466 }
Denys Vlasenkob0b83432011-03-07 12:34:59 +010010467 break; /* "-" or "--" terminates options */
Eric Andersencb57d552001-06-28 07:25:16 +000010468 }
Eric Andersencb57d552001-06-28 07:25:16 +000010469 }
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010470 /* first char was + or - */
Eric Andersencb57d552001-06-28 07:25:16 +000010471 while ((c = *p++) != '\0') {
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010472 /* bash 3.2 indeed handles -c CMD and +c CMD the same */
Eric Andersencb57d552001-06-28 07:25:16 +000010473 if (c == 'c' && cmdline) {
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010474 minusc = p; /* command is after shell args */
Eric Andersencb57d552001-06-28 07:25:16 +000010475 } else if (c == 'o') {
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010476 if (plus_minus_o(*argptr, val)) {
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010477 /* it already printed err message */
10478 return 1; /* error */
10479 }
Eric Andersencb57d552001-06-28 07:25:16 +000010480 if (*argptr)
10481 argptr++;
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010482 } else if (cmdline && (c == 'l')) { /* -l or +l == --login */
10483 isloginsh = 1;
10484 /* bash does not accept +-login, we also won't */
10485 } else if (cmdline && val && (c == '-')) { /* long options */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010486 if (strcmp(p, "login") == 0)
Robert Griebl64f70cc2002-05-14 23:22:06 +000010487 isloginsh = 1;
10488 break;
Eric Andersencb57d552001-06-28 07:25:16 +000010489 } else {
10490 setoption(c, val);
10491 }
10492 }
10493 }
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010494 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010495}
10496
Eric Andersencb57d552001-06-28 07:25:16 +000010497/*
Eric Andersencb57d552001-06-28 07:25:16 +000010498 * The shift builtin command.
10499 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010500static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010501shiftcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000010502{
10503 int n;
10504 char **ap1, **ap2;
10505
10506 n = 1;
Denis Vlasenko68404f12008-03-17 09:00:54 +000010507 if (argv[1])
Eric Andersencb57d552001-06-28 07:25:16 +000010508 n = number(argv[1]);
10509 if (n > shellparam.nparam)
Denis Vlasenkoc90e1be2008-07-30 15:35:05 +000010510 n = 0; /* bash compat, was = shellparam.nparam; */
Denis Vlasenkob012b102007-02-19 22:43:01 +000010511 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +000010512 shellparam.nparam -= n;
Denis Vlasenko2da584f2007-02-19 22:44:05 +000010513 for (ap1 = shellparam.p; --n >= 0; ap1++) {
Denis Vlasenko01631112007-12-16 17:20:38 +000010514 if (shellparam.malloced)
Denis Vlasenkob012b102007-02-19 22:43:01 +000010515 free(*ap1);
Eric Andersencb57d552001-06-28 07:25:16 +000010516 }
10517 ap2 = shellparam.p;
Denis Vlasenkof7d56652008-03-25 05:51:41 +000010518 while ((*ap2++ = *ap1++) != NULL)
10519 continue;
Denis Vlasenko131ae172007-02-18 13:00:19 +000010520#if ENABLE_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +000010521 shellparam.optind = 1;
10522 shellparam.optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +000010523#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +000010524 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +000010525 return 0;
10526}
10527
Eric Andersencb57d552001-06-28 07:25:16 +000010528/*
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010529 * POSIX requires that 'set' (but not export or readonly) output the
10530 * variables in lexicographic order - by the locale's collating order (sigh).
10531 * Maybe we could keep them in an ordered balanced binary tree
10532 * instead of hashed lists.
10533 * For now just roll 'em through qsort for printing...
10534 */
10535static int
10536showvars(const char *sep_prefix, int on, int off)
10537{
10538 const char *sep;
10539 char **ep, **epend;
10540
10541 ep = listvars(on, off, &epend);
10542 qsort(ep, epend - ep, sizeof(char *), vpcmp);
10543
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010544 sep = *sep_prefix ? " " : sep_prefix;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010545
10546 for (; ep < epend; ep++) {
10547 const char *p;
10548 const char *q;
10549
10550 p = strchrnul(*ep, '=');
10551 q = nullstr;
10552 if (*p)
10553 q = single_quote(++p);
10554 out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
10555 }
10556 return 0;
10557}
10558
10559/*
Eric Andersencb57d552001-06-28 07:25:16 +000010560 * The set command builtin.
10561 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010562static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010563setcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +000010564{
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010565 int retval;
10566
Denis Vlasenko68404f12008-03-17 09:00:54 +000010567 if (!argv[1])
Eric Andersenc470f442003-07-28 09:56:35 +000010568 return showvars(nullstr, 0, VUNSET);
Denys Vlasenkob0b83432011-03-07 12:34:59 +010010569
Denis Vlasenkob012b102007-02-19 22:43:01 +000010570 INT_OFF;
Denys Vlasenkob0b83432011-03-07 12:34:59 +010010571 retval = options(/*cmdline:*/ 0);
10572 if (retval == 0) { /* if no parse error... */
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010573 optschanged();
10574 if (*argptr != NULL) {
10575 setparam(argptr);
10576 }
Eric Andersencb57d552001-06-28 07:25:16 +000010577 }
Denis Vlasenkob012b102007-02-19 22:43:01 +000010578 INT_ON;
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010579 return retval;
Eric Andersencb57d552001-06-28 07:25:16 +000010580}
10581
Denis Vlasenko131ae172007-02-18 13:00:19 +000010582#if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010583static void FAST_FUNC
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000010584change_random(const char *value)
Eric Andersenef02f822004-03-11 13:34:24 +000010585{
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020010586 uint32_t t;
10587
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000010588 if (value == NULL) {
Eric Andersen16767e22004-03-16 05:14:10 +000010589 /* "get", generate */
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020010590 t = next_random(&random_gen);
Eric Andersen16767e22004-03-16 05:14:10 +000010591 /* set without recursion */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +020010592 setvar(vrandom.var_text, utoa(t), VNOFUNC);
Eric Andersen16767e22004-03-16 05:14:10 +000010593 vrandom.flags &= ~VNOFUNC;
10594 } else {
10595 /* set/reset */
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020010596 t = strtoul(value, NULL, 10);
10597 INIT_RANDOM_T(&random_gen, (t ? t : 1), t);
Eric Andersen16767e22004-03-16 05:14:10 +000010598 }
Eric Andersenef02f822004-03-11 13:34:24 +000010599}
Eric Andersen16767e22004-03-16 05:14:10 +000010600#endif
10601
Denis Vlasenko131ae172007-02-18 13:00:19 +000010602#if ENABLE_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +000010603static int
Denys Vlasenko35c2a132016-10-26 17:34:26 +020010604getopts(char *optstr, char *optvar, char **optfirst)
Eric Andersencb57d552001-06-28 07:25:16 +000010605{
10606 char *p, *q;
10607 char c = '?';
10608 int done = 0;
Denys Vlasenko9c541002015-10-07 15:44:36 +020010609 char sbuf[2];
Eric Andersena48b0a32003-10-22 10:56:47 +000010610 char **optnext;
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010611 int ind = shellparam.optind;
10612 int off = shellparam.optoff;
Eric Andersencb57d552001-06-28 07:25:16 +000010613
Denys Vlasenko9c541002015-10-07 15:44:36 +020010614 sbuf[1] = '\0';
10615
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010616 shellparam.optind = -1;
10617 optnext = optfirst + ind - 1;
Eric Andersena48b0a32003-10-22 10:56:47 +000010618
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010619 if (ind <= 1 || off < 0 || (int)strlen(optnext[-1]) < off)
Eric Andersencb57d552001-06-28 07:25:16 +000010620 p = NULL;
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010621 else
10622 p = optnext[-1] + off;
Eric Andersencb57d552001-06-28 07:25:16 +000010623 if (p == NULL || *p == '\0') {
10624 /* Current word is done, advance */
Eric Andersencb57d552001-06-28 07:25:16 +000010625 p = *optnext;
10626 if (p == NULL || *p != '-' || *++p == '\0') {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010627 atend:
Eric Andersencb57d552001-06-28 07:25:16 +000010628 p = NULL;
10629 done = 1;
10630 goto out;
10631 }
10632 optnext++;
Denis Vlasenko9f739442006-12-16 23:49:13 +000010633 if (LONE_DASH(p)) /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +000010634 goto atend;
10635 }
10636
10637 c = *p++;
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +000010638 for (q = optstr; *q != c;) {
Eric Andersencb57d552001-06-28 07:25:16 +000010639 if (*q == '\0') {
10640 if (optstr[0] == ':') {
Denys Vlasenko9c541002015-10-07 15:44:36 +020010641 sbuf[0] = c;
10642 /*sbuf[1] = '\0'; - already is */
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010643 setvar0("OPTARG", sbuf);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010644 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010645 fprintf(stderr, "Illegal option -%c\n", c);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010646 unsetvar("OPTARG");
Eric Andersencb57d552001-06-28 07:25:16 +000010647 }
10648 c = '?';
Eric Andersenc470f442003-07-28 09:56:35 +000010649 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +000010650 }
10651 if (*++q == ':')
10652 q++;
10653 }
10654
10655 if (*++q == ':') {
10656 if (*p == '\0' && (p = *optnext) == NULL) {
10657 if (optstr[0] == ':') {
Denys Vlasenko9c541002015-10-07 15:44:36 +020010658 sbuf[0] = c;
10659 /*sbuf[1] = '\0'; - already is */
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010660 setvar0("OPTARG", sbuf);
Eric Andersencb57d552001-06-28 07:25:16 +000010661 c = ':';
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010662 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010663 fprintf(stderr, "No arg for -%c option\n", c);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010664 unsetvar("OPTARG");
Eric Andersencb57d552001-06-28 07:25:16 +000010665 c = '?';
10666 }
Eric Andersenc470f442003-07-28 09:56:35 +000010667 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +000010668 }
10669
10670 if (p == *optnext)
10671 optnext++;
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010672 setvar0("OPTARG", p);
Eric Andersencb57d552001-06-28 07:25:16 +000010673 p = NULL;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010674 } else
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010675 setvar0("OPTARG", nullstr);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010676 out:
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010677 ind = optnext - optfirst + 1;
10678 setvar("OPTIND", itoa(ind), VNOFUNC);
Denys Vlasenko9c541002015-10-07 15:44:36 +020010679 sbuf[0] = c;
10680 /*sbuf[1] = '\0'; - already is */
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010681 setvar0(optvar, sbuf);
10682
10683 shellparam.optoff = p ? p - *(optnext - 1) : -1;
10684 shellparam.optind = ind;
10685
Eric Andersencb57d552001-06-28 07:25:16 +000010686 return done;
10687}
Eric Andersenc470f442003-07-28 09:56:35 +000010688
10689/*
10690 * The getopts builtin. Shellparam.optnext points to the next argument
10691 * to be processed. Shellparam.optptr points to the next character to
10692 * be processed in the current argument. If shellparam.optnext is NULL,
10693 * then it's the first time getopts has been called.
10694 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010695static int FAST_FUNC
Eric Andersenc470f442003-07-28 09:56:35 +000010696getoptscmd(int argc, char **argv)
10697{
10698 char **optbase;
10699
10700 if (argc < 3)
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +000010701 ash_msg_and_raise_error("usage: getopts optstring var [arg]");
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010702 if (argc == 3) {
Eric Andersenc470f442003-07-28 09:56:35 +000010703 optbase = shellparam.p;
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010704 if ((unsigned)shellparam.optind > shellparam.nparam + 1) {
Eric Andersenc470f442003-07-28 09:56:35 +000010705 shellparam.optind = 1;
10706 shellparam.optoff = -1;
10707 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010708 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010709 optbase = &argv[3];
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010710 if ((unsigned)shellparam.optind > argc - 2) {
Eric Andersenc470f442003-07-28 09:56:35 +000010711 shellparam.optind = 1;
10712 shellparam.optoff = -1;
10713 }
10714 }
10715
Denys Vlasenko35c2a132016-10-26 17:34:26 +020010716 return getopts(argv[1], argv[2], optbase);
Eric Andersenc470f442003-07-28 09:56:35 +000010717}
Denis Vlasenko131ae172007-02-18 13:00:19 +000010718#endif /* ASH_GETOPTS */
Eric Andersencb57d552001-06-28 07:25:16 +000010719
Eric Andersencb57d552001-06-28 07:25:16 +000010720
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010721/* ============ Shell parser */
Eric Andersencb57d552001-06-28 07:25:16 +000010722
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010723struct heredoc {
10724 struct heredoc *next; /* next here document in list */
10725 union node *here; /* redirection node */
10726 char *eofmark; /* string indicating end of input */
10727 smallint striptabs; /* if set, strip leading tabs */
10728};
10729
10730static smallint tokpushback; /* last token pushed back */
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010731static smallint quoteflag; /* set if (part of) last token was quoted */
10732static token_id_t lasttoken; /* last token read (integer id Txxx) */
10733static struct heredoc *heredoclist; /* list of here documents to read */
10734static char *wordtext; /* text of last word returned by readtoken */
10735static struct nodelist *backquotelist;
10736static union node *redirnode;
10737static struct heredoc *heredoc;
Denis Vlasenko99eb8502007-02-23 21:09:49 +000010738
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010739static const char *
10740tokname(char *buf, int tok)
10741{
10742 if (tok < TSEMI)
Denys Vlasenko888527c2016-10-02 16:54:17 +020010743 return tokname_array[tok];
10744 sprintf(buf, "\"%s\"", tokname_array[tok]);
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010745 return buf;
10746}
10747
10748/* raise_error_unexpected_syntax:
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010749 * Called when an unexpected token is read during the parse. The argument
10750 * is the token that is expected, or -1 if more than one type of token can
10751 * occur at this point.
10752 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010753static void raise_error_unexpected_syntax(int) NORETURN;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010754static void
10755raise_error_unexpected_syntax(int token)
10756{
10757 char msg[64];
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010758 char buf[16];
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010759 int l;
10760
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010761 l = sprintf(msg, "unexpected %s", tokname(buf, lasttoken));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010762 if (token >= 0)
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010763 sprintf(msg + l, " (expecting %s)", tokname(buf, token));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010764 raise_error_syntax(msg);
10765 /* NOTREACHED */
10766}
Eric Andersencb57d552001-06-28 07:25:16 +000010767
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010768#define EOFMARKLEN 79
Eric Andersencb57d552001-06-28 07:25:16 +000010769
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010770/* parsing is heavily cross-recursive, need these forward decls */
10771static union node *andor(void);
10772static union node *pipeline(void);
10773static union node *parse_command(void);
10774static void parseheredoc(void);
Ron Yorstonc0e00762015-10-29 11:30:55 +000010775static int peektoken(void);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010776static int readtoken(void);
Eric Andersencb57d552001-06-28 07:25:16 +000010777
Eric Andersenc470f442003-07-28 09:56:35 +000010778static union node *
10779list(int nlflag)
Eric Andersencb57d552001-06-28 07:25:16 +000010780{
10781 union node *n1, *n2, *n3;
10782 int tok;
10783
Eric Andersencb57d552001-06-28 07:25:16 +000010784 n1 = NULL;
10785 for (;;) {
Ron Yorstonc0e00762015-10-29 11:30:55 +000010786 switch (peektoken()) {
10787 case TNL:
10788 if (!(nlflag & 1))
10789 break;
10790 parseheredoc();
10791 return n1;
10792
10793 case TEOF:
10794 if (!n1 && (nlflag & 1))
10795 n1 = NODE_EOF;
10796 parseheredoc();
10797 return n1;
10798 }
10799
10800 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Denys Vlasenko888527c2016-10-02 16:54:17 +020010801 if (nlflag == 2 && ((1 << peektoken()) & tokendlist))
Ron Yorstonc0e00762015-10-29 11:30:55 +000010802 return n1;
10803 nlflag |= 2;
10804
Eric Andersencb57d552001-06-28 07:25:16 +000010805 n2 = andor();
10806 tok = readtoken();
10807 if (tok == TBACKGND) {
Eric Andersenc470f442003-07-28 09:56:35 +000010808 if (n2->type == NPIPE) {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +000010809 n2->npipe.pipe_backgnd = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010810 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010811 if (n2->type != NREDIR) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000010812 n3 = stzalloc(sizeof(struct nredir));
Eric Andersenc470f442003-07-28 09:56:35 +000010813 n3->nredir.n = n2;
Denis Vlasenko597906c2008-02-20 16:38:54 +000010814 /*n3->nredir.redirect = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000010815 n2 = n3;
10816 }
10817 n2->type = NBACKGND;
Eric Andersencb57d552001-06-28 07:25:16 +000010818 }
10819 }
10820 if (n1 == NULL) {
10821 n1 = n2;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010822 } else {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010823 n3 = stzalloc(sizeof(struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +000010824 n3->type = NSEMI;
10825 n3->nbinary.ch1 = n1;
10826 n3->nbinary.ch2 = n2;
10827 n1 = n3;
10828 }
10829 switch (tok) {
Ron Yorstonc0e00762015-10-29 11:30:55 +000010830 case TNL:
10831 case TEOF:
10832 tokpushback = 1;
10833 /* fall through */
Eric Andersencb57d552001-06-28 07:25:16 +000010834 case TBACKGND:
10835 case TSEMI:
Eric Andersencb57d552001-06-28 07:25:16 +000010836 break;
Eric Andersencb57d552001-06-28 07:25:16 +000010837 default:
Ron Yorstonc0e00762015-10-29 11:30:55 +000010838 if ((nlflag & 1))
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010839 raise_error_unexpected_syntax(-1);
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010840 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010841 return n1;
10842 }
10843 }
10844}
10845
Eric Andersenc470f442003-07-28 09:56:35 +000010846static union node *
10847andor(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010848{
Eric Andersencb57d552001-06-28 07:25:16 +000010849 union node *n1, *n2, *n3;
10850 int t;
10851
Eric Andersencb57d552001-06-28 07:25:16 +000010852 n1 = pipeline();
10853 for (;;) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010854 t = readtoken();
10855 if (t == TAND) {
Eric Andersencb57d552001-06-28 07:25:16 +000010856 t = NAND;
10857 } else if (t == TOR) {
10858 t = NOR;
10859 } else {
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010860 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010861 return n1;
10862 }
Eric Andersenc470f442003-07-28 09:56:35 +000010863 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000010864 n2 = pipeline();
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010865 n3 = stzalloc(sizeof(struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +000010866 n3->type = t;
10867 n3->nbinary.ch1 = n1;
10868 n3->nbinary.ch2 = n2;
10869 n1 = n3;
10870 }
10871}
10872
Eric Andersenc470f442003-07-28 09:56:35 +000010873static union node *
10874pipeline(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010875{
Eric Andersencb57d552001-06-28 07:25:16 +000010876 union node *n1, *n2, *pipenode;
10877 struct nodelist *lp, *prev;
10878 int negate;
10879
10880 negate = 0;
10881 TRACE(("pipeline: entered\n"));
10882 if (readtoken() == TNOT) {
10883 negate = !negate;
Eric Andersenc470f442003-07-28 09:56:35 +000010884 checkkwd = CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000010885 } else
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010886 tokpushback = 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010887 n1 = parse_command();
Eric Andersencb57d552001-06-28 07:25:16 +000010888 if (readtoken() == TPIPE) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000010889 pipenode = stzalloc(sizeof(struct npipe));
Eric Andersencb57d552001-06-28 07:25:16 +000010890 pipenode->type = NPIPE;
Denis Vlasenko2dc240c2008-07-24 06:07:50 +000010891 /*pipenode->npipe.pipe_backgnd = 0; - stzalloc did it */
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010892 lp = stzalloc(sizeof(struct nodelist));
Eric Andersencb57d552001-06-28 07:25:16 +000010893 pipenode->npipe.cmdlist = lp;
10894 lp->n = n1;
10895 do {
10896 prev = lp;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010897 lp = stzalloc(sizeof(struct nodelist));
Eric Andersenc470f442003-07-28 09:56:35 +000010898 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010899 lp->n = parse_command();
Eric Andersencb57d552001-06-28 07:25:16 +000010900 prev->next = lp;
10901 } while (readtoken() == TPIPE);
10902 lp->next = NULL;
10903 n1 = pipenode;
10904 }
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010905 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010906 if (negate) {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010907 n2 = stzalloc(sizeof(struct nnot));
Eric Andersencb57d552001-06-28 07:25:16 +000010908 n2->type = NNOT;
10909 n2->nnot.com = n1;
10910 return n2;
Denis Vlasenko2da584f2007-02-19 22:44:05 +000010911 }
10912 return n1;
Eric Andersencb57d552001-06-28 07:25:16 +000010913}
10914
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010915static union node *
10916makename(void)
10917{
10918 union node *n;
10919
Denis Vlasenko597906c2008-02-20 16:38:54 +000010920 n = stzalloc(sizeof(struct narg));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010921 n->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000010922 /*n->narg.next = NULL; - stzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010923 n->narg.text = wordtext;
10924 n->narg.backquote = backquotelist;
10925 return n;
10926}
10927
10928static void
10929fixredir(union node *n, const char *text, int err)
10930{
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000010931 int fd;
10932
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010933 TRACE(("Fix redir %s %d\n", text, err));
10934 if (!err)
10935 n->ndup.vname = NULL;
10936
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000010937 fd = bb_strtou(text, NULL, 10);
10938 if (!errno && fd >= 0)
10939 n->ndup.dupfd = fd;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010940 else if (LONE_DASH(text))
10941 n->ndup.dupfd = -1;
10942 else {
10943 if (err)
Denis Vlasenko559691a2008-10-05 18:39:31 +000010944 raise_error_syntax("bad fd number");
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010945 n->ndup.vname = makename();
10946 }
10947}
10948
10949/*
10950 * Returns true if the text contains nothing to expand (no dollar signs
10951 * or backquotes).
10952 */
10953static int
Denis Vlasenko68819d12008-12-15 11:26:36 +000010954noexpand(const char *text)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010955{
Denys Vlasenkocd716832009-11-28 22:14:02 +010010956 unsigned char c;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010957
Denys Vlasenkocd716832009-11-28 22:14:02 +010010958 while ((c = *text++) != '\0') {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010959 if (c == CTLQUOTEMARK)
10960 continue;
10961 if (c == CTLESC)
Denys Vlasenkocd716832009-11-28 22:14:02 +010010962 text++;
Denys Vlasenko76bc2d62009-11-29 01:37:46 +010010963 else if (SIT(c, BASESYNTAX) == CCTL)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010964 return 0;
10965 }
10966 return 1;
10967}
10968
10969static void
10970parsefname(void)
10971{
10972 union node *n = redirnode;
10973
10974 if (readtoken() != TWORD)
10975 raise_error_unexpected_syntax(-1);
10976 if (n->type == NHERE) {
10977 struct heredoc *here = heredoc;
10978 struct heredoc *p;
10979 int i;
10980
10981 if (quoteflag == 0)
10982 n->type = NXHERE;
10983 TRACE(("Here document %d\n", n->type));
10984 if (!noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
Denis Vlasenko559691a2008-10-05 18:39:31 +000010985 raise_error_syntax("illegal eof marker for << redirection");
Denys Vlasenkob6c84342009-08-29 20:23:20 +020010986 rmescapes(wordtext, 0);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010987 here->eofmark = wordtext;
10988 here->next = NULL;
10989 if (heredoclist == NULL)
10990 heredoclist = here;
10991 else {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010992 for (p = heredoclist; p->next; p = p->next)
10993 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010994 p->next = here;
10995 }
10996 } else if (n->type == NTOFD || n->type == NFROMFD) {
10997 fixredir(n, wordtext, 0);
10998 } else {
10999 n->nfile.fname = makename();
11000 }
11001}
Eric Andersencb57d552001-06-28 07:25:16 +000011002
Eric Andersenc470f442003-07-28 09:56:35 +000011003static union node *
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011004simplecmd(void)
11005{
11006 union node *args, **app;
11007 union node *n = NULL;
11008 union node *vars, **vpp;
11009 union node **rpp, *redir;
11010 int savecheckkwd;
Denis Vlasenko80591b02008-03-25 07:49:43 +000011011#if ENABLE_ASH_BASH_COMPAT
11012 smallint double_brackets_flag = 0;
Ron Yorston95ebcf72015-11-03 09:42:23 +000011013 smallint function_flag = 0;
Denis Vlasenko80591b02008-03-25 07:49:43 +000011014#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011015
11016 args = NULL;
11017 app = &args;
11018 vars = NULL;
11019 vpp = &vars;
11020 redir = NULL;
11021 rpp = &redir;
11022
11023 savecheckkwd = CHKALIAS;
11024 for (;;) {
Denis Vlasenko80591b02008-03-25 07:49:43 +000011025 int t;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011026 checkkwd = savecheckkwd;
Denis Vlasenko80591b02008-03-25 07:49:43 +000011027 t = readtoken();
11028 switch (t) {
11029#if ENABLE_ASH_BASH_COMPAT
Ron Yorston95ebcf72015-11-03 09:42:23 +000011030 case TFUNCTION:
11031 if (peektoken() != TWORD)
11032 raise_error_unexpected_syntax(TWORD);
11033 function_flag = 1;
11034 break;
Denis Vlasenko80591b02008-03-25 07:49:43 +000011035 case TAND: /* "&&" */
11036 case TOR: /* "||" */
11037 if (!double_brackets_flag) {
11038 tokpushback = 1;
11039 goto out;
11040 }
11041 wordtext = (char *) (t == TAND ? "-a" : "-o");
11042#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011043 case TWORD:
Denis Vlasenko597906c2008-02-20 16:38:54 +000011044 n = stzalloc(sizeof(struct narg));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011045 n->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011046 /*n->narg.next = NULL; - stzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011047 n->narg.text = wordtext;
Denis Vlasenko80591b02008-03-25 07:49:43 +000011048#if ENABLE_ASH_BASH_COMPAT
11049 if (strcmp("[[", wordtext) == 0)
11050 double_brackets_flag = 1;
11051 else if (strcmp("]]", wordtext) == 0)
11052 double_brackets_flag = 0;
11053#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011054 n->narg.backquote = backquotelist;
11055 if (savecheckkwd && isassignment(wordtext)) {
11056 *vpp = n;
11057 vpp = &n->narg.next;
11058 } else {
11059 *app = n;
11060 app = &n->narg.next;
11061 savecheckkwd = 0;
11062 }
Ron Yorston95ebcf72015-11-03 09:42:23 +000011063#if ENABLE_ASH_BASH_COMPAT
11064 if (function_flag) {
11065 checkkwd = CHKNL | CHKKWD;
11066 switch (peektoken()) {
11067 case TBEGIN:
11068 case TIF:
11069 case TCASE:
11070 case TUNTIL:
11071 case TWHILE:
11072 case TFOR:
11073 goto do_func;
11074 case TLP:
11075 function_flag = 0;
11076 break;
11077 case TWORD:
11078 if (strcmp("[[", wordtext) == 0)
11079 goto do_func;
11080 /* fall through */
11081 default:
11082 raise_error_unexpected_syntax(-1);
11083 }
11084 }
11085#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011086 break;
11087 case TREDIR:
11088 *rpp = n = redirnode;
11089 rpp = &n->nfile.next;
11090 parsefname(); /* read name of redirection file */
11091 break;
11092 case TLP:
Ron Yorston95ebcf72015-11-03 09:42:23 +000011093 IF_ASH_BASH_COMPAT(do_func:)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011094 if (args && app == &args->narg.next
11095 && !vars && !redir
11096 ) {
11097 struct builtincmd *bcmd;
11098 const char *name;
11099
11100 /* We have a function */
Ron Yorston95ebcf72015-11-03 09:42:23 +000011101 if (IF_ASH_BASH_COMPAT(!function_flag &&) readtoken() != TRP)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011102 raise_error_unexpected_syntax(TRP);
11103 name = n->narg.text;
11104 if (!goodname(name)
11105 || ((bcmd = find_builtin(name)) && IS_BUILTIN_SPECIAL(bcmd))
11106 ) {
Denis Vlasenko559691a2008-10-05 18:39:31 +000011107 raise_error_syntax("bad function name");
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011108 }
11109 n->type = NDEFUN;
11110 checkkwd = CHKNL | CHKKWD | CHKALIAS;
11111 n->narg.next = parse_command();
11112 return n;
11113 }
Ron Yorston95ebcf72015-11-03 09:42:23 +000011114 IF_ASH_BASH_COMPAT(function_flag = 0;)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011115 /* fall through */
11116 default:
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011117 tokpushback = 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011118 goto out;
11119 }
11120 }
11121 out:
11122 *app = NULL;
11123 *vpp = NULL;
11124 *rpp = NULL;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011125 n = stzalloc(sizeof(struct ncmd));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011126 n->type = NCMD;
11127 n->ncmd.args = args;
11128 n->ncmd.assign = vars;
11129 n->ncmd.redirect = redir;
11130 return n;
11131}
11132
11133static union node *
11134parse_command(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011135{
Eric Andersencb57d552001-06-28 07:25:16 +000011136 union node *n1, *n2;
11137 union node *ap, **app;
11138 union node *cp, **cpp;
11139 union node *redir, **rpp;
Eric Andersenc470f442003-07-28 09:56:35 +000011140 union node **rpp2;
Eric Andersencb57d552001-06-28 07:25:16 +000011141 int t;
11142
11143 redir = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +000011144 rpp2 = &redir;
Eric Andersen88cec252001-09-06 17:35:20 +000011145
Eric Andersencb57d552001-06-28 07:25:16 +000011146 switch (readtoken()) {
Eric Andersenc470f442003-07-28 09:56:35 +000011147 default:
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011148 raise_error_unexpected_syntax(-1);
Eric Andersenc470f442003-07-28 09:56:35 +000011149 /* NOTREACHED */
Eric Andersencb57d552001-06-28 07:25:16 +000011150 case TIF:
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011151 n1 = stzalloc(sizeof(struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +000011152 n1->type = NIF;
11153 n1->nif.test = list(0);
11154 if (readtoken() != TTHEN)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011155 raise_error_unexpected_syntax(TTHEN);
Eric Andersencb57d552001-06-28 07:25:16 +000011156 n1->nif.ifpart = list(0);
11157 n2 = n1;
11158 while (readtoken() == TELIF) {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011159 n2->nif.elsepart = stzalloc(sizeof(struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +000011160 n2 = n2->nif.elsepart;
11161 n2->type = NIF;
11162 n2->nif.test = list(0);
11163 if (readtoken() != TTHEN)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011164 raise_error_unexpected_syntax(TTHEN);
Eric Andersencb57d552001-06-28 07:25:16 +000011165 n2->nif.ifpart = list(0);
11166 }
11167 if (lasttoken == TELSE)
11168 n2->nif.elsepart = list(0);
11169 else {
11170 n2->nif.elsepart = NULL;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011171 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011172 }
Eric Andersenc470f442003-07-28 09:56:35 +000011173 t = TFI;
Eric Andersencb57d552001-06-28 07:25:16 +000011174 break;
11175 case TWHILE:
Eric Andersenc470f442003-07-28 09:56:35 +000011176 case TUNTIL: {
Eric Andersencb57d552001-06-28 07:25:16 +000011177 int got;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011178 n1 = stzalloc(sizeof(struct nbinary));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011179 n1->type = (lasttoken == TWHILE) ? NWHILE : NUNTIL;
Eric Andersencb57d552001-06-28 07:25:16 +000011180 n1->nbinary.ch1 = list(0);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011181 got = readtoken();
11182 if (got != TDO) {
Denys Vlasenko888527c2016-10-02 16:54:17 +020011183 TRACE(("expecting DO got '%s' %s\n", tokname_array[got],
Denis Vlasenko131ae172007-02-18 13:00:19 +000011184 got == TWORD ? wordtext : ""));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011185 raise_error_unexpected_syntax(TDO);
Eric Andersencb57d552001-06-28 07:25:16 +000011186 }
11187 n1->nbinary.ch2 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +000011188 t = TDONE;
Eric Andersencb57d552001-06-28 07:25:16 +000011189 break;
11190 }
11191 case TFOR:
Denis Vlasenko2dc240c2008-07-24 06:07:50 +000011192 if (readtoken() != TWORD || quoteflag || !goodname(wordtext))
Denis Vlasenko559691a2008-10-05 18:39:31 +000011193 raise_error_syntax("bad for loop variable");
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011194 n1 = stzalloc(sizeof(struct nfor));
Eric Andersencb57d552001-06-28 07:25:16 +000011195 n1->type = NFOR;
11196 n1->nfor.var = wordtext;
Ron Yorstonab80e012015-08-03 13:46:00 +010011197 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000011198 if (readtoken() == TIN) {
11199 app = &ap;
11200 while (readtoken() == TWORD) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011201 n2 = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000011202 n2->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011203 /*n2->narg.next = NULL; - stzalloc did it */
Eric Andersencb57d552001-06-28 07:25:16 +000011204 n2->narg.text = wordtext;
11205 n2->narg.backquote = backquotelist;
11206 *app = n2;
11207 app = &n2->narg.next;
11208 }
11209 *app = NULL;
11210 n1->nfor.args = ap;
11211 if (lasttoken != TNL && lasttoken != TSEMI)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011212 raise_error_unexpected_syntax(-1);
Eric Andersencb57d552001-06-28 07:25:16 +000011213 } else {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011214 n2 = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000011215 n2->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011216 /*n2->narg.next = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011217 n2->narg.text = (char *)dolatstr;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011218 /*n2->narg.backquote = NULL;*/
Eric Andersencb57d552001-06-28 07:25:16 +000011219 n1->nfor.args = n2;
11220 /*
11221 * Newline or semicolon here is optional (but note
11222 * that the original Bourne shell only allowed NL).
11223 */
Ron Yorstonab80e012015-08-03 13:46:00 +010011224 if (lasttoken != TSEMI)
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011225 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011226 }
Eric Andersenc470f442003-07-28 09:56:35 +000011227 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000011228 if (readtoken() != TDO)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011229 raise_error_unexpected_syntax(TDO);
Eric Andersencb57d552001-06-28 07:25:16 +000011230 n1->nfor.body = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +000011231 t = TDONE;
Eric Andersencb57d552001-06-28 07:25:16 +000011232 break;
11233 case TCASE:
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011234 n1 = stzalloc(sizeof(struct ncase));
Eric Andersencb57d552001-06-28 07:25:16 +000011235 n1->type = NCASE;
11236 if (readtoken() != TWORD)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011237 raise_error_unexpected_syntax(TWORD);
Denis Vlasenko597906c2008-02-20 16:38:54 +000011238 n1->ncase.expr = n2 = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000011239 n2->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011240 /*n2->narg.next = NULL; - stzalloc did it */
Eric Andersencb57d552001-06-28 07:25:16 +000011241 n2->narg.text = wordtext;
11242 n2->narg.backquote = backquotelist;
Ron Yorston383b8852015-08-03 13:46:25 +010011243 checkkwd = CHKNL | CHKKWD | CHKALIAS;
11244 if (readtoken() != TIN)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011245 raise_error_unexpected_syntax(TIN);
Eric Andersencb57d552001-06-28 07:25:16 +000011246 cpp = &n1->ncase.cases;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011247 next_case:
Eric Andersenc470f442003-07-28 09:56:35 +000011248 checkkwd = CHKNL | CHKKWD;
11249 t = readtoken();
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011250 while (t != TESAC) {
Eric Andersencb57d552001-06-28 07:25:16 +000011251 if (lasttoken == TLP)
11252 readtoken();
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011253 *cpp = cp = stzalloc(sizeof(struct nclist));
Eric Andersencb57d552001-06-28 07:25:16 +000011254 cp->type = NCLIST;
11255 app = &cp->nclist.pattern;
11256 for (;;) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011257 *app = ap = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000011258 ap->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011259 /*ap->narg.next = NULL; - stzalloc did it */
Eric Andersencb57d552001-06-28 07:25:16 +000011260 ap->narg.text = wordtext;
11261 ap->narg.backquote = backquotelist;
Eric Andersenc470f442003-07-28 09:56:35 +000011262 if (readtoken() != TPIPE)
Eric Andersencb57d552001-06-28 07:25:16 +000011263 break;
11264 app = &ap->narg.next;
11265 readtoken();
11266 }
Denis Vlasenko597906c2008-02-20 16:38:54 +000011267 //ap->narg.next = NULL;
Eric Andersencb57d552001-06-28 07:25:16 +000011268 if (lasttoken != TRP)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011269 raise_error_unexpected_syntax(TRP);
Eric Andersenc470f442003-07-28 09:56:35 +000011270 cp->nclist.body = list(2);
Eric Andersencb57d552001-06-28 07:25:16 +000011271
Eric Andersenc470f442003-07-28 09:56:35 +000011272 cpp = &cp->nclist.next;
11273
11274 checkkwd = CHKNL | CHKKWD;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011275 t = readtoken();
11276 if (t != TESAC) {
Eric Andersencb57d552001-06-28 07:25:16 +000011277 if (t != TENDCASE)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011278 raise_error_unexpected_syntax(TENDCASE);
11279 goto next_case;
Eric Andersencb57d552001-06-28 07:25:16 +000011280 }
Eric Andersenc470f442003-07-28 09:56:35 +000011281 }
Eric Andersencb57d552001-06-28 07:25:16 +000011282 *cpp = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +000011283 goto redir;
Eric Andersencb57d552001-06-28 07:25:16 +000011284 case TLP:
Denis Vlasenko597906c2008-02-20 16:38:54 +000011285 n1 = stzalloc(sizeof(struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +000011286 n1->type = NSUBSHELL;
11287 n1->nredir.n = list(0);
Denis Vlasenko597906c2008-02-20 16:38:54 +000011288 /*n1->nredir.redirect = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011289 t = TRP;
Eric Andersencb57d552001-06-28 07:25:16 +000011290 break;
11291 case TBEGIN:
11292 n1 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +000011293 t = TEND;
Eric Andersencb57d552001-06-28 07:25:16 +000011294 break;
Ron Yorston95ebcf72015-11-03 09:42:23 +000011295 IF_ASH_BASH_COMPAT(case TFUNCTION:)
Eric Andersencb57d552001-06-28 07:25:16 +000011296 case TWORD:
Eric Andersenc470f442003-07-28 09:56:35 +000011297 case TREDIR:
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011298 tokpushback = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000011299 return simplecmd();
Eric Andersencb57d552001-06-28 07:25:16 +000011300 }
11301
Eric Andersenc470f442003-07-28 09:56:35 +000011302 if (readtoken() != t)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011303 raise_error_unexpected_syntax(t);
Eric Andersenc470f442003-07-28 09:56:35 +000011304
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011305 redir:
Eric Andersencb57d552001-06-28 07:25:16 +000011306 /* Now check for redirection which may follow command */
Eric Andersenc470f442003-07-28 09:56:35 +000011307 checkkwd = CHKKWD | CHKALIAS;
11308 rpp = rpp2;
Eric Andersencb57d552001-06-28 07:25:16 +000011309 while (readtoken() == TREDIR) {
11310 *rpp = n2 = redirnode;
11311 rpp = &n2->nfile.next;
11312 parsefname();
11313 }
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011314 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011315 *rpp = NULL;
11316 if (redir) {
11317 if (n1->type != NSUBSHELL) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011318 n2 = stzalloc(sizeof(struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +000011319 n2->type = NREDIR;
11320 n2->nredir.n = n1;
11321 n1 = n2;
11322 }
11323 n1->nredir.redirect = redir;
11324 }
Eric Andersencb57d552001-06-28 07:25:16 +000011325 return n1;
11326}
11327
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011328#if ENABLE_ASH_BASH_COMPAT
Denys Vlasenko37dc08b2016-10-02 04:38:07 +020011329static int
11330decode_dollar_squote(void)
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011331{
11332 static const char C_escapes[] ALIGN1 = "nrbtfav""x\\01234567";
11333 int c, cnt;
11334 char *p;
11335 char buf[4];
11336
11337 c = pgetc();
11338 p = strchr(C_escapes, c);
11339 if (p) {
11340 buf[0] = c;
11341 p = buf;
11342 cnt = 3;
11343 if ((unsigned char)(c - '0') <= 7) { /* \ooo */
11344 do {
11345 c = pgetc();
11346 *++p = c;
11347 } while ((unsigned char)(c - '0') <= 7 && --cnt);
11348 pungetc();
11349 } else if (c == 'x') { /* \xHH */
11350 do {
11351 c = pgetc();
11352 *++p = c;
11353 } while (isxdigit(c) && --cnt);
11354 pungetc();
11355 if (cnt == 3) { /* \x but next char is "bad" */
11356 c = 'x';
11357 goto unrecognized;
11358 }
11359 } else { /* simple seq like \\ or \t */
11360 p++;
11361 }
11362 *p = '\0';
11363 p = buf;
11364 c = bb_process_escape_sequence((void*)&p);
11365 } else { /* unrecognized "\z": print both chars unless ' or " */
11366 if (c != '\'' && c != '"') {
11367 unrecognized:
11368 c |= 0x100; /* "please encode \, then me" */
11369 }
11370 }
11371 return c;
11372}
11373#endif
11374
Eric Andersencb57d552001-06-28 07:25:16 +000011375/*
11376 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
11377 * is not NULL, read a here document. In the latter case, eofmark is the
11378 * word which marks the end of the document and striptabs is true if
Denys Vlasenkocd716832009-11-28 22:14:02 +010011379 * leading tabs should be stripped from the document. The argument c
Eric Andersencb57d552001-06-28 07:25:16 +000011380 * is the first character of the input token or document.
11381 *
11382 * Because C does not have internal subroutines, I have simulated them
11383 * using goto's to implement the subroutine linkage. The following macros
11384 * will run code that appears at the end of readtoken1.
11385 */
Eric Andersen2870d962001-07-02 17:27:21 +000011386#define CHECKEND() {goto checkend; checkend_return:;}
11387#define PARSEREDIR() {goto parseredir; parseredir_return:;}
11388#define PARSESUB() {goto parsesub; parsesub_return:;}
11389#define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
11390#define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
11391#define PARSEARITH() {goto parsearith; parsearith_return:;}
Eric Andersencb57d552001-06-28 07:25:16 +000011392static int
Denys Vlasenkocd716832009-11-28 22:14:02 +010011393readtoken1(int c, int syntax, char *eofmark, int striptabs)
Manuel Novoa III 16815d42001-08-10 19:36:07 +000011394{
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011395 /* NB: syntax parameter fits into smallint */
Denys Vlasenkocd716832009-11-28 22:14:02 +010011396 /* c parameter is an unsigned char or PEOF or PEOA */
Eric Andersencb57d552001-06-28 07:25:16 +000011397 char *out;
Denys Vlasenko50e6d422016-09-30 11:35:54 +020011398 size_t len;
Eric Andersencb57d552001-06-28 07:25:16 +000011399 char line[EOFMARKLEN + 1];
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011400 struct nodelist *bqlist;
11401 smallint quotef;
11402 smallint dblquote;
11403 smallint oldstyle;
Denys Vlasenko0b883582016-12-23 16:49:07 +010011404 IF_FEATURE_SH_MATH(smallint prevsyntax;) /* syntax before arithmetic */
Denis Vlasenko46a53062007-09-24 18:30:02 +000011405#if ENABLE_ASH_EXPAND_PRMT
11406 smallint pssyntax; /* we are expanding a prompt string */
11407#endif
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011408 int varnest; /* levels of variables expansion */
Denys Vlasenko0b883582016-12-23 16:49:07 +010011409 IF_FEATURE_SH_MATH(int arinest;) /* levels of arithmetic expansion */
11410 IF_FEATURE_SH_MATH(int parenlevel;) /* levels of parens in arithmetic */
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011411 int dqvarnest; /* levels of variables expansion within double quotes */
11412
Denis Vlasenko5e34ff22009-04-21 11:09:40 +000011413 IF_ASH_BASH_COMPAT(smallint bash_dollar_squote = 0;)
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011414
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011415 startlinno = g_parsefile->linno;
Eric Andersencb57d552001-06-28 07:25:16 +000011416 bqlist = NULL;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011417 quotef = 0;
Denys Vlasenko0b883582016-12-23 16:49:07 +010011418 IF_FEATURE_SH_MATH(prevsyntax = 0;)
Denis Vlasenko46a53062007-09-24 18:30:02 +000011419#if ENABLE_ASH_EXPAND_PRMT
11420 pssyntax = (syntax == PSSYNTAX);
11421 if (pssyntax)
11422 syntax = DQSYNTAX;
11423#endif
11424 dblquote = (syntax == DQSYNTAX);
Eric Andersencb57d552001-06-28 07:25:16 +000011425 varnest = 0;
Denys Vlasenko0b883582016-12-23 16:49:07 +010011426 IF_FEATURE_SH_MATH(arinest = 0;)
11427 IF_FEATURE_SH_MATH(parenlevel = 0;)
Eric Andersencb57d552001-06-28 07:25:16 +000011428 dqvarnest = 0;
11429
11430 STARTSTACKSTR(out);
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011431 loop:
11432 /* For each line, until end of word */
Denys Vlasenko958581a2010-09-12 15:04:27 +020011433 CHECKEND(); /* set c to PEOF if at end of here document */
11434 for (;;) { /* until end of line or end of word */
11435 CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */
11436 switch (SIT(c, syntax)) {
11437 case CNL: /* '\n' */
11438 if (syntax == BASESYNTAX)
11439 goto endword; /* exit outer loop */
11440 USTPUTC(c, out);
Denys Vlasenkoce332a22016-10-02 23:47:34 +020011441 nlprompt();
Denys Vlasenko958581a2010-09-12 15:04:27 +020011442 c = pgetc();
11443 goto loop; /* continue outer loop */
11444 case CWORD:
11445 USTPUTC(c, out);
11446 break;
11447 case CCTL:
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011448#if ENABLE_ASH_BASH_COMPAT
Denys Vlasenko958581a2010-09-12 15:04:27 +020011449 if (c == '\\' && bash_dollar_squote) {
11450 c = decode_dollar_squote();
Denys Vlasenko13f20912016-09-25 20:54:25 +020011451 if (c == '\0') {
11452 /* skip $'\000', $'\x00' (like bash) */
11453 break;
11454 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020011455 if (c & 0x100) {
Denys Vlasenko13f20912016-09-25 20:54:25 +020011456 /* Unknown escape. Encode as '\z' */
Denys Vlasenko958581a2010-09-12 15:04:27 +020011457 c = (unsigned char)c;
Denys Vlasenko13f20912016-09-25 20:54:25 +020011458 if (eofmark == NULL || dblquote)
11459 USTPUTC(CTLESC, out);
11460 USTPUTC('\\', out);
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011461 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020011462 }
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011463#endif
Denys Vlasenko13f20912016-09-25 20:54:25 +020011464 if (eofmark == NULL || dblquote)
11465 USTPUTC(CTLESC, out);
Denys Vlasenko958581a2010-09-12 15:04:27 +020011466 USTPUTC(c, out);
11467 break;
11468 case CBACK: /* backslash */
11469 c = pgetc_without_PEOA();
11470 if (c == PEOF) {
11471 USTPUTC(CTLESC, out);
11472 USTPUTC('\\', out);
11473 pungetc();
11474 } else if (c == '\n') {
Denys Vlasenkoce332a22016-10-02 23:47:34 +020011475 nlprompt();
Denys Vlasenko958581a2010-09-12 15:04:27 +020011476 } else {
11477#if ENABLE_ASH_EXPAND_PRMT
11478 if (c == '$' && pssyntax) {
Eric Andersenc470f442003-07-28 09:56:35 +000011479 USTPUTC(CTLESC, out);
Eric Andersencb57d552001-06-28 07:25:16 +000011480 USTPUTC('\\', out);
Denys Vlasenko958581a2010-09-12 15:04:27 +020011481 }
Denis Vlasenko46a53062007-09-24 18:30:02 +000011482#endif
Denys Vlasenko958581a2010-09-12 15:04:27 +020011483 /* Backslash is retained if we are in "str" and next char isn't special */
11484 if (dblquote
11485 && c != '\\'
11486 && c != '`'
11487 && c != '$'
11488 && (c != '"' || eofmark != NULL)
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011489 ) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020011490 USTPUTC('\\', out);
Eric Andersencb57d552001-06-28 07:25:16 +000011491 }
Ron Yorston549deab2015-05-18 09:57:51 +020011492 USTPUTC(CTLESC, out);
Denys Vlasenko0ff78a02010-08-30 15:20:07 +020011493 USTPUTC(c, out);
Denys Vlasenko958581a2010-09-12 15:04:27 +020011494 quotef = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011495 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020011496 break;
11497 case CSQUOTE:
11498 syntax = SQSYNTAX;
11499 quotemark:
11500 if (eofmark == NULL) {
11501 USTPUTC(CTLQUOTEMARK, out);
11502 }
11503 break;
11504 case CDQUOTE:
11505 syntax = DQSYNTAX;
11506 dblquote = 1;
11507 goto quotemark;
11508 case CENDQUOTE:
11509 IF_ASH_BASH_COMPAT(bash_dollar_squote = 0;)
Ron Yorston7e4ed262015-05-18 09:54:43 +020011510 if (eofmark != NULL && varnest == 0) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020011511 USTPUTC(c, out);
11512 } else {
11513 if (dqvarnest == 0) {
11514 syntax = BASESYNTAX;
11515 dblquote = 0;
11516 }
11517 quotef = 1;
11518 goto quotemark;
11519 }
11520 break;
11521 case CVAR: /* '$' */
11522 PARSESUB(); /* parse substitution */
11523 break;
11524 case CENDVAR: /* '}' */
11525 if (varnest > 0) {
11526 varnest--;
11527 if (dqvarnest > 0) {
11528 dqvarnest--;
11529 }
11530 c = CTLENDVAR;
11531 }
11532 USTPUTC(c, out);
11533 break;
Denys Vlasenko0b883582016-12-23 16:49:07 +010011534#if ENABLE_FEATURE_SH_MATH
Denys Vlasenko958581a2010-09-12 15:04:27 +020011535 case CLP: /* '(' in arithmetic */
11536 parenlevel++;
11537 USTPUTC(c, out);
11538 break;
11539 case CRP: /* ')' in arithmetic */
11540 if (parenlevel > 0) {
11541 parenlevel--;
11542 } else {
Denys Vlasenko459293b2016-09-29 17:58:58 +020011543 if (pgetc_eatbnl() == ')') {
Ron Yorstonad88bde2015-05-18 09:56:16 +020011544 c = CTLENDARI;
Denys Vlasenko958581a2010-09-12 15:04:27 +020011545 if (--arinest == 0) {
11546 syntax = prevsyntax;
Denys Vlasenko958581a2010-09-12 15:04:27 +020011547 }
11548 } else {
11549 /*
11550 * unbalanced parens
11551 * (don't 2nd guess - no error)
11552 */
11553 pungetc();
11554 }
11555 }
11556 USTPUTC(c, out);
11557 break;
11558#endif
11559 case CBQUOTE: /* '`' */
11560 PARSEBACKQOLD();
11561 break;
11562 case CENDFILE:
11563 goto endword; /* exit outer loop */
11564 case CIGN:
11565 break;
11566 default:
11567 if (varnest == 0) {
11568#if ENABLE_ASH_BASH_COMPAT
11569 if (c == '&') {
Denys Vlasenko459293b2016-09-29 17:58:58 +020011570//Can't call pgetc_eatbnl() here, this requires three-deep pungetc()
Denys Vlasenko958581a2010-09-12 15:04:27 +020011571 if (pgetc() == '>')
11572 c = 0x100 + '>'; /* flag &> */
11573 pungetc();
11574 }
11575#endif
11576 goto endword; /* exit outer loop */
11577 }
11578 IF_ASH_ALIAS(if (c != PEOA))
11579 USTPUTC(c, out);
11580 }
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020011581 c = pgetc();
Denys Vlasenko958581a2010-09-12 15:04:27 +020011582 } /* for (;;) */
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011583 endword:
Denys Vlasenko958581a2010-09-12 15:04:27 +020011584
Denys Vlasenko0b883582016-12-23 16:49:07 +010011585#if ENABLE_FEATURE_SH_MATH
Eric Andersencb57d552001-06-28 07:25:16 +000011586 if (syntax == ARISYNTAX)
Denis Vlasenko559691a2008-10-05 18:39:31 +000011587 raise_error_syntax("missing '))'");
Eric Andersenc470f442003-07-28 09:56:35 +000011588#endif
Ron Yorston0e056f72015-07-01 16:45:40 +010011589 if (syntax != BASESYNTAX && eofmark == NULL)
Denis Vlasenko559691a2008-10-05 18:39:31 +000011590 raise_error_syntax("unterminated quoted string");
Eric Andersencb57d552001-06-28 07:25:16 +000011591 if (varnest != 0) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011592 startlinno = g_parsefile->linno;
Eric Andersenc470f442003-07-28 09:56:35 +000011593 /* { */
Denis Vlasenko559691a2008-10-05 18:39:31 +000011594 raise_error_syntax("missing '}'");
Eric Andersencb57d552001-06-28 07:25:16 +000011595 }
11596 USTPUTC('\0', out);
Eric Andersenc470f442003-07-28 09:56:35 +000011597 len = out - (char *)stackblock();
Eric Andersencb57d552001-06-28 07:25:16 +000011598 out = stackblock();
11599 if (eofmark == NULL) {
Denis Vlasenko5e34ff22009-04-21 11:09:40 +000011600 if ((c == '>' || c == '<' IF_ASH_BASH_COMPAT( || c == 0x100 + '>'))
Denis Vlasenko834dee72008-10-07 09:18:30 +000011601 && quotef == 0
11602 ) {
Denis Vlasenko559691a2008-10-05 18:39:31 +000011603 if (isdigit_str9(out)) {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000011604 PARSEREDIR(); /* passed as params: out, c */
11605 lasttoken = TREDIR;
11606 return lasttoken;
11607 }
11608 /* else: non-number X seen, interpret it
11609 * as "NNNX>file" = "NNNX >file" */
Eric Andersencb57d552001-06-28 07:25:16 +000011610 }
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011611 pungetc();
Eric Andersencb57d552001-06-28 07:25:16 +000011612 }
11613 quoteflag = quotef;
11614 backquotelist = bqlist;
11615 grabstackblock(len);
11616 wordtext = out;
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011617 lasttoken = TWORD;
11618 return lasttoken;
Eric Andersencb57d552001-06-28 07:25:16 +000011619/* end of readtoken routine */
11620
Eric Andersencb57d552001-06-28 07:25:16 +000011621/*
11622 * Check to see whether we are at the end of the here document. When this
11623 * is called, c is set to the first character of the next input line. If
11624 * we are at the end of the here document, this routine sets the c to PEOF.
11625 */
Eric Andersenc470f442003-07-28 09:56:35 +000011626checkend: {
11627 if (eofmark) {
Denis Vlasenko131ae172007-02-18 13:00:19 +000011628#if ENABLE_ASH_ALIAS
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010011629 if (c == PEOA)
11630 c = pgetc_without_PEOA();
Eric Andersenc470f442003-07-28 09:56:35 +000011631#endif
11632 if (striptabs) {
11633 while (c == '\t') {
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010011634 c = pgetc_without_PEOA();
Eric Andersencb57d552001-06-28 07:25:16 +000011635 }
Eric Andersenc470f442003-07-28 09:56:35 +000011636 }
11637 if (c == *eofmark) {
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011638 if (pfgets(line, sizeof(line)) != NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +000011639 char *p, *q;
Denys Vlasenko350e6862016-10-26 16:26:45 +020011640 int cc;
Eric Andersencb57d552001-06-28 07:25:16 +000011641
Eric Andersenc470f442003-07-28 09:56:35 +000011642 p = line;
Denys Vlasenko350e6862016-10-26 16:26:45 +020011643 for (q = eofmark + 1;; p++, q++) {
11644 cc = *p;
11645 if (cc == '\n')
11646 cc = 0;
11647 if (!*q || cc != *q)
11648 break;
11649 }
11650 if (cc == *q) {
Eric Andersenc470f442003-07-28 09:56:35 +000011651 c = PEOF;
Denys Vlasenkoce332a22016-10-02 23:47:34 +020011652 nlnoprompt();
Eric Andersenc470f442003-07-28 09:56:35 +000011653 } else {
11654 pushstring(line, NULL);
Eric Andersencb57d552001-06-28 07:25:16 +000011655 }
11656 }
11657 }
11658 }
Eric Andersenc470f442003-07-28 09:56:35 +000011659 goto checkend_return;
11660}
Eric Andersencb57d552001-06-28 07:25:16 +000011661
Eric Andersencb57d552001-06-28 07:25:16 +000011662/*
11663 * Parse a redirection operator. The variable "out" points to a string
11664 * specifying the fd to be redirected. The variable "c" contains the
11665 * first character of the redirection operator.
11666 */
Eric Andersenc470f442003-07-28 09:56:35 +000011667parseredir: {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000011668 /* out is already checked to be a valid number or "" */
11669 int fd = (*out == '\0' ? -1 : atoi(out));
Eric Andersenc470f442003-07-28 09:56:35 +000011670 union node *np;
Eric Andersencb57d552001-06-28 07:25:16 +000011671
Denis Vlasenko597906c2008-02-20 16:38:54 +000011672 np = stzalloc(sizeof(struct nfile));
Eric Andersenc470f442003-07-28 09:56:35 +000011673 if (c == '>') {
11674 np->nfile.fd = 1;
11675 c = pgetc();
11676 if (c == '>')
11677 np->type = NAPPEND;
11678 else if (c == '|')
11679 np->type = NCLOBBER;
11680 else if (c == '&')
11681 np->type = NTOFD;
Denis Vlasenko559691a2008-10-05 18:39:31 +000011682 /* it also can be NTO2 (>&file), but we can't figure it out yet */
Eric Andersenc470f442003-07-28 09:56:35 +000011683 else {
11684 np->type = NTO;
11685 pungetc();
Eric Andersencb57d552001-06-28 07:25:16 +000011686 }
Denis Vlasenko834dee72008-10-07 09:18:30 +000011687 }
11688#if ENABLE_ASH_BASH_COMPAT
11689 else if (c == 0x100 + '>') { /* this flags &> redirection */
11690 np->nfile.fd = 1;
11691 pgetc(); /* this is '>', no need to check */
11692 np->type = NTO2;
11693 }
11694#endif
11695 else { /* c == '<' */
Denis Vlasenko597906c2008-02-20 16:38:54 +000011696 /*np->nfile.fd = 0; - stzalloc did it */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011697 c = pgetc();
11698 switch (c) {
Eric Andersenc470f442003-07-28 09:56:35 +000011699 case '<':
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011700 if (sizeof(struct nfile) != sizeof(struct nhere)) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011701 np = stzalloc(sizeof(struct nhere));
11702 /*np->nfile.fd = 0; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011703 }
11704 np->type = NHERE;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011705 heredoc = stzalloc(sizeof(struct heredoc));
Eric Andersenc470f442003-07-28 09:56:35 +000011706 heredoc->here = np;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011707 c = pgetc();
11708 if (c == '-') {
Eric Andersenc470f442003-07-28 09:56:35 +000011709 heredoc->striptabs = 1;
11710 } else {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011711 /*heredoc->striptabs = 0; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011712 pungetc();
11713 }
11714 break;
11715
11716 case '&':
11717 np->type = NFROMFD;
11718 break;
11719
11720 case '>':
11721 np->type = NFROMTO;
11722 break;
11723
11724 default:
11725 np->type = NFROM;
11726 pungetc();
11727 break;
11728 }
Eric Andersencb57d552001-06-28 07:25:16 +000011729 }
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000011730 if (fd >= 0)
11731 np->nfile.fd = fd;
Eric Andersenc470f442003-07-28 09:56:35 +000011732 redirnode = np;
11733 goto parseredir_return;
11734}
Eric Andersencb57d552001-06-28 07:25:16 +000011735
Eric Andersencb57d552001-06-28 07:25:16 +000011736/*
11737 * Parse a substitution. At this point, we have read the dollar sign
11738 * and nothing else.
11739 */
Denis Vlasenkocc571512007-02-23 21:10:35 +000011740
11741/* is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise
11742 * (assuming ascii char codes, as the original implementation did) */
11743#define is_special(c) \
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011744 (((unsigned)(c) - 33 < 32) \
11745 && ((0xc1ff920dU >> ((unsigned)(c) - 33)) & 1))
Eric Andersenc470f442003-07-28 09:56:35 +000011746parsesub: {
Denys Vlasenkocd716832009-11-28 22:14:02 +010011747 unsigned char subtype;
Eric Andersenc470f442003-07-28 09:56:35 +000011748 int typeloc;
Eric Andersencb57d552001-06-28 07:25:16 +000011749
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011750 c = pgetc_eatbnl();
Denys Vlasenkocd716832009-11-28 22:14:02 +010011751 if (c > 255 /* PEOA or PEOF */
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011752 || (c != '(' && c != '{' && !is_name(c) && !is_special(c))
Eric Andersenc470f442003-07-28 09:56:35 +000011753 ) {
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011754#if ENABLE_ASH_BASH_COMPAT
Ron Yorston84ba50c2016-04-03 22:43:14 +010011755 if (syntax != DQSYNTAX && c == '\'')
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011756 bash_dollar_squote = 1;
11757 else
11758#endif
11759 USTPUTC('$', out);
Eric Andersenc470f442003-07-28 09:56:35 +000011760 pungetc();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011761 } else if (c == '(') {
11762 /* $(command) or $((arith)) */
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011763 if (pgetc_eatbnl() == '(') {
Denys Vlasenko0b883582016-12-23 16:49:07 +010011764#if ENABLE_FEATURE_SH_MATH
Eric Andersenc470f442003-07-28 09:56:35 +000011765 PARSEARITH();
11766#else
Mike Frysinger98a6f562008-06-09 09:38:45 +000011767 raise_error_syntax("you disabled math support for $((arith)) syntax");
Eric Andersenc470f442003-07-28 09:56:35 +000011768#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011769 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000011770 pungetc();
11771 PARSEBACKQNEW();
11772 }
11773 } else {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011774 /* $VAR, $<specialchar>, ${...}, or PEOA/PEOF */
Eric Andersenc470f442003-07-28 09:56:35 +000011775 USTPUTC(CTLVAR, out);
11776 typeloc = out - (char *)stackblock();
Denys Vlasenko3df14102016-10-26 16:41:13 +020011777 STADJUST(1, out);
Eric Andersenc470f442003-07-28 09:56:35 +000011778 subtype = VSNORMAL;
11779 if (c == '{') {
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011780 c = pgetc_eatbnl();
Denys Vlasenkof15aa572016-10-26 15:56:53 +020011781 subtype = 0;
Eric Andersenc470f442003-07-28 09:56:35 +000011782 }
Denys Vlasenkof15aa572016-10-26 15:56:53 +020011783 varname:
Denys Vlasenko3df14102016-10-26 16:41:13 +020011784 if (is_name(c)) {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011785 /* $[{[#]]NAME[}] */
Eric Andersenc470f442003-07-28 09:56:35 +000011786 do {
11787 STPUTC(c, out);
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011788 c = pgetc_eatbnl();
Denys Vlasenko3df14102016-10-26 16:41:13 +020011789 } while (is_in_name(c));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011790 } else if (isdigit(c)) {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011791 /* $[{[#]]NUM[}] */
Eric Andersenc470f442003-07-28 09:56:35 +000011792 do {
11793 STPUTC(c, out);
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011794 c = pgetc_eatbnl();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011795 } while (isdigit(c));
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011796 } else if (is_special(c)) {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011797 /* $[{[#]]<specialchar>[}] */
Denys Vlasenkof15aa572016-10-26 15:56:53 +020011798 int cc = c;
11799
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011800 c = pgetc_eatbnl();
Denys Vlasenkof15aa572016-10-26 15:56:53 +020011801 if (!subtype && cc == '#') {
11802 subtype = VSLENGTH;
11803 if (c == '_' || isalnum(c))
11804 goto varname;
11805 cc = c;
11806 c = pgetc_eatbnl();
11807 if (cc == '}' || c != '}') {
11808 pungetc();
11809 subtype = 0;
11810 c = cc;
11811 cc = '#';
11812 }
11813 }
11814 USTPUTC(cc, out);
Denis Vlasenko559691a2008-10-05 18:39:31 +000011815 } else {
Denys Vlasenko88e15702016-10-26 01:55:56 +020011816 goto badsub;
Denis Vlasenko559691a2008-10-05 18:39:31 +000011817 }
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011818 if (c != '}' && subtype == VSLENGTH) {
11819 /* ${#VAR didn't end with } */
Cristian Ionescu-Idbohrn301f5ec2009-10-05 02:07:23 +020011820 goto badsub;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011821 }
Eric Andersencb57d552001-06-28 07:25:16 +000011822
Eric Andersenc470f442003-07-28 09:56:35 +000011823 if (subtype == 0) {
Denys Vlasenkof8ddbe12016-07-25 03:56:00 +020011824 static const char types[] ALIGN1 = "}-+?=";
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011825 /* ${VAR...} but not $VAR or ${#VAR} */
11826 /* c == first char after VAR */
Eric Andersenc470f442003-07-28 09:56:35 +000011827 switch (c) {
11828 case ':':
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011829 c = pgetc_eatbnl();
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011830#if ENABLE_ASH_BASH_COMPAT
Denys Vlasenkof8ddbe12016-07-25 03:56:00 +020011831 /* This check is only needed to not misinterpret
11832 * ${VAR:-WORD}, ${VAR:+WORD}, ${VAR:=WORD}, ${VAR:?WORD}
11833 * constructs.
11834 */
11835 if (!strchr(types, c)) {
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011836 subtype = VSSUBSTR;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011837 pungetc();
Denys Vlasenko88e15702016-10-26 01:55:56 +020011838 break; /* "goto badsub" is bigger (!) */
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011839 }
11840#endif
Denys Vlasenko3df14102016-10-26 16:41:13 +020011841 subtype = VSNUL;
Eric Andersenc470f442003-07-28 09:56:35 +000011842 /*FALLTHROUGH*/
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011843 default: {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011844 const char *p = strchr(types, c);
Eric Andersenc470f442003-07-28 09:56:35 +000011845 if (p == NULL)
Denys Vlasenko88e15702016-10-26 01:55:56 +020011846 break;
Denys Vlasenko3df14102016-10-26 16:41:13 +020011847 subtype |= p - types + VSNORMAL;
Eric Andersenc470f442003-07-28 09:56:35 +000011848 break;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011849 }
Eric Andersenc470f442003-07-28 09:56:35 +000011850 case '%':
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011851 case '#': {
11852 int cc = c;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011853 subtype = (c == '#' ? VSTRIMLEFT : VSTRIMRIGHT);
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011854 c = pgetc_eatbnl();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011855 if (c != cc)
Denys Vlasenko88e15702016-10-26 01:55:56 +020011856 goto badsub;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011857 subtype++;
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011858 break;
11859 }
11860#if ENABLE_ASH_BASH_COMPAT
11861 case '/':
Denys Vlasenko6040fe82010-09-12 15:03:16 +020011862 /* ${v/[/]pattern/repl} */
11863//TODO: encode pattern and repl separately.
11864// Currently ${v/$var_with_slash/repl} is horribly broken
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011865 subtype = VSREPLACE;
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011866 c = pgetc_eatbnl();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011867 if (c != '/')
Denys Vlasenko88e15702016-10-26 01:55:56 +020011868 goto badsub;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011869 subtype++; /* VSREPLACEALL */
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011870 break;
11871#endif
Eric Andersencb57d552001-06-28 07:25:16 +000011872 }
Eric Andersenc470f442003-07-28 09:56:35 +000011873 } else {
Denys Vlasenko88e15702016-10-26 01:55:56 +020011874 badsub:
Eric Andersenc470f442003-07-28 09:56:35 +000011875 pungetc();
11876 }
Denys Vlasenko3df14102016-10-26 16:41:13 +020011877 ((unsigned char *)stackblock())[typeloc] = subtype;
Eric Andersenc470f442003-07-28 09:56:35 +000011878 if (subtype != VSNORMAL) {
11879 varnest++;
Denys Vlasenko3df14102016-10-26 16:41:13 +020011880 if (dblquote)
Eric Andersenc470f442003-07-28 09:56:35 +000011881 dqvarnest++;
Eric Andersencb57d552001-06-28 07:25:16 +000011882 }
Denys Vlasenko88e15702016-10-26 01:55:56 +020011883 STPUTC('=', out);
Eric Andersencb57d552001-06-28 07:25:16 +000011884 }
Eric Andersenc470f442003-07-28 09:56:35 +000011885 goto parsesub_return;
11886}
Eric Andersencb57d552001-06-28 07:25:16 +000011887
Eric Andersencb57d552001-06-28 07:25:16 +000011888/*
11889 * Called to parse command substitutions. Newstyle is set if the command
11890 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
11891 * list of commands (passed by reference), and savelen is the number of
11892 * characters on the top of the stack which must be preserved.
11893 */
Eric Andersenc470f442003-07-28 09:56:35 +000011894parsebackq: {
11895 struct nodelist **nlpp;
Eric Andersenc470f442003-07-28 09:56:35 +000011896 union node *n;
Ron Yorston072fc602015-07-01 16:46:18 +010011897 char *str;
Eric Andersenc470f442003-07-28 09:56:35 +000011898 size_t savelen;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011899 smallint saveprompt = 0;
11900
Eric Andersenc470f442003-07-28 09:56:35 +000011901 str = NULL;
11902 savelen = out - (char *)stackblock();
11903 if (savelen > 0) {
Denys Vlasenko7bc3d392016-09-17 20:53:47 +020011904 /*
11905 * FIXME: this can allocate very large block on stack and SEGV.
11906 * Example:
11907 * echo "..<100kbytes>..`true` $(true) `true` ..."
Denys Vlasenko73737592016-09-17 20:58:22 +020011908 * allocates 100kb for every command subst. With about
Denys Vlasenko7bc3d392016-09-17 20:53:47 +020011909 * a hundred command substitutions stack overflows.
11910 * With larger prepended string, SEGV happens sooner.
11911 */
Ron Yorston072fc602015-07-01 16:46:18 +010011912 str = alloca(savelen);
Eric Andersenc470f442003-07-28 09:56:35 +000011913 memcpy(str, stackblock(), savelen);
11914 }
Denys Vlasenko7bc3d392016-09-17 20:53:47 +020011915
Eric Andersenc470f442003-07-28 09:56:35 +000011916 if (oldstyle) {
11917 /* We must read until the closing backquote, giving special
Denys Vlasenko60cb48c2013-01-14 15:57:44 +010011918 * treatment to some slashes, and then push the string and
11919 * reread it as input, interpreting it normally.
11920 */
Eric Andersenc470f442003-07-28 09:56:35 +000011921 char *pout;
Eric Andersenc470f442003-07-28 09:56:35 +000011922 size_t psavelen;
11923 char *pstr;
11924
Eric Andersenc470f442003-07-28 09:56:35 +000011925 STARTSTACKSTR(pout);
11926 for (;;) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020011927 int pc;
11928
11929 setprompt_if(needprompt, 2);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011930 pc = pgetc();
11931 switch (pc) {
Eric Andersenc470f442003-07-28 09:56:35 +000011932 case '`':
11933 goto done;
11934
11935 case '\\':
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011936 pc = pgetc();
11937 if (pc == '\n') {
Denys Vlasenkoce332a22016-10-02 23:47:34 +020011938 nlprompt();
Eric Andersenc470f442003-07-28 09:56:35 +000011939 /*
11940 * If eating a newline, avoid putting
11941 * the newline into the new character
11942 * stream (via the STPUTC after the
11943 * switch).
11944 */
11945 continue;
11946 }
11947 if (pc != '\\' && pc != '`' && pc != '$'
Denys Vlasenko76bc2d62009-11-29 01:37:46 +010011948 && (!dblquote || pc != '"')
11949 ) {
Eric Andersenc470f442003-07-28 09:56:35 +000011950 STPUTC('\\', pout);
Denys Vlasenko76bc2d62009-11-29 01:37:46 +010011951 }
Denys Vlasenkocd716832009-11-28 22:14:02 +010011952 if (pc <= 255 /* not PEOA or PEOF */) {
Eric Andersenc470f442003-07-28 09:56:35 +000011953 break;
11954 }
11955 /* fall through */
11956
11957 case PEOF:
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010011958 IF_ASH_ALIAS(case PEOA:)
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011959 startlinno = g_parsefile->linno;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011960 raise_error_syntax("EOF in backquote substitution");
Eric Andersenc470f442003-07-28 09:56:35 +000011961
11962 case '\n':
Denys Vlasenkoce332a22016-10-02 23:47:34 +020011963 nlnoprompt();
Eric Andersenc470f442003-07-28 09:56:35 +000011964 break;
11965
11966 default:
11967 break;
11968 }
11969 STPUTC(pc, pout);
11970 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011971 done:
Eric Andersenc470f442003-07-28 09:56:35 +000011972 STPUTC('\0', pout);
11973 psavelen = pout - (char *)stackblock();
11974 if (psavelen > 0) {
11975 pstr = grabstackstr(pout);
11976 setinputstring(pstr);
11977 }
11978 }
11979 nlpp = &bqlist;
11980 while (*nlpp)
11981 nlpp = &(*nlpp)->next;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011982 *nlpp = stzalloc(sizeof(**nlpp));
11983 /* (*nlpp)->next = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011984
11985 if (oldstyle) {
11986 saveprompt = doprompt;
11987 doprompt = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000011988 }
11989
Eric Andersenc470f442003-07-28 09:56:35 +000011990 n = list(2);
11991
11992 if (oldstyle)
11993 doprompt = saveprompt;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011994 else if (readtoken() != TRP)
11995 raise_error_unexpected_syntax(TRP);
Eric Andersenc470f442003-07-28 09:56:35 +000011996
11997 (*nlpp)->n = n;
11998 if (oldstyle) {
11999 /*
12000 * Start reading from old file again, ignoring any pushed back
12001 * tokens left from the backquote parsing
12002 */
12003 popfile();
12004 tokpushback = 0;
12005 }
12006 while (stackblocksize() <= savelen)
12007 growstackblock();
12008 STARTSTACKSTR(out);
12009 if (str) {
12010 memcpy(out, str, savelen);
12011 STADJUST(savelen, out);
Eric Andersenc470f442003-07-28 09:56:35 +000012012 }
Ron Yorston549deab2015-05-18 09:57:51 +020012013 USTPUTC(CTLBACKQ, out);
Eric Andersenc470f442003-07-28 09:56:35 +000012014 if (oldstyle)
12015 goto parsebackq_oldreturn;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000012016 goto parsebackq_newreturn;
Eric Andersenc470f442003-07-28 09:56:35 +000012017}
12018
Denys Vlasenko0b883582016-12-23 16:49:07 +010012019#if ENABLE_FEATURE_SH_MATH
Eric Andersencb57d552001-06-28 07:25:16 +000012020/*
12021 * Parse an arithmetic expansion (indicate start of one and set state)
12022 */
Eric Andersenc470f442003-07-28 09:56:35 +000012023parsearith: {
Eric Andersenc470f442003-07-28 09:56:35 +000012024 if (++arinest == 1) {
12025 prevsyntax = syntax;
12026 syntax = ARISYNTAX;
Eric Andersencb57d552001-06-28 07:25:16 +000012027 }
Ron Yorstonad88bde2015-05-18 09:56:16 +020012028 USTPUTC(CTLARI, out);
Eric Andersenc470f442003-07-28 09:56:35 +000012029 goto parsearith_return;
12030}
12031#endif
Eric Andersenc470f442003-07-28 09:56:35 +000012032} /* end of readtoken */
12033
Eric Andersencb57d552001-06-28 07:25:16 +000012034/*
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012035 * Read the next input token.
12036 * If the token is a word, we set backquotelist to the list of cmds in
12037 * backquotes. We set quoteflag to true if any part of the word was
12038 * quoted.
12039 * If the token is TREDIR, then we set redirnode to a structure containing
12040 * the redirection.
12041 * In all cases, the variable startlinno is set to the number of the line
12042 * on which the token starts.
12043 *
12044 * [Change comment: here documents and internal procedures]
12045 * [Readtoken shouldn't have any arguments. Perhaps we should make the
12046 * word parsing code into a separate routine. In this case, readtoken
12047 * doesn't need to have any internal procedures, but parseword does.
12048 * We could also make parseoperator in essence the main routine, and
12049 * have parseword (readtoken1?) handle both words and redirection.]
Eric Andersencb57d552001-06-28 07:25:16 +000012050 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012051#define NEW_xxreadtoken
12052#ifdef NEW_xxreadtoken
12053/* singles must be first! */
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000012054static const char xxreadtoken_chars[7] ALIGN1 = {
Denis Vlasenko834dee72008-10-07 09:18:30 +000012055 '\n', '(', ')', /* singles */
12056 '&', '|', ';', /* doubles */
12057 0
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000012058};
Eric Andersencb57d552001-06-28 07:25:16 +000012059
Denis Vlasenko834dee72008-10-07 09:18:30 +000012060#define xxreadtoken_singles 3
12061#define xxreadtoken_doubles 3
12062
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000012063static const char xxreadtoken_tokens[] ALIGN1 = {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012064 TNL, TLP, TRP, /* only single occurrence allowed */
12065 TBACKGND, TPIPE, TSEMI, /* if single occurrence */
12066 TEOF, /* corresponds to trailing nul */
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000012067 TAND, TOR, TENDCASE /* if double occurrence */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012068};
12069
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012070static int
12071xxreadtoken(void)
12072{
12073 int c;
12074
12075 if (tokpushback) {
12076 tokpushback = 0;
12077 return lasttoken;
Eric Andersencb57d552001-06-28 07:25:16 +000012078 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020012079 setprompt_if(needprompt, 2);
Denis Vlasenko41eb3002008-11-28 03:42:31 +000012080 startlinno = g_parsefile->linno;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012081 for (;;) { /* until token or start of word found */
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020012082 c = pgetc();
Denis Vlasenko5e34ff22009-04-21 11:09:40 +000012083 if (c == ' ' || c == '\t' IF_ASH_ALIAS( || c == PEOA))
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012084 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012085
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012086 if (c == '#') {
12087 while ((c = pgetc()) != '\n' && c != PEOF)
12088 continue;
12089 pungetc();
12090 } else if (c == '\\') {
12091 if (pgetc() != '\n') {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012092 pungetc();
Denis Vlasenko834dee72008-10-07 09:18:30 +000012093 break; /* return readtoken1(...) */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012094 }
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012095 nlprompt();
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012096 } else {
12097 const char *p;
12098
12099 p = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
12100 if (c != PEOF) {
12101 if (c == '\n') {
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012102 nlnoprompt();
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012103 }
12104
12105 p = strchr(xxreadtoken_chars, c);
Denis Vlasenko834dee72008-10-07 09:18:30 +000012106 if (p == NULL)
12107 break; /* return readtoken1(...) */
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012108
Denis Vlasenko834dee72008-10-07 09:18:30 +000012109 if ((int)(p - xxreadtoken_chars) >= xxreadtoken_singles) {
12110 int cc = pgetc();
12111 if (cc == c) { /* double occurrence? */
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012112 p += xxreadtoken_doubles + 1;
12113 } else {
12114 pungetc();
Denis Vlasenko834dee72008-10-07 09:18:30 +000012115#if ENABLE_ASH_BASH_COMPAT
12116 if (c == '&' && cc == '>') /* &> */
12117 break; /* return readtoken1(...) */
12118#endif
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012119 }
12120 }
12121 }
12122 lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
12123 return lasttoken;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012124 }
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012125 } /* for (;;) */
Denis Vlasenko834dee72008-10-07 09:18:30 +000012126
12127 return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012128}
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012129#else /* old xxreadtoken */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012130#define RETURN(token) return lasttoken = token
12131static int
12132xxreadtoken(void)
12133{
12134 int c;
12135
12136 if (tokpushback) {
12137 tokpushback = 0;
12138 return lasttoken;
12139 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020012140 setprompt_if(needprompt, 2);
Denis Vlasenko41eb3002008-11-28 03:42:31 +000012141 startlinno = g_parsefile->linno;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012142 for (;;) { /* until token or start of word found */
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020012143 c = pgetc();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012144 switch (c) {
12145 case ' ': case '\t':
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010012146 IF_ASH_ALIAS(case PEOA:)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012147 continue;
12148 case '#':
Denis Vlasenkof7d56652008-03-25 05:51:41 +000012149 while ((c = pgetc()) != '\n' && c != PEOF)
12150 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012151 pungetc();
12152 continue;
12153 case '\\':
12154 if (pgetc() == '\n') {
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012155 nlprompt();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012156 continue;
12157 }
12158 pungetc();
12159 goto breakloop;
12160 case '\n':
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012161 nlnoprompt();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012162 RETURN(TNL);
12163 case PEOF:
12164 RETURN(TEOF);
12165 case '&':
12166 if (pgetc() == '&')
12167 RETURN(TAND);
12168 pungetc();
12169 RETURN(TBACKGND);
12170 case '|':
12171 if (pgetc() == '|')
12172 RETURN(TOR);
12173 pungetc();
12174 RETURN(TPIPE);
12175 case ';':
12176 if (pgetc() == ';')
12177 RETURN(TENDCASE);
12178 pungetc();
12179 RETURN(TSEMI);
12180 case '(':
12181 RETURN(TLP);
12182 case ')':
12183 RETURN(TRP);
12184 default:
12185 goto breakloop;
12186 }
12187 }
12188 breakloop:
12189 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
12190#undef RETURN
12191}
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012192#endif /* old xxreadtoken */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012193
12194static int
12195readtoken(void)
12196{
12197 int t;
Ron Yorston713f07d2015-10-29 16:44:56 +000012198 int kwd = checkkwd;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012199#if DEBUG
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000012200 smallint alreadyseen = tokpushback;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012201#endif
12202
12203#if ENABLE_ASH_ALIAS
12204 top:
12205#endif
12206
12207 t = xxreadtoken();
12208
12209 /*
12210 * eat newlines
12211 */
Ron Yorston713f07d2015-10-29 16:44:56 +000012212 if (kwd & CHKNL) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012213 while (t == TNL) {
12214 parseheredoc();
12215 t = xxreadtoken();
12216 }
12217 }
12218
12219 if (t != TWORD || quoteflag) {
12220 goto out;
12221 }
12222
12223 /*
12224 * check for keywords
12225 */
Ron Yorston713f07d2015-10-29 16:44:56 +000012226 if (kwd & CHKKWD) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012227 const char *const *pp;
12228
12229 pp = findkwd(wordtext);
12230 if (pp) {
12231 lasttoken = t = pp - tokname_array;
Denys Vlasenko888527c2016-10-02 16:54:17 +020012232 TRACE(("keyword '%s' recognized\n", tokname_array[t]));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012233 goto out;
12234 }
12235 }
12236
12237 if (checkkwd & CHKALIAS) {
12238#if ENABLE_ASH_ALIAS
12239 struct alias *ap;
12240 ap = lookupalias(wordtext, 1);
12241 if (ap != NULL) {
12242 if (*ap->val) {
12243 pushstring(ap->val, ap);
12244 }
12245 goto top;
12246 }
12247#endif
12248 }
12249 out:
12250 checkkwd = 0;
12251#if DEBUG
12252 if (!alreadyseen)
Denys Vlasenko888527c2016-10-02 16:54:17 +020012253 TRACE(("token '%s' %s\n", tokname_array[t], t == TWORD ? wordtext : ""));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012254 else
Denys Vlasenko888527c2016-10-02 16:54:17 +020012255 TRACE(("reread token '%s' %s\n", tokname_array[t], t == TWORD ? wordtext : ""));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012256#endif
12257 return t;
Eric Andersencb57d552001-06-28 07:25:16 +000012258}
12259
Ron Yorstonc0e00762015-10-29 11:30:55 +000012260static int
Ron Yorston6bd2fab2015-10-29 11:30:22 +000012261peektoken(void)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012262{
12263 int t;
12264
12265 t = readtoken();
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000012266 tokpushback = 1;
Ron Yorstonc0e00762015-10-29 11:30:55 +000012267 return t;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012268}
Eric Andersencb57d552001-06-28 07:25:16 +000012269
12270/*
Denys Vlasenko86e83ec2009-07-23 22:07:07 +020012271 * Read and parse a command. Returns NODE_EOF on end of file.
12272 * (NULL is a valid parse tree indicating a blank line.)
Eric Andersencb57d552001-06-28 07:25:16 +000012273 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012274static union node *
12275parsecmd(int interact)
Eric Andersen90898442003-08-06 11:20:52 +000012276{
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012277 tokpushback = 0;
Ron Yorstonc0e00762015-10-29 11:30:55 +000012278 checkkwd = 0;
12279 heredoclist = 0;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012280 doprompt = interact;
Denys Vlasenko958581a2010-09-12 15:04:27 +020012281 setprompt_if(doprompt, doprompt);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012282 needprompt = 0;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012283 return list(1);
12284}
12285
12286/*
12287 * Input any here documents.
12288 */
12289static void
12290parseheredoc(void)
12291{
12292 struct heredoc *here;
12293 union node *n;
12294
12295 here = heredoclist;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000012296 heredoclist = NULL;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012297
12298 while (here) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020012299 setprompt_if(needprompt, 2);
12300 readtoken1(pgetc(), here->here->type == NHERE ? SQSYNTAX : DQSYNTAX,
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012301 here->eofmark, here->striptabs);
Denis Vlasenko597906c2008-02-20 16:38:54 +000012302 n = stzalloc(sizeof(struct narg));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012303 n->narg.type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000012304 /*n->narg.next = NULL; - stzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012305 n->narg.text = wordtext;
12306 n->narg.backquote = backquotelist;
12307 here->here->nhere.doc = n;
12308 here = here->next;
Eric Andersencb57d552001-06-28 07:25:16 +000012309 }
Eric Andersencb57d552001-06-28 07:25:16 +000012310}
12311
12312
12313/*
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000012314 * called by editline -- any expansions to the prompt should be added here.
Eric Andersencb57d552001-06-28 07:25:16 +000012315 */
Denis Vlasenko131ae172007-02-18 13:00:19 +000012316#if ENABLE_ASH_EXPAND_PRMT
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012317static const char *
12318expandstr(const char *ps)
12319{
12320 union node n;
Denys Vlasenko2a6d29a2016-10-25 21:17:52 +020012321 int saveprompt;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012322
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000012323 /* XXX Fix (char *) cast. It _is_ a bug. ps is variable's value,
12324 * and token processing _can_ alter it (delete NULs etc). */
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012325 setinputstring((char *)ps);
Denys Vlasenko2a6d29a2016-10-25 21:17:52 +020012326
12327 saveprompt = doprompt;
12328 doprompt = 0;
Denis Vlasenko46a53062007-09-24 18:30:02 +000012329 readtoken1(pgetc(), PSSYNTAX, nullstr, 0);
Denys Vlasenko2a6d29a2016-10-25 21:17:52 +020012330 doprompt = saveprompt;
12331
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012332 popfile();
12333
12334 n.narg.type = NARG;
12335 n.narg.next = NULL;
12336 n.narg.text = wordtext;
12337 n.narg.backquote = backquotelist;
12338
Ron Yorston549deab2015-05-18 09:57:51 +020012339 expandarg(&n, NULL, EXP_QUOTED);
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012340 return stackblock();
12341}
12342#endif
12343
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012344/*
12345 * Execute a command or commands contained in a string.
12346 */
12347static int
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020012348evalstring(char *s, int flags)
Eric Andersenc470f442003-07-28 09:56:35 +000012349{
Denys Vlasenko493b9ca2016-10-30 18:27:14 +010012350 struct jmploc *volatile savehandler;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012351 struct jmploc jmploc;
12352 int ex;
12353
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012354 union node *n;
12355 struct stackmark smark;
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012356 int status;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012357
Denys Vlasenko8e2bc472016-09-28 23:02:57 +020012358 s = sstrdup(s);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012359 setinputstring(s);
12360 setstackmark(&smark);
12361
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012362 status = 0;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012363 /* On exception inside execution loop, we must popfile().
12364 * Try interactively:
12365 * readonly a=a
12366 * command eval "a=b" # throws "is read only" error
12367 * "command BLTIN" is not supposed to abort (even in non-interactive use).
12368 * But if we skip popfile(), we hit EOF in eval's string, and exit.
12369 */
12370 savehandler = exception_handler;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012371 ex = setjmp(jmploc.loc);
12372 if (ex)
12373 goto out;
Denys Vlasenko493b9ca2016-10-30 18:27:14 +010012374 exception_handler = &jmploc;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012375
Denys Vlasenko86e83ec2009-07-23 22:07:07 +020012376 while ((n = parsecmd(0)) != NODE_EOF) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020012377 int i;
12378
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020012379 i = evaltree(n, flags);
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012380 if (n)
12381 status = i;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012382 popstackmark(&smark);
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012383 if (evalskip)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012384 break;
12385 }
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012386 out:
Denys Vlasenko8e2bc472016-09-28 23:02:57 +020012387 popstackmark(&smark);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012388 popfile();
Denys Vlasenko8e2bc472016-09-28 23:02:57 +020012389 stunalloc(s);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012390
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012391 exception_handler = savehandler;
12392 if (ex)
12393 longjmp(exception_handler->loc, ex);
12394
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012395 return status;
Eric Andersenc470f442003-07-28 09:56:35 +000012396}
12397
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012398/*
12399 * The eval command.
12400 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012401static int FAST_FUNC
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020012402evalcmd(int argc UNUSED_PARAM, char **argv, int flags)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012403{
12404 char *p;
12405 char *concat;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012406
Denis Vlasenko68404f12008-03-17 09:00:54 +000012407 if (argv[1]) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012408 p = argv[1];
Denis Vlasenko68404f12008-03-17 09:00:54 +000012409 argv += 2;
12410 if (argv[0]) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012411 STARTSTACKSTR(concat);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012412 for (;;) {
12413 concat = stack_putstr(p, concat);
Denis Vlasenko68404f12008-03-17 09:00:54 +000012414 p = *argv++;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012415 if (p == NULL)
12416 break;
12417 STPUTC(' ', concat);
12418 }
12419 STPUTC('\0', concat);
12420 p = grabstackstr(concat);
12421 }
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020012422 return evalstring(p, flags & EV_TESTED);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012423 }
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012424 return 0;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012425}
12426
12427/*
Denys Vlasenko285ad152009-12-04 23:02:27 +010012428 * Read and execute commands.
12429 * "Top" is nonzero for the top level command loop;
12430 * it turns on prompting if the shell is interactive.
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012431 */
12432static int
12433cmdloop(int top)
12434{
12435 union node *n;
12436 struct stackmark smark;
12437 int inter;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020012438 int status = 0;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012439 int numeof = 0;
12440
12441 TRACE(("cmdloop(%d) called\n", top));
12442 for (;;) {
12443 int skip;
12444
12445 setstackmark(&smark);
12446#if JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +000012447 if (doing_jobctl)
Denys Vlasenko9c541002015-10-07 15:44:36 +020012448 showjobs(SHOW_CHANGED|SHOW_STDERR);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012449#endif
12450 inter = 0;
12451 if (iflag && top) {
12452 inter++;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012453 chkmail();
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012454 }
12455 n = parsecmd(inter);
Denys Vlasenko7cee00e2009-07-24 01:08:03 +020012456#if DEBUG
12457 if (DEBUG > 2 && debug && (n != NODE_EOF))
Denys Vlasenko883cea42009-07-11 15:31:59 +020012458 showtree(n);
Denis Vlasenko135cecb2009-04-12 00:00:57 +000012459#endif
Denys Vlasenko86e83ec2009-07-23 22:07:07 +020012460 if (n == NODE_EOF) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012461 if (!top || numeof >= 50)
12462 break;
12463 if (!stoppedjobs()) {
12464 if (!Iflag)
12465 break;
12466 out2str("\nUse \"exit\" to leave shell.\n");
12467 }
12468 numeof++;
12469 } else if (nflag == 0) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020012470 int i;
12471
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +000012472 /* job_warning can only be 2,1,0. Here 2->1, 1/0->0 */
12473 job_warning >>= 1;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012474 numeof = 0;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020012475 i = evaltree(n, 0);
12476 if (n)
12477 status = i;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012478 }
12479 popstackmark(&smark);
12480 skip = evalskip;
12481
12482 if (skip) {
Denys Vlasenko6a0710e2016-09-30 14:18:34 +020012483 evalskip &= ~SKIPFUNC;
Denys Vlasenko0840c912016-10-01 15:27:44 +020012484 break;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012485 }
12486 }
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020012487 return status;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012488}
12489
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000012490/*
12491 * Take commands from a file. To be compatible we should do a path
12492 * search for the file, which is necessary to find sub-commands.
12493 */
12494static char *
12495find_dot_file(char *name)
12496{
12497 char *fullname;
12498 const char *path = pathval();
12499 struct stat statb;
12500
12501 /* don't try this for absolute or relative paths */
12502 if (strchr(name, '/'))
12503 return name;
12504
Denis Vlasenko8ad78e12009-02-15 12:40:30 +000012505 /* IIRC standards do not say whether . is to be searched.
12506 * And it is even smaller this way, making it unconditional for now:
12507 */
12508 if (1) { /* ENABLE_ASH_BASH_COMPAT */
12509 fullname = name;
12510 goto try_cur_dir;
12511 }
12512
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020012513 while ((fullname = path_advance(&path, name)) != NULL) {
Denis Vlasenko8ad78e12009-02-15 12:40:30 +000012514 try_cur_dir:
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000012515 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
12516 /*
12517 * Don't bother freeing here, since it will
12518 * be freed by the caller.
12519 */
12520 return fullname;
12521 }
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020012522 if (fullname != name)
12523 stunalloc(fullname);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000012524 }
12525
12526 /* not found in the PATH */
12527 ash_msg_and_raise_error("%s: not found", name);
12528 /* NOTREACHED */
12529}
12530
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012531static int FAST_FUNC
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012532dotcmd(int argc_ UNUSED_PARAM, char **argv_ UNUSED_PARAM)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012533{
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012534 /* "false; . empty_file; echo $?" should print 0, not 1: */
12535 int status = 0;
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012536 char *fullname;
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012537 char **argv;
Denys Vlasenkofb87d932017-01-09 08:22:06 +010012538 char *args_need_save;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012539 struct strlist *sp;
12540 volatile struct shparam saveparam;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012541
12542 for (sp = cmdenviron; sp; sp = sp->next)
Denis Vlasenko4222ae42007-02-25 02:37:49 +000012543 setvareq(ckstrdup(sp->text), VSTRFIXED | VTEXTFIXED);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012544
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012545 nextopt(nullstr); /* handle possible "--" */
12546 argv = argptr;
12547
12548 if (!argv[0]) {
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012549 /* bash says: "bash: .: filename argument required" */
12550 return 2; /* bash compat */
12551 }
12552
Denys Vlasenko091f8312013-03-17 14:25:22 +010012553 /* This aborts if file isn't found, which is POSIXly correct.
12554 * bash returns exitcode 1 instead.
12555 */
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012556 fullname = find_dot_file(argv[0]);
12557 argv++;
Denys Vlasenkofb87d932017-01-09 08:22:06 +010012558 args_need_save = argv[0];
12559 if (args_need_save) { /* . FILE ARGS, ARGS exist */
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012560 int argc;
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012561 saveparam = shellparam;
12562 shellparam.malloced = 0;
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012563 argc = 1;
12564 while (argv[argc])
12565 argc++;
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012566 shellparam.nparam = argc;
12567 shellparam.p = argv;
12568 };
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012569
Denys Vlasenko091f8312013-03-17 14:25:22 +010012570 /* This aborts if file can't be opened, which is POSIXly correct.
12571 * bash returns exitcode 1 instead.
12572 */
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012573 setinputfile(fullname, INPUT_PUSH_FILE);
12574 commandname = fullname;
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012575 status = cmdloop(0);
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012576 popfile();
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012577
Denys Vlasenkofb87d932017-01-09 08:22:06 +010012578 if (args_need_save) {
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012579 freeparam(&shellparam);
12580 shellparam = saveparam;
12581 };
12582
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012583 return status;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012584}
12585
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012586static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012587exitcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012588{
12589 if (stoppedjobs())
12590 return 0;
Denis Vlasenko68404f12008-03-17 09:00:54 +000012591 if (argv[1])
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012592 exitstatus = number(argv[1]);
12593 raise_exception(EXEXIT);
12594 /* NOTREACHED */
12595}
12596
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012597/*
12598 * Read a file containing shell functions.
12599 */
12600static void
12601readcmdfile(char *name)
12602{
12603 setinputfile(name, INPUT_PUSH_FILE);
12604 cmdloop(0);
12605 popfile();
12606}
12607
12608
Denis Vlasenkocc571512007-02-23 21:10:35 +000012609/* ============ find_command inplementation */
12610
12611/*
12612 * Resolve a command name. If you change this routine, you may have to
12613 * change the shellexec routine as well.
12614 */
12615static void
12616find_command(char *name, struct cmdentry *entry, int act, const char *path)
12617{
12618 struct tblentry *cmdp;
12619 int idx;
12620 int prev;
12621 char *fullname;
12622 struct stat statb;
12623 int e;
12624 int updatetbl;
12625 struct builtincmd *bcmd;
12626
12627 /* If name contains a slash, don't use PATH or hash table */
12628 if (strchr(name, '/') != NULL) {
12629 entry->u.index = -1;
12630 if (act & DO_ABS) {
12631 while (stat(name, &statb) < 0) {
12632#ifdef SYSV
12633 if (errno == EINTR)
12634 continue;
12635#endif
12636 entry->cmdtype = CMDUNKNOWN;
12637 return;
12638 }
12639 }
12640 entry->cmdtype = CMDNORMAL;
12641 return;
12642 }
12643
Denis Vlasenkof20de5b2007-04-29 23:42:54 +000012644/* #if ENABLE_FEATURE_SH_STANDALONE... moved after builtin check */
Denis Vlasenkocc571512007-02-23 21:10:35 +000012645
12646 updatetbl = (path == pathval());
12647 if (!updatetbl) {
12648 act |= DO_ALTPATH;
12649 if (strstr(path, "%builtin") != NULL)
12650 act |= DO_ALTBLTIN;
12651 }
12652
12653 /* If name is in the table, check answer will be ok */
12654 cmdp = cmdlookup(name, 0);
12655 if (cmdp != NULL) {
12656 int bit;
12657
12658 switch (cmdp->cmdtype) {
12659 default:
12660#if DEBUG
12661 abort();
12662#endif
12663 case CMDNORMAL:
12664 bit = DO_ALTPATH;
12665 break;
12666 case CMDFUNCTION:
12667 bit = DO_NOFUNC;
12668 break;
12669 case CMDBUILTIN:
12670 bit = DO_ALTBLTIN;
12671 break;
12672 }
12673 if (act & bit) {
12674 updatetbl = 0;
12675 cmdp = NULL;
12676 } else if (cmdp->rehash == 0)
12677 /* if not invalidated by cd, we're done */
12678 goto success;
12679 }
12680
12681 /* If %builtin not in path, check for builtin next */
12682 bcmd = find_builtin(name);
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000012683 if (bcmd) {
12684 if (IS_BUILTIN_REGULAR(bcmd))
12685 goto builtin_success;
12686 if (act & DO_ALTPATH) {
12687 if (!(act & DO_ALTBLTIN))
12688 goto builtin_success;
12689 } else if (builtinloc <= 0) {
12690 goto builtin_success;
Denis Vlasenko8e858e22007-03-07 09:35:43 +000012691 }
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000012692 }
Denis Vlasenkocc571512007-02-23 21:10:35 +000012693
Denis Vlasenkof20de5b2007-04-29 23:42:54 +000012694#if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko7465dbc2008-04-13 02:25:53 +000012695 {
12696 int applet_no = find_applet_by_name(name);
12697 if (applet_no >= 0) {
12698 entry->cmdtype = CMDNORMAL;
12699 entry->u.index = -2 - applet_no;
12700 return;
12701 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +000012702 }
12703#endif
12704
Denis Vlasenkocc571512007-02-23 21:10:35 +000012705 /* We have to search path. */
12706 prev = -1; /* where to start */
12707 if (cmdp && cmdp->rehash) { /* doing a rehash */
12708 if (cmdp->cmdtype == CMDBUILTIN)
12709 prev = builtinloc;
12710 else
12711 prev = cmdp->param.index;
12712 }
12713
12714 e = ENOENT;
12715 idx = -1;
12716 loop:
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020012717 while ((fullname = path_advance(&path, name)) != NULL) {
Denis Vlasenkocc571512007-02-23 21:10:35 +000012718 stunalloc(fullname);
Denis Vlasenkodee82b62007-07-29 14:05:27 +000012719 /* NB: code below will still use fullname
12720 * despite it being "unallocated" */
Denis Vlasenkocc571512007-02-23 21:10:35 +000012721 idx++;
12722 if (pathopt) {
12723 if (prefix(pathopt, "builtin")) {
12724 if (bcmd)
12725 goto builtin_success;
12726 continue;
Denis Vlasenko4a9ca132008-04-12 20:07:08 +000012727 }
12728 if ((act & DO_NOFUNC)
12729 || !prefix(pathopt, "func")
Denys Vlasenkoe4dcba12010-10-28 18:57:19 +020012730 ) { /* ignore unimplemented options */
Denis Vlasenkocc571512007-02-23 21:10:35 +000012731 continue;
12732 }
12733 }
12734 /* if rehash, don't redo absolute path names */
12735 if (fullname[0] == '/' && idx <= prev) {
12736 if (idx < prev)
12737 continue;
12738 TRACE(("searchexec \"%s\": no change\n", name));
12739 goto success;
12740 }
12741 while (stat(fullname, &statb) < 0) {
12742#ifdef SYSV
12743 if (errno == EINTR)
12744 continue;
12745#endif
12746 if (errno != ENOENT && errno != ENOTDIR)
12747 e = errno;
12748 goto loop;
12749 }
12750 e = EACCES; /* if we fail, this will be the error */
12751 if (!S_ISREG(statb.st_mode))
12752 continue;
12753 if (pathopt) { /* this is a %func directory */
12754 stalloc(strlen(fullname) + 1);
Denis Vlasenkodee82b62007-07-29 14:05:27 +000012755 /* NB: stalloc will return space pointed by fullname
12756 * (because we don't have any intervening allocations
12757 * between stunalloc above and this stalloc) */
Denis Vlasenkocc571512007-02-23 21:10:35 +000012758 readcmdfile(fullname);
12759 cmdp = cmdlookup(name, 0);
12760 if (cmdp == NULL || cmdp->cmdtype != CMDFUNCTION)
12761 ash_msg_and_raise_error("%s not defined in %s", name, fullname);
12762 stunalloc(fullname);
12763 goto success;
12764 }
12765 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
12766 if (!updatetbl) {
12767 entry->cmdtype = CMDNORMAL;
12768 entry->u.index = idx;
12769 return;
12770 }
12771 INT_OFF;
12772 cmdp = cmdlookup(name, 1);
12773 cmdp->cmdtype = CMDNORMAL;
12774 cmdp->param.index = idx;
12775 INT_ON;
12776 goto success;
12777 }
12778
12779 /* We failed. If there was an entry for this command, delete it */
12780 if (cmdp && updatetbl)
12781 delete_cmd_entry();
12782 if (act & DO_ERR)
12783 ash_msg("%s: %s", name, errmsg(e, "not found"));
12784 entry->cmdtype = CMDUNKNOWN;
12785 return;
12786
12787 builtin_success:
12788 if (!updatetbl) {
12789 entry->cmdtype = CMDBUILTIN;
12790 entry->u.cmd = bcmd;
12791 return;
12792 }
12793 INT_OFF;
12794 cmdp = cmdlookup(name, 1);
12795 cmdp->cmdtype = CMDBUILTIN;
12796 cmdp->param.cmd = bcmd;
12797 INT_ON;
12798 success:
12799 cmdp->rehash = 0;
12800 entry->cmdtype = cmdp->cmdtype;
12801 entry->u = cmdp->param;
12802}
12803
12804
Eric Andersencb57d552001-06-28 07:25:16 +000012805/*
Eric Andersencb57d552001-06-28 07:25:16 +000012806 * The trap builtin.
12807 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012808static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012809trapcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +000012810{
12811 char *action;
12812 char **ap;
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010012813 int signo, exitcode;
Eric Andersencb57d552001-06-28 07:25:16 +000012814
Eric Andersenc470f442003-07-28 09:56:35 +000012815 nextopt(nullstr);
12816 ap = argptr;
12817 if (!*ap) {
Denis Vlasenko2da584f2007-02-19 22:44:05 +000012818 for (signo = 0; signo < NSIG; signo++) {
Denys Vlasenko21d87d42009-09-25 00:06:51 +020012819 char *tr = trap_ptr[signo];
12820 if (tr) {
Denys Vlasenkoe74aaf92009-09-27 02:05:45 +020012821 /* note: bash adds "SIG", but only if invoked
12822 * as "bash". If called as "sh", or if set -o posix,
12823 * then it prints short signal names.
12824 * We are printing short names: */
12825 out1fmt("trap -- %s %s\n",
Denys Vlasenko21d87d42009-09-25 00:06:51 +020012826 single_quote(tr),
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +000012827 get_signame(signo));
Denys Vlasenko726e1a02009-09-25 02:58:20 +020012828 /* trap_ptr != trap only if we are in special-cased `trap` code.
12829 * In this case, we will exit very soon, no need to free(). */
Denys Vlasenkoe74aaf92009-09-27 02:05:45 +020012830 /* if (trap_ptr != trap && tp[0]) */
Denys Vlasenko726e1a02009-09-25 02:58:20 +020012831 /* free(tr); */
Eric Andersencb57d552001-06-28 07:25:16 +000012832 }
12833 }
Denys Vlasenko726e1a02009-09-25 02:58:20 +020012834 /*
Denys Vlasenko21d87d42009-09-25 00:06:51 +020012835 if (trap_ptr != trap) {
12836 free(trap_ptr);
12837 trap_ptr = trap;
12838 }
Denys Vlasenko726e1a02009-09-25 02:58:20 +020012839 */
Eric Andersencb57d552001-06-28 07:25:16 +000012840 return 0;
12841 }
Denys Vlasenko21d87d42009-09-25 00:06:51 +020012842
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +000012843 action = NULL;
12844 if (ap[1])
Eric Andersencb57d552001-06-28 07:25:16 +000012845 action = *ap++;
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010012846 exitcode = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000012847 while (*ap) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000012848 signo = get_signum(*ap);
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010012849 if (signo < 0) {
12850 /* Mimic bash message exactly */
12851 ash_msg("%s: invalid signal specification", *ap);
12852 exitcode = 1;
12853 goto next;
12854 }
Denis Vlasenkob012b102007-02-19 22:43:01 +000012855 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +000012856 if (action) {
Denis Vlasenko9f739442006-12-16 23:49:13 +000012857 if (LONE_DASH(action))
Eric Andersencb57d552001-06-28 07:25:16 +000012858 action = NULL;
Denys Vlasenkob4f51d32016-10-27 12:55:09 +020012859 else {
12860 if (action[0]) /* not NULL and not "" and not "-" */
12861 may_have_traps = 1;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012862 action = ckstrdup(action);
Denys Vlasenkob4f51d32016-10-27 12:55:09 +020012863 }
Eric Andersencb57d552001-06-28 07:25:16 +000012864 }
Denis Vlasenko60818682007-09-28 22:07:23 +000012865 free(trap[signo]);
Eric Andersencb57d552001-06-28 07:25:16 +000012866 trap[signo] = action;
12867 if (signo != 0)
12868 setsignal(signo);
Denis Vlasenkob012b102007-02-19 22:43:01 +000012869 INT_ON;
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010012870 next:
Eric Andersencb57d552001-06-28 07:25:16 +000012871 ap++;
12872 }
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010012873 return exitcode;
Eric Andersencb57d552001-06-28 07:25:16 +000012874}
12875
Eric Andersenc470f442003-07-28 09:56:35 +000012876
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000012877/* ============ Builtins */
Eric Andersenc470f442003-07-28 09:56:35 +000012878
Denys Vlasenko2ec34962014-09-08 16:52:39 +020012879#if ENABLE_ASH_HELP
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012880static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012881helpcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000012882{
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000012883 unsigned col;
12884 unsigned i;
Eric Andersenc470f442003-07-28 09:56:35 +000012885
Denys Vlasenkod6b05eb2009-06-06 20:59:55 +020012886 out1fmt(
Denis Vlasenko34d4d892009-04-04 20:24:37 +000012887 "Built-in commands:\n"
12888 "------------------\n");
Denis Vlasenkob71c6682007-07-21 15:08:09 +000012889 for (col = 0, i = 0; i < ARRAY_SIZE(builtintab); i++) {
Eric Andersenc470f442003-07-28 09:56:35 +000012890 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
Denis Vlasenko52764022007-02-24 13:42:56 +000012891 builtintab[i].name + 1);
Eric Andersenc470f442003-07-28 09:56:35 +000012892 if (col > 60) {
12893 out1fmt("\n");
12894 col = 0;
12895 }
12896 }
Denys Vlasenko2ec34962014-09-08 16:52:39 +020012897# if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko1aa7e472007-11-28 06:49:03 +000012898 {
12899 const char *a = applet_names;
12900 while (*a) {
12901 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), a);
12902 if (col > 60) {
12903 out1fmt("\n");
12904 col = 0;
12905 }
Ron Yorston2b919582016-04-08 11:57:20 +010012906 while (*a++ != '\0')
12907 continue;
Eric Andersenc470f442003-07-28 09:56:35 +000012908 }
12909 }
Denys Vlasenko2ec34962014-09-08 16:52:39 +020012910# endif
Denys Vlasenkoebedb942016-10-02 18:45:09 +020012911 newline_and_flush(stdout);
Eric Andersenc470f442003-07-28 09:56:35 +000012912 return EXIT_SUCCESS;
12913}
Denys Vlasenko2ec34962014-09-08 16:52:39 +020012914#endif
Eric Andersenc470f442003-07-28 09:56:35 +000012915
Flemming Madsend96ffda2013-04-07 18:47:24 +020012916#if MAX_HISTORY
12917static int FAST_FUNC
12918historycmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12919{
12920 show_history(line_input_state);
12921 return EXIT_SUCCESS;
12922}
12923#endif
12924
Eric Andersencb57d552001-06-28 07:25:16 +000012925/*
Eric Andersencb57d552001-06-28 07:25:16 +000012926 * The export and readonly commands.
12927 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012928static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012929exportcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000012930{
12931 struct var *vp;
12932 char *name;
12933 const char *p;
Eric Andersenc470f442003-07-28 09:56:35 +000012934 char **aptr;
Denys Vlasenkod5275882012-10-01 13:41:17 +020012935 char opt;
12936 int flag;
12937 int flag_off;
Eric Andersencb57d552001-06-28 07:25:16 +000012938
Denys Vlasenkod5275882012-10-01 13:41:17 +020012939 /* "readonly" in bash accepts, but ignores -n.
12940 * We do the same: it saves a conditional in nextopt's param.
12941 */
12942 flag_off = 0;
12943 while ((opt = nextopt("np")) != '\0') {
12944 if (opt == 'n')
12945 flag_off = VEXPORT;
12946 }
12947 flag = VEXPORT;
12948 if (argv[0][0] == 'r') {
12949 flag = VREADONLY;
12950 flag_off = 0; /* readonly ignores -n */
12951 }
12952 flag_off = ~flag_off;
12953
12954 /*if (opt_p_not_specified) - bash doesnt check this. Try "export -p NAME" */
12955 {
Denis Vlasenko2da584f2007-02-19 22:44:05 +000012956 aptr = argptr;
12957 name = *aptr;
12958 if (name) {
12959 do {
12960 p = strchr(name, '=');
12961 if (p != NULL) {
12962 p++;
12963 } else {
12964 vp = *findvar(hashvar(name), name);
12965 if (vp) {
Denys Vlasenkod5275882012-10-01 13:41:17 +020012966 vp->flags = ((vp->flags | flag) & flag_off);
Denis Vlasenko2da584f2007-02-19 22:44:05 +000012967 continue;
12968 }
Eric Andersencb57d552001-06-28 07:25:16 +000012969 }
Denys Vlasenkod5275882012-10-01 13:41:17 +020012970 setvar(name, p, (flag & flag_off));
Denis Vlasenko2da584f2007-02-19 22:44:05 +000012971 } while ((name = *++aptr) != NULL);
12972 return 0;
12973 }
Eric Andersencb57d552001-06-28 07:25:16 +000012974 }
Denys Vlasenkod5275882012-10-01 13:41:17 +020012975
12976 /* No arguments. Show the list of exported or readonly vars.
12977 * -n is ignored.
12978 */
Denis Vlasenko2da584f2007-02-19 22:44:05 +000012979 showvars(argv[0], flag, 0);
Eric Andersencb57d552001-06-28 07:25:16 +000012980 return 0;
12981}
12982
Eric Andersencb57d552001-06-28 07:25:16 +000012983/*
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000012984 * Delete a function if it exists.
Eric Andersencb57d552001-06-28 07:25:16 +000012985 */
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +000012986static void
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000012987unsetfunc(const char *name)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012988{
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000012989 struct tblentry *cmdp;
Eric Andersencb57d552001-06-28 07:25:16 +000012990
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000012991 cmdp = cmdlookup(name, 0);
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020012992 if (cmdp != NULL && cmdp->cmdtype == CMDFUNCTION)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000012993 delete_cmd_entry();
Eric Andersenc470f442003-07-28 09:56:35 +000012994}
12995
Eric Andersencb57d552001-06-28 07:25:16 +000012996/*
Eric Andersencb57d552001-06-28 07:25:16 +000012997 * The unset builtin command. We unset the function before we unset the
12998 * variable to allow a function to be unset when there is a readonly variable
12999 * with the same name.
13000 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013001static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013002unsetcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +000013003{
13004 char **ap;
13005 int i;
Eric Andersenc470f442003-07-28 09:56:35 +000013006 int flag = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000013007 int ret = 0;
13008
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020013009 while ((i = nextopt("vf")) != 0) {
Eric Andersenc470f442003-07-28 09:56:35 +000013010 flag = i;
Eric Andersencb57d552001-06-28 07:25:16 +000013011 }
Eric Andersencb57d552001-06-28 07:25:16 +000013012
Denis Vlasenko2da584f2007-02-19 22:44:05 +000013013 for (ap = argptr; *ap; ap++) {
Eric Andersenc470f442003-07-28 09:56:35 +000013014 if (flag != 'f') {
13015 i = unsetvar(*ap);
13016 ret |= i;
13017 if (!(i & 2))
13018 continue;
13019 }
13020 if (flag != 'v')
Eric Andersencb57d552001-06-28 07:25:16 +000013021 unsetfunc(*ap);
Eric Andersencb57d552001-06-28 07:25:16 +000013022 }
Eric Andersenc470f442003-07-28 09:56:35 +000013023 return ret & 1;
Eric Andersencb57d552001-06-28 07:25:16 +000013024}
13025
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000013026static const unsigned char timescmd_str[] ALIGN1 = {
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013027 ' ', offsetof(struct tms, tms_utime),
13028 '\n', offsetof(struct tms, tms_stime),
13029 ' ', offsetof(struct tms, tms_cutime),
13030 '\n', offsetof(struct tms, tms_cstime),
13031 0
13032};
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013033static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013034timescmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013035{
Denys Vlasenko8cd9f342010-06-18 15:36:48 +020013036 unsigned long clk_tck, s, t;
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013037 const unsigned char *p;
13038 struct tms buf;
13039
Bartosz Golaszewski5d2e4092014-06-22 14:01:13 +020013040 clk_tck = bb_clk_tck();
Eric Andersencb57d552001-06-28 07:25:16 +000013041 times(&buf);
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013042
13043 p = timescmd_str;
13044 do {
13045 t = *(clock_t *)(((char *) &buf) + p[1]);
13046 s = t / clk_tck;
Denys Vlasenko8cd9f342010-06-18 15:36:48 +020013047 t = t % clk_tck;
13048 out1fmt("%lum%lu.%03lus%c",
13049 s / 60, s % 60,
13050 (t * 1000) / clk_tck,
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013051 p[0]);
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020013052 p += 2;
13053 } while (*p);
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013054
Eric Andersencb57d552001-06-28 07:25:16 +000013055 return 0;
13056}
13057
Denys Vlasenko0b883582016-12-23 16:49:07 +010013058#if ENABLE_FEATURE_SH_MATH
Eric Andersenc470f442003-07-28 09:56:35 +000013059/*
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020013060 * The let builtin. Partially stolen from GNU Bash, the Bourne Again SHell.
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +000013061 * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
Eric Andersen90898442003-08-06 11:20:52 +000013062 *
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +000013063 * Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
Eric Andersenc470f442003-07-28 09:56:35 +000013064 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013065static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013066letcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersenc470f442003-07-28 09:56:35 +000013067{
Denis Vlasenko68404f12008-03-17 09:00:54 +000013068 arith_t i;
Eric Andersenc470f442003-07-28 09:56:35 +000013069
Denis Vlasenko68404f12008-03-17 09:00:54 +000013070 argv++;
13071 if (!*argv)
Denis Vlasenkob012b102007-02-19 22:43:01 +000013072 ash_msg_and_raise_error("expression expected");
Denis Vlasenko68404f12008-03-17 09:00:54 +000013073 do {
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +000013074 i = ash_arith(*argv);
Denis Vlasenko68404f12008-03-17 09:00:54 +000013075 } while (*++argv);
Eric Andersenc470f442003-07-28 09:56:35 +000013076
Denis Vlasenkod9e15f22006-11-27 16:49:55 +000013077 return !i;
Eric Andersenc470f442003-07-28 09:56:35 +000013078}
Eric Andersenc470f442003-07-28 09:56:35 +000013079#endif
Eric Andersen74bcd162001-07-30 21:41:37 +000013080
Eric Andersenc470f442003-07-28 09:56:35 +000013081/*
Denis Vlasenko59f351c2008-03-25 00:07:12 +000013082 * The read builtin. Options:
13083 * -r Do not interpret '\' specially
13084 * -s Turn off echo (tty only)
13085 * -n NCHARS Read NCHARS max
13086 * -p PROMPT Display PROMPT on stderr (if input is from tty)
13087 * -t SECONDS Timeout after SECONDS (tty or pipe only)
13088 * -u FD Read from given FD instead of fd 0
Eric Andersenc470f442003-07-28 09:56:35 +000013089 * This uses unbuffered input, which may be avoidable in some cases.
Denis Vlasenko59f351c2008-03-25 00:07:12 +000013090 * TODO: bash also has:
13091 * -a ARRAY Read into array[0],[1],etc
13092 * -d DELIM End on DELIM char, not newline
13093 * -e Use line editing (tty only)
Eric Andersenc470f442003-07-28 09:56:35 +000013094 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013095static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013096readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000013097{
Denys Vlasenko73067272010-01-12 22:11:24 +010013098 char *opt_n = NULL;
13099 char *opt_p = NULL;
13100 char *opt_t = NULL;
13101 char *opt_u = NULL;
13102 int read_flags = 0;
13103 const char *r;
Eric Andersenc470f442003-07-28 09:56:35 +000013104 int i;
13105
Denys Vlasenko73067272010-01-12 22:11:24 +010013106 while ((i = nextopt("p:u:rt:n:s")) != '\0') {
Denis Vlasenkobf0a2012006-12-26 10:42:51 +000013107 switch (i) {
Paul Fox02eb9342005-09-07 16:56:02 +000013108 case 'p':
Denys Vlasenko73067272010-01-12 22:11:24 +010013109 opt_p = optionarg;
Paul Fox02eb9342005-09-07 16:56:02 +000013110 break;
Paul Fox02eb9342005-09-07 16:56:02 +000013111 case 'n':
Denys Vlasenko73067272010-01-12 22:11:24 +010013112 opt_n = optionarg;
Paul Fox02eb9342005-09-07 16:56:02 +000013113 break;
13114 case 's':
Denys Vlasenko73067272010-01-12 22:11:24 +010013115 read_flags |= BUILTIN_READ_SILENT;
Paul Fox02eb9342005-09-07 16:56:02 +000013116 break;
Paul Fox02eb9342005-09-07 16:56:02 +000013117 case 't':
Denys Vlasenko73067272010-01-12 22:11:24 +010013118 opt_t = optionarg;
Paul Fox02eb9342005-09-07 16:56:02 +000013119 break;
Paul Fox02eb9342005-09-07 16:56:02 +000013120 case 'r':
Denys Vlasenko73067272010-01-12 22:11:24 +010013121 read_flags |= BUILTIN_READ_RAW;
Paul Fox02eb9342005-09-07 16:56:02 +000013122 break;
Denis Vlasenko59f351c2008-03-25 00:07:12 +000013123 case 'u':
Denys Vlasenko73067272010-01-12 22:11:24 +010013124 opt_u = optionarg;
Denis Vlasenko59f351c2008-03-25 00:07:12 +000013125 break;
Paul Fox02eb9342005-09-07 16:56:02 +000013126 default:
13127 break;
13128 }
Eric Andersenc470f442003-07-28 09:56:35 +000013129 }
Paul Fox02eb9342005-09-07 16:56:02 +000013130
Denys Vlasenko9e71e3c2012-09-06 13:28:10 +020013131 /* "read -s" needs to save/restore termios, can't allow ^C
13132 * to jump out of it.
13133 */
13134 INT_OFF;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020013135 r = shell_builtin_read(setvar0,
Denys Vlasenko73067272010-01-12 22:11:24 +010013136 argptr,
13137 bltinlookup("IFS"), /* can be NULL */
13138 read_flags,
13139 opt_n,
13140 opt_p,
13141 opt_t,
13142 opt_u
13143 );
Denys Vlasenko9e71e3c2012-09-06 13:28:10 +020013144 INT_ON;
Denis Vlasenko46aeab92009-03-31 19:18:17 +000013145
Denys Vlasenko73067272010-01-12 22:11:24 +010013146 if ((uintptr_t)r > 1)
13147 ash_msg_and_raise_error(r);
Denis Vlasenko037576d2007-10-20 18:30:38 +000013148
Denys Vlasenko73067272010-01-12 22:11:24 +010013149 return (uintptr_t)r;
Eric Andersenc470f442003-07-28 09:56:35 +000013150}
13151
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013152static int FAST_FUNC
Denys Vlasenko6283f982015-10-07 16:56:20 +020013153umaskcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000013154{
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013155 static const char permuser[3] ALIGN1 = "ogu";
Eric Andersenc470f442003-07-28 09:56:35 +000013156
Eric Andersenc470f442003-07-28 09:56:35 +000013157 mode_t mask;
Eric Andersenc470f442003-07-28 09:56:35 +000013158 int symbolic_mode = 0;
13159
13160 while (nextopt("S") != '\0') {
13161 symbolic_mode = 1;
13162 }
13163
Denis Vlasenkob012b102007-02-19 22:43:01 +000013164 INT_OFF;
Eric Andersenc470f442003-07-28 09:56:35 +000013165 mask = umask(0);
13166 umask(mask);
Denis Vlasenkob012b102007-02-19 22:43:01 +000013167 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +000013168
Denys Vlasenko6283f982015-10-07 16:56:20 +020013169 if (*argptr == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +000013170 if (symbolic_mode) {
Denys Vlasenko005c4922015-10-10 20:17:12 +020013171 char buf[sizeof(",u=rwx,g=rwx,o=rwx")];
Eric Andersenc470f442003-07-28 09:56:35 +000013172 char *p = buf;
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013173 int i;
Eric Andersenc470f442003-07-28 09:56:35 +000013174
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013175 i = 2;
13176 for (;;) {
Denys Vlasenko005c4922015-10-10 20:17:12 +020013177 *p++ = ',';
Eric Andersenc470f442003-07-28 09:56:35 +000013178 *p++ = permuser[i];
13179 *p++ = '=';
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013180 /* mask is 0..0uuugggooo. i=2 selects uuu bits */
Denys Vlasenko005c4922015-10-10 20:17:12 +020013181 if (!(mask & 0400)) *p++ = 'r';
13182 if (!(mask & 0200)) *p++ = 'w';
13183 if (!(mask & 0100)) *p++ = 'x';
13184 mask <<= 3;
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013185 if (--i < 0)
13186 break;
Eric Andersenc470f442003-07-28 09:56:35 +000013187 }
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013188 *p = '\0';
Denys Vlasenko005c4922015-10-10 20:17:12 +020013189 puts(buf + 1);
Eric Andersenc470f442003-07-28 09:56:35 +000013190 } else {
Denys Vlasenkoec046f72015-10-07 17:57:53 +020013191 out1fmt("%04o\n", mask);
Eric Andersenc470f442003-07-28 09:56:35 +000013192 }
13193 } else {
Denys Vlasenko6283f982015-10-07 16:56:20 +020013194 char *modestr = *argptr;
13195 /* numeric umasks are taken as-is */
13196 /* symbolic umasks are inverted: "umask a=rx" calls umask(222) */
13197 if (!isdigit(modestr[0]))
13198 mask ^= 0777;
Denys Vlasenko5711a2a2015-10-07 17:55:33 +020013199 mask = bb_parse_mode(modestr, mask);
13200 if ((unsigned)mask > 0777) {
Denys Vlasenko6283f982015-10-07 16:56:20 +020013201 ash_msg_and_raise_error("illegal mode: %s", modestr);
Eric Andersenc470f442003-07-28 09:56:35 +000013202 }
Denys Vlasenko6283f982015-10-07 16:56:20 +020013203 if (!isdigit(modestr[0]))
13204 mask ^= 0777;
13205 umask(mask);
Eric Andersenc470f442003-07-28 09:56:35 +000013206 }
13207 return 0;
13208}
13209
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013210static int FAST_FUNC
Denys Vlasenkof3c742f2010-03-06 20:12:00 +010013211ulimitcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersenc470f442003-07-28 09:56:35 +000013212{
Denys Vlasenkof3c742f2010-03-06 20:12:00 +010013213 return shell_builtin_ulimit(argv);
Eric Andersenc470f442003-07-28 09:56:35 +000013214}
13215
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013216/* ============ main() and helpers */
13217
13218/*
13219 * Called to exit the shell.
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013220 */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013221static void
13222exitshell(void)
13223{
13224 struct jmploc loc;
13225 char *p;
13226 int status;
13227
Denys Vlasenkobede2152011-09-04 16:12:33 +020013228#if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT
13229 save_history(line_input_state);
13230#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013231 status = exitstatus;
13232 TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
13233 if (setjmp(loc.loc)) {
Denis Vlasenko7f88e342009-03-19 03:36:18 +000013234 if (exception_type == EXEXIT)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013235 status = exitstatus;
13236 goto out;
13237 }
13238 exception_handler = &loc;
13239 p = trap[0];
13240 if (p) {
13241 trap[0] = NULL;
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020013242 evalskip = 0;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013243 evalstring(p, 0);
Denys Vlasenkof37e1152016-10-07 03:17:28 +020013244 /*free(p); - we'll exit soon */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013245 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013246 out:
Denys Vlasenkof37e1152016-10-07 03:17:28 +020013247 /* dash wraps setjobctl(0) in "if (setjmp(loc.loc) == 0) {...}".
13248 * our setjobctl(0) does not panic if tcsetpgrp fails inside it.
13249 */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013250 setjobctl(0);
Denys Vlasenkocaee80c2016-10-25 20:49:53 +020013251 flush_stdout_stderr();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013252 _exit(status);
13253 /* NOTREACHED */
13254}
13255
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +000013256static void
13257init(void)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013258{
Denys Vlasenko82dd14a2010-05-17 10:10:01 +020013259 /* we will never free this */
13260 basepf.next_to_pgetc = basepf.buf = ckmalloc(IBUFSIZ);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013261
Denys Vlasenko458c1f22016-10-27 23:51:19 +020013262 sigmode[SIGCHLD - 1] = S_DFL;
13263 setsignal(SIGCHLD);
13264
Denys Vlasenko7a7b0342009-12-04 04:18:31 +010013265 /* bash re-enables SIGHUP which is SIG_IGNed on entry.
13266 * Try: "trap '' HUP; bash; echo RET" and type "kill -HUP $$"
13267 */
Denys Vlasenkocacb2cd2010-10-05 00:13:02 +020013268 signal(SIGHUP, SIG_DFL);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013269
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013270 {
13271 char **envp;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013272 const char *p;
13273 struct stat st1, st2;
13274
13275 initvar();
13276 for (envp = environ; envp && *envp; envp++) {
Denys Vlasenkob6838b52016-09-30 11:33:47 +020013277 p = endofname(*envp);
13278 if (p != *envp && *p == '=') {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013279 setvareq(*envp, VEXPORT|VTEXTFIXED);
13280 }
13281 }
13282
Denys Vlasenkoe627ac92016-09-30 14:36:59 +020013283 setvareq((char*)defoptindvar, VTEXTFIXED);
13284
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020013285 setvar0("PPID", utoa(getppid()));
Bernhard Reutner-Fischer80f8cdf2013-11-08 14:25:24 +010013286#if ENABLE_ASH_BASH_COMPAT
13287 p = lookupvar("SHLVL");
Denys Vlasenko5680e982014-01-07 16:12:48 +010013288 setvar("SHLVL", utoa((p ? atoi(p) : 0) + 1), VEXPORT);
Denys Vlasenko3fa97af2014-04-15 11:43:29 +020013289 if (!lookupvar("HOSTNAME")) {
13290 struct utsname uts;
13291 uname(&uts);
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020013292 setvar0("HOSTNAME", uts.nodename);
Denys Vlasenko3fa97af2014-04-15 11:43:29 +020013293 }
Bernhard Reutner-Fischer80f8cdf2013-11-08 14:25:24 +010013294#endif
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013295 p = lookupvar("PWD");
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013296 if (p) {
Denys Vlasenkoef159702016-09-01 11:16:22 +020013297 if (p[0] != '/' || stat(p, &st1) || stat(".", &st2)
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013298 || st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino
13299 ) {
Denys Vlasenkoef159702016-09-01 11:16:22 +020013300 p = NULL;
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013301 }
13302 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013303 setpwd(p, 0);
13304 }
13305}
13306
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013307
13308//usage:#define ash_trivial_usage
Denys Vlasenko6b6af532011-03-08 10:24:17 +010013309//usage: "[-/+OPTIONS] [-/+o OPT]... [-c 'SCRIPT' [ARG0 [ARGS]] / FILE [ARGS]]"
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013310//usage:#define ash_full_usage "\n\n"
13311//usage: "Unix shell interpreter"
13312
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013313/*
13314 * Process the shell command line arguments.
13315 */
13316static void
Denis Vlasenko68404f12008-03-17 09:00:54 +000013317procargs(char **argv)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013318{
13319 int i;
13320 const char *xminusc;
13321 char **xargv;
13322
13323 xargv = argv;
13324 arg0 = xargv[0];
Denis Vlasenko68404f12008-03-17 09:00:54 +000013325 /* if (xargv[0]) - mmm, this is always true! */
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013326 xargv++;
13327 for (i = 0; i < NOPTS; i++)
13328 optlist[i] = 2;
13329 argptr = xargv;
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013330 if (options(/*cmdline:*/ 1)) {
Denis Vlasenko28bf6712008-02-14 15:01:47 +000013331 /* it already printed err message */
13332 raise_exception(EXERROR);
13333 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013334 xargv = argptr;
13335 xminusc = minusc;
13336 if (*xargv == NULL) {
13337 if (xminusc)
13338 ash_msg_and_raise_error(bb_msg_requires_arg, "-c");
13339 sflag = 1;
13340 }
13341 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
13342 iflag = 1;
13343 if (mflag == 2)
13344 mflag = iflag;
13345 for (i = 0; i < NOPTS; i++)
13346 if (optlist[i] == 2)
13347 optlist[i] = 0;
13348#if DEBUG == 2
13349 debug = 1;
13350#endif
13351 /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
13352 if (xminusc) {
13353 minusc = *xargv++;
13354 if (*xargv)
13355 goto setarg0;
13356 } else if (!sflag) {
13357 setinputfile(*xargv, 0);
13358 setarg0:
13359 arg0 = *xargv++;
13360 commandname = arg0;
13361 }
13362
13363 shellparam.p = xargv;
13364#if ENABLE_ASH_GETOPTS
13365 shellparam.optind = 1;
13366 shellparam.optoff = -1;
13367#endif
Denis Vlasenko01631112007-12-16 17:20:38 +000013368 /* assert(shellparam.malloced == 0 && shellparam.nparam == 0); */
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013369 while (*xargv) {
13370 shellparam.nparam++;
13371 xargv++;
13372 }
13373 optschanged();
13374}
13375
13376/*
Denys Vlasenko2eb0a7e2016-10-27 11:28:59 +020013377 * Read /etc/profile, ~/.profile, $ENV.
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013378 */
13379static void
13380read_profile(const char *name)
13381{
Denys Vlasenko2eb0a7e2016-10-27 11:28:59 +020013382 name = expandstr(name);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013383 if (setinputfile(name, INPUT_PUSH_FILE | INPUT_NOFILE_OK) < 0)
13384 return;
Denys Vlasenko0840c912016-10-01 15:27:44 +020013385 cmdloop(0);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013386 popfile();
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013387}
13388
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013389/*
13390 * This routine is called when an error or an interrupt occurs in an
13391 * interactive shell and control is returned to the main command loop.
Denys Vlasenko5ac04f22016-10-27 14:46:50 +020013392 * (In dash, this function is auto-generated by build machinery).
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013393 */
13394static void
13395reset(void)
13396{
13397 /* from eval.c: */
13398 evalskip = 0;
13399 loopnest = 0;
Denys Vlasenko5ac04f22016-10-27 14:46:50 +020013400
13401 /* from expand.c: */
13402 ifsfree();
13403
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013404 /* from input.c: */
Denis Vlasenko41eb3002008-11-28 03:42:31 +000013405 g_parsefile->left_in_buffer = 0;
13406 g_parsefile->left_in_line = 0; /* clear input buffer */
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013407 popallfiles();
Denys Vlasenko5ac04f22016-10-27 14:46:50 +020013408
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013409 /* from redir.c: */
Denys Vlasenkoe19923f2016-10-26 15:38:44 +020013410 while (redirlist)
13411 popredir(/*drop:*/ 0, /*restore:*/ 0);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013412}
13413
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013414#if PROFILE
13415static short profile_buf[16384];
13416extern int etext();
13417#endif
13418
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013419/*
13420 * Main routine. We initialize things, parse the arguments, execute
13421 * profiles if we're a login shell, and then call cmdloop to execute
13422 * commands. The setjmp call sets up the location to jump to when an
13423 * exception occurs. When an exception occurs the variable "state"
13424 * is used to figure out how far we had gotten.
13425 */
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +000013426int ash_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013427int ash_main(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013428{
Denis Vlasenko4e12b1a2008-12-23 23:36:47 +000013429 volatile smallint state;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013430 struct jmploc jmploc;
13431 struct stackmark smark;
13432
Denis Vlasenko01631112007-12-16 17:20:38 +000013433 /* Initialize global data */
13434 INIT_G_misc();
13435 INIT_G_memstack();
13436 INIT_G_var();
Denis Vlasenkoee87ebf2007-12-21 22:18:16 +000013437#if ENABLE_ASH_ALIAS
Denis Vlasenko01631112007-12-16 17:20:38 +000013438 INIT_G_alias();
Denis Vlasenkoee87ebf2007-12-21 22:18:16 +000013439#endif
Denis Vlasenko01631112007-12-16 17:20:38 +000013440 INIT_G_cmdtable();
13441
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013442#if PROFILE
13443 monitor(4, etext, profile_buf, sizeof(profile_buf), 50);
13444#endif
13445
13446#if ENABLE_FEATURE_EDITING
13447 line_input_state = new_line_input_t(FOR_SHELL | WITH_PATH_LOOKUP);
13448#endif
13449 state = 0;
13450 if (setjmp(jmploc.loc)) {
Denis Vlasenko7f88e342009-03-19 03:36:18 +000013451 smallint e;
Denis Vlasenko4e12b1a2008-12-23 23:36:47 +000013452 smallint s;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013453
13454 reset();
13455
Denis Vlasenko7f88e342009-03-19 03:36:18 +000013456 e = exception_type;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013457 s = state;
Denys Vlasenkob563f622010-09-25 17:15:13 +020013458 if (e == EXEXIT || s == 0 || iflag == 0 || shlvl) {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013459 exitshell();
Denys Vlasenkob563f622010-09-25 17:15:13 +020013460 }
13461 if (e == EXINT) {
Denys Vlasenko9c541002015-10-07 15:44:36 +020013462 newline_and_flush(stderr);
Denys Vlasenkob563f622010-09-25 17:15:13 +020013463 }
Denis Vlasenko7f88e342009-03-19 03:36:18 +000013464
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013465 popstackmark(&smark);
13466 FORCE_INT_ON; /* enable interrupts */
13467 if (s == 1)
13468 goto state1;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000013469 if (s == 2)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013470 goto state2;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000013471 if (s == 3)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013472 goto state3;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000013473 goto state4;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013474 }
13475 exception_handler = &jmploc;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013476 rootpid = getpid();
13477
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013478 init();
13479 setstackmark(&smark);
Denis Vlasenko68404f12008-03-17 09:00:54 +000013480 procargs(argv);
Denys Vlasenko474ed062016-10-30 18:30:29 +010013481#if DEBUG
13482 TRACE(("Shell args: "));
13483 trace_puts_args(argv);
13484#endif
Denis Vlasenko68404f12008-03-17 09:00:54 +000013485
Denys Vlasenko6088e132010-12-25 23:58:42 +010013486 if (argv[0] && argv[0][0] == '-')
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013487 isloginsh = 1;
13488 if (isloginsh) {
Stefan Hellermann4ef14392013-03-15 02:45:50 +010013489 const char *hp;
13490
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013491 state = 1;
13492 read_profile("/etc/profile");
13493 state1:
13494 state = 2;
Stefan Hellermann4ef14392013-03-15 02:45:50 +010013495 hp = lookupvar("HOME");
Denys Vlasenko2eb0a7e2016-10-27 11:28:59 +020013496 if (hp)
13497 read_profile("$HOME/.profile");
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013498 }
13499 state2:
13500 state = 3;
13501 if (
13502#ifndef linux
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013503 getuid() == geteuid() && getgid() == getegid() &&
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013504#endif
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013505 iflag
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013506 ) {
Denys Vlasenko2eb0a7e2016-10-27 11:28:59 +020013507 const char *shinit = lookupvar("ENV");
13508 if (shinit != NULL && *shinit != '\0')
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013509 read_profile(shinit);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013510 }
Denys Vlasenko2eb0a7e2016-10-27 11:28:59 +020013511 popstackmark(&smark);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013512 state3:
13513 state = 4;
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000013514 if (minusc) {
13515 /* evalstring pushes parsefile stack.
13516 * Ensure we don't falsely claim that 0 (stdin)
Denis Vlasenko5368ad52009-03-20 10:20:08 +000013517 * is one of stacked source fds.
13518 * Testcase: ash -c 'exec 1>&0' must not complain. */
Denys Vlasenko79b3d422010-06-03 04:29:08 +020013519 // if (!sflag) g_parsefile->pf_fd = -1;
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +020013520 // ^^ not necessary since now we special-case fd 0
13521 // in is_hidden_fd() to not be considered "hidden fd"
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013522 evalstring(minusc, 0);
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000013523 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013524
13525 if (sflag || minusc == NULL) {
Denys Vlasenko4840ae82011-09-04 15:28:03 +020013526#if MAX_HISTORY > 0 && ENABLE_FEATURE_EDITING_SAVEHISTORY
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +000013527 if (iflag) {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013528 const char *hp = lookupvar("HISTFILE");
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010013529 if (!hp) {
13530 hp = lookupvar("HOME");
Stefan Hellermann4ef14392013-03-15 02:45:50 +010013531 if (hp) {
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010013532 hp = concat_path_file(hp, ".ash_history");
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020013533 setvar0("HISTFILE", hp);
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010013534 free((char*)hp);
13535 hp = lookupvar("HISTFILE");
13536 }
13537 }
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000013538 if (hp)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013539 line_input_state->hist_file = hp;
Denys Vlasenko2c4de5b2011-03-31 13:16:52 +020013540# if ENABLE_FEATURE_SH_HISTFILESIZE
13541 hp = lookupvar("HISTFILESIZE");
13542 line_input_state->max_history = size_from_HISTFILESIZE(hp);
13543# endif
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013544 }
13545#endif
13546 state4: /* XXX ??? - why isn't this before the "if" statement */
13547 cmdloop(1);
13548 }
13549#if PROFILE
13550 monitor(0);
13551#endif
13552#ifdef GPROF
13553 {
13554 extern void _mcleanup(void);
13555 _mcleanup();
13556 }
13557#endif
Denys Vlasenkob563f622010-09-25 17:15:13 +020013558 TRACE(("End of main reached\n"));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013559 exitshell();
13560 /* NOTREACHED */
13561}
13562
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013563
Eric Andersendf82f612001-06-28 07:46:40 +000013564/*-
13565 * Copyright (c) 1989, 1991, 1993, 1994
Eric Andersen2870d962001-07-02 17:27:21 +000013566 * The Regents of the University of California. All rights reserved.
Eric Andersendf82f612001-06-28 07:46:40 +000013567 *
13568 * This code is derived from software contributed to Berkeley by
13569 * Kenneth Almquist.
13570 *
13571 * Redistribution and use in source and binary forms, with or without
13572 * modification, are permitted provided that the following conditions
13573 * are met:
13574 * 1. Redistributions of source code must retain the above copyright
13575 * notice, this list of conditions and the following disclaimer.
13576 * 2. Redistributions in binary form must reproduce the above copyright
13577 * notice, this list of conditions and the following disclaimer in the
13578 * documentation and/or other materials provided with the distribution.
"Vladimir N. Oleynik"ddc280e2005-12-15 12:01:49 +000013579 * 3. Neither the name of the University nor the names of its contributors
Eric Andersendf82f612001-06-28 07:46:40 +000013580 * may be used to endorse or promote products derived from this software
13581 * without specific prior written permission.
13582 *
13583 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
13584 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
13585 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
13586 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
13587 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
13588 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
13589 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
13590 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
13591 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
13592 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
13593 * SUCH DAMAGE.
13594 */