blob: 9c46a93e0d4e5303e34fb72a98ff0b83f4365577 [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: help
39//config: Compile ash for reduced size at the price of speed.
40//config:
41//config:config ASH_INTERNAL_GLOB
42//config: bool "Use internal glob() implementation"
Denys Vlasenko326edc32016-12-22 14:36:49 +010043//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 +010044//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
Denys Vlasenko514b51d2016-10-01 14:33:08 +020045//config: help
46//config: Do not use glob() function from libc, use internal implementation.
47//config: Use this if you are getting "glob.h: No such file or directory"
48//config: or similar build errors.
49//config:
50//config:config ASH_RANDOM_SUPPORT
51//config: bool "Pseudorandom generator and $RANDOM variable"
52//config: default y
Denys Vlasenko0b883582016-12-23 16:49:07 +010053//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
Denys Vlasenko514b51d2016-10-01 14:33:08 +020054//config: help
55//config: Enable pseudorandom generator and dynamic variable "$RANDOM".
56//config: Each read of "$RANDOM" will generate a new pseudorandom value.
57//config: You can reset the generator by using a specified start value.
58//config: After "unset RANDOM" the generator will switch off and this
59//config: variable will no longer have special treatment.
60//config:
61//config:config ASH_EXPAND_PRMT
62//config: bool "Expand prompt string"
63//config: default y
Denys Vlasenko0b883582016-12-23 16:49:07 +010064//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
Denys Vlasenko514b51d2016-10-01 14:33:08 +020065//config: help
66//config: "PS#" may contain volatile content, such as backquote commands.
67//config: This option recreates the prompt string from the environment
68//config: variable each time it is displayed.
69//config:
Denys Vlasenko771f1992010-07-16 14:31:34 +020070//config:config ASH_BASH_COMPAT
71//config: bool "bash-compatible extensions"
72//config: default y
Denys Vlasenko0b883582016-12-23 16:49:07 +010073//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
Denys Vlasenko771f1992010-07-16 14:31:34 +020074//config: help
75//config: Enable bash-compatible extensions.
76//config:
Denys Vlasenko046341e2011-02-04 17:53:59 +010077//config:config ASH_IDLE_TIMEOUT
78//config: bool "Idle timeout variable"
79//config: default n
Denys Vlasenko0b883582016-12-23 16:49:07 +010080//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
Denys Vlasenko046341e2011-02-04 17:53:59 +010081//config: help
Denys Vlasenko66c5b122011-02-08 05:07:02 +010082//config: Enables bash-like auto-logout after $TMOUT seconds of idle time.
Denys Vlasenko046341e2011-02-04 17:53:59 +010083//config:
Denys Vlasenko771f1992010-07-16 14:31:34 +020084//config:config ASH_JOB_CONTROL
85//config: bool "Job control"
86//config: default y
Denys Vlasenko0b883582016-12-23 16:49:07 +010087//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
Denys Vlasenko771f1992010-07-16 14:31:34 +020088//config: help
89//config: Enable job control in the ash shell.
90//config:
91//config:config ASH_ALIAS
Denys Vlasenko8c52f802011-02-04 17:36:21 +010092//config: bool "Alias support"
Denys Vlasenko771f1992010-07-16 14:31:34 +020093//config: default y
Denys Vlasenko0b883582016-12-23 16:49:07 +010094//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
Denys Vlasenko771f1992010-07-16 14:31:34 +020095//config: help
96//config: Enable alias support in the ash shell.
97//config:
98//config:config ASH_GETOPTS
99//config: bool "Builtin getopt to parse positional parameters"
100//config: default y
Denys Vlasenko0b883582016-12-23 16:49:07 +0100101//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
Denys Vlasenko771f1992010-07-16 14:31:34 +0200102//config: help
Denys Vlasenko8c52f802011-02-04 17:36:21 +0100103//config: Enable support for getopts builtin in ash.
Denys Vlasenko771f1992010-07-16 14:31:34 +0200104//config:
105//config:config ASH_BUILTIN_ECHO
106//config: bool "Builtin version of 'echo'"
107//config: default y
Denys Vlasenko0b883582016-12-23 16:49:07 +0100108//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
Denys Vlasenko771f1992010-07-16 14:31:34 +0200109//config: help
Denys Vlasenko8c52f802011-02-04 17:36:21 +0100110//config: Enable support for echo builtin in ash.
Denys Vlasenko771f1992010-07-16 14:31:34 +0200111//config:
112//config:config ASH_BUILTIN_PRINTF
113//config: bool "Builtin version of 'printf'"
114//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: help
Denys Vlasenko8c52f802011-02-04 17:36:21 +0100117//config: Enable support for printf builtin in ash.
Denys Vlasenko771f1992010-07-16 14:31:34 +0200118//config:
119//config:config ASH_BUILTIN_TEST
120//config: bool "Builtin version of 'test'"
121//config: default y
Denys Vlasenko0b883582016-12-23 16:49:07 +0100122//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
Denys Vlasenko771f1992010-07-16 14:31:34 +0200123//config: help
Denys Vlasenko8c52f802011-02-04 17:36:21 +0100124//config: Enable support for test builtin in ash.
Denys Vlasenko771f1992010-07-16 14:31:34 +0200125//config:
Denys Vlasenko2ec34962014-09-08 16:52:39 +0200126//config:config ASH_HELP
127//config: bool "help builtin"
128//config: default y
Denys Vlasenko0b883582016-12-23 16:49:07 +0100129//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
Denys Vlasenko2ec34962014-09-08 16:52:39 +0200130//config: help
131//config: Enable help builtin in ash.
132//config:
Denys Vlasenko771f1992010-07-16 14:31:34 +0200133//config:config ASH_CMDCMD
134//config: bool "'command' command to override shell builtins"
135//config: default y
Denys Vlasenko0b883582016-12-23 16:49:07 +0100136//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
Denys Vlasenko771f1992010-07-16 14:31:34 +0200137//config: help
138//config: Enable support for the ash 'command' builtin, which allows
139//config: you to run the specified command with the specified arguments,
140//config: even when there is an ash builtin command with the same name.
141//config:
142//config:config ASH_MAIL
143//config: bool "Check for new mail on interactive shells"
Denys Vlasenko326edc32016-12-22 14:36:49 +0100144//config: default y
Denys Vlasenko0b883582016-12-23 16:49:07 +0100145//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
Denys Vlasenko771f1992010-07-16 14:31:34 +0200146//config: help
Denys Vlasenko8c52f802011-02-04 17:36:21 +0100147//config: Enable "check for new mail" function in the ash shell.
Kang-Che Sung6cd02942017-01-06 17:02:03 +0100148//config:
149//config:endif # ash options
Denys Vlasenko771f1992010-07-16 14:31:34 +0200150
Denys Vlasenko20704f02011-03-23 17:59:27 +0100151//applet:IF_ASH(APPLET(ash, BB_DIR_BIN, BB_SUID_DROP))
Denys Vlasenko0b883582016-12-23 16:49:07 +0100152//applet:IF_SH_IS_ASH(APPLET_ODDNAME(sh, ash, BB_DIR_BIN, BB_SUID_DROP, ash))
153//applet:IF_BASH_IS_ASH(APPLET_ODDNAME(bash, ash, BB_DIR_BIN, BB_SUID_DROP, ash))
Denys Vlasenko20704f02011-03-23 17:59:27 +0100154
155//kbuild:lib-$(CONFIG_ASH) += ash.o ash_ptr_hack.o shell_common.o
Denys Vlasenko0b883582016-12-23 16:49:07 +0100156//kbuild:lib-$(CONFIG_SH_IS_ASH) += ash.o ash_ptr_hack.o shell_common.o
157//kbuild:lib-$(CONFIG_BASH_IS_ASH) += ash.o ash_ptr_hack.o shell_common.o
Denys Vlasenko20704f02011-03-23 17:59:27 +0100158//kbuild:lib-$(CONFIG_ASH_RANDOM_SUPPORT) += random.o
159
Denys Vlasenko67047462016-12-22 15:21:58 +0100160/*
161 * The following should be set to reflect the type of system you have:
162 * JOBS -> 1 if you have Berkeley job control, 0 otherwise.
163 * define SYSV if you are running under System V.
164 * define DEBUG=1 to compile in debugging ('set -o debug' to turn on)
165 * define DEBUG=2 to compile in and turn on debugging.
166 *
167 * When debugging is on (DEBUG is 1 and "set -o debug" was executed),
168 * debugging info will be written to ./trace and a quit signal
169 * will generate a core dump.
170 */
171#define DEBUG 0
172/* Tweak debug output verbosity here */
173#define DEBUG_TIME 0
174#define DEBUG_PID 1
175#define DEBUG_SIG 1
176#define DEBUG_INTONOFF 0
177
178#define PROFILE 0
179
180#define JOBS ENABLE_ASH_JOB_CONTROL
181
182#include <setjmp.h>
183#include <fnmatch.h>
184#include <sys/times.h>
185#include <sys/utsname.h> /* for setting $HOSTNAME */
186
187#include "busybox.h" /* for applet_names */
188
189#if defined(__ANDROID_API__) && __ANDROID_API__ <= 24
190/* Bionic at least up to version 24 has no glob() */
191# undef ENABLE_ASH_INTERNAL_GLOB
192# define ENABLE_ASH_INTERNAL_GLOB 1
193#endif
194
195#if !ENABLE_ASH_INTERNAL_GLOB && defined(__UCLIBC__)
196# error uClibc glob() is buggy, use ASH_INTERNAL_GLOB.
197# error The bug is: for "$PWD"/<pattern> ash will escape e.g. dashes in "$PWD"
198# error with backslash, even ones which do not need to be: "/a-b" -> "/a\-b"
199# error glob() should unbackslash them and match. uClibc does not unbackslash,
200# error fails to match dirname, subsequently not expanding <pattern> in it.
201// Testcase:
202// if (glob("/etc/polkit\\-1", 0, NULL, &pglob)) - this returns 0 on uclibc, no bug
203// if (glob("/etc/polkit\\-1/*", 0, NULL, &pglob)) printf("uclibc bug!\n");
204#endif
205
206#if !ENABLE_ASH_INTERNAL_GLOB
207# include <glob.h>
208#endif
209
210#include "unicode.h"
211#include "shell_common.h"
Denys Vlasenko0b883582016-12-23 16:49:07 +0100212#if ENABLE_FEATURE_SH_MATH
Denys Vlasenko67047462016-12-22 15:21:58 +0100213# include "math.h"
214#endif
215#if ENABLE_ASH_RANDOM_SUPPORT
216# include "random.h"
217#else
218# define CLEAR_RANDOM_T(rnd) ((void)0)
219#endif
220
221#include "NUM_APPLETS.h"
222#if NUM_APPLETS == 1
223/* STANDALONE does not make sense, and won't compile */
224# undef CONFIG_FEATURE_SH_STANDALONE
225# undef ENABLE_FEATURE_SH_STANDALONE
226# undef IF_FEATURE_SH_STANDALONE
227# undef IF_NOT_FEATURE_SH_STANDALONE
228# define ENABLE_FEATURE_SH_STANDALONE 0
229# define IF_FEATURE_SH_STANDALONE(...)
230# define IF_NOT_FEATURE_SH_STANDALONE(...) __VA_ARGS__
231#endif
232
233#ifndef PIPE_BUF
234# define PIPE_BUF 4096 /* amount of buffering in a pipe */
235#endif
236
237#if !BB_MMU
238# error "Do not even bother, ash will not run on NOMMU machine"
239#endif
240
Denis Vlasenkob012b102007-02-19 22:43:01 +0000241
Denis Vlasenko01631112007-12-16 17:20:38 +0000242/* ============ Hash table sizes. Configurable. */
243
244#define VTABSIZE 39
245#define ATABSIZE 39
246#define CMDTABLESIZE 31 /* should be prime */
247
248
Denis Vlasenkob012b102007-02-19 22:43:01 +0000249/* ============ Shell options */
250
251static const char *const optletters_optnames[] = {
252 "e" "errexit",
253 "f" "noglob",
254 "I" "ignoreeof",
255 "i" "interactive",
256 "m" "monitor",
257 "n" "noexec",
258 "s" "stdin",
259 "x" "xtrace",
260 "v" "verbose",
261 "C" "noclobber",
262 "a" "allexport",
263 "b" "notify",
264 "u" "nounset",
Denys Vlasenkoe9ac32a2009-12-05 02:01:25 +0100265 "\0" "vi"
Michael Abbott359da5e2009-12-04 23:03:29 +0100266#if ENABLE_ASH_BASH_COMPAT
Denys Vlasenkoe9ac32a2009-12-05 02:01:25 +0100267 ,"\0" "pipefail"
Michael Abbott359da5e2009-12-04 23:03:29 +0100268#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +0000269#if DEBUG
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000270 ,"\0" "nolog"
271 ,"\0" "debug"
Denis Vlasenkob012b102007-02-19 22:43:01 +0000272#endif
273};
274
Denys Vlasenko285ad152009-12-04 23:02:27 +0100275#define optletters(n) optletters_optnames[n][0]
276#define optnames(n) (optletters_optnames[n] + 1)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000277
Denis Vlasenko80b8b392007-06-25 10:55:35 +0000278enum { NOPTS = ARRAY_SIZE(optletters_optnames) };
Denis Vlasenkob012b102007-02-19 22:43:01 +0000279
Eric Andersenc470f442003-07-28 09:56:35 +0000280
Denis Vlasenkob012b102007-02-19 22:43:01 +0000281/* ============ Misc data */
Eric Andersenc470f442003-07-28 09:56:35 +0000282
Denys Vlasenkoea8b2522010-06-02 12:57:26 +0200283#define msg_illnum "Illegal number: %s"
Denis Vlasenkoaa744452007-02-23 01:04:22 +0000284
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +0000285/*
Eric Andersenc470f442003-07-28 09:56:35 +0000286 * We enclose jmp_buf in a structure so that we can declare pointers to
287 * jump locations. The global variable handler contains the location to
Denis Vlasenkof1733952009-03-19 23:21:55 +0000288 * jump to when an exception occurs, and the global variable exception_type
Eric Andersenaff114c2004-04-14 17:51:38 +0000289 * contains a code identifying the exception. To implement nested
Eric Andersenc470f442003-07-28 09:56:35 +0000290 * exception handlers, the user should save the value of handler on entry
291 * to an inner scope, set handler to point to a jmploc structure for the
292 * inner scope, and restore handler on exit from the scope.
293 */
Eric Andersenc470f442003-07-28 09:56:35 +0000294struct jmploc {
295 jmp_buf loc;
296};
Denis Vlasenko01631112007-12-16 17:20:38 +0000297
298struct globals_misc {
Denys Vlasenko4d12e942016-10-01 16:03:11 +0200299 uint8_t exitstatus; /* exit status of last command */
300 uint8_t back_exitstatus;/* exit status of backquoted command */
301 smallint job_warning; /* user was warned about stopped jobs (can be 2, 1 or 0). */
302 int rootpid; /* pid of main shell */
Denis Vlasenko01631112007-12-16 17:20:38 +0000303 /* shell level: 0 for the main shell, 1 for its children, and so on */
304 int shlvl;
305#define rootshell (!shlvl)
306 char *minusc; /* argument to -c option */
307
308 char *curdir; // = nullstr; /* current working directory */
309 char *physdir; // = nullstr; /* physical working directory */
310
311 char *arg0; /* value of $0 */
312
313 struct jmploc *exception_handler;
Denis Vlasenko991a1da2008-02-10 19:02:53 +0000314
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200315 volatile int suppress_int; /* counter */
316 volatile /*sig_atomic_t*/ smallint pending_int; /* 1 = got SIGINT */
Denys Vlasenko458c1f22016-10-27 23:51:19 +0200317 volatile /*sig_atomic_t*/ smallint got_sigchld; /* 1 = got SIGCHLD */
Denys Vlasenko8f7b0242016-10-28 17:16:11 +0200318 volatile /*sig_atomic_t*/ smallint pending_sig; /* last pending signal */
Denis Vlasenko7f88e342009-03-19 03:36:18 +0000319 smallint exception_type; /* kind of exception (0..5) */
Denis Vlasenko01631112007-12-16 17:20:38 +0000320 /* exceptions */
Eric Andersenc470f442003-07-28 09:56:35 +0000321#define EXINT 0 /* SIGINT received */
322#define EXERROR 1 /* a generic error */
Eric Andersenc470f442003-07-28 09:56:35 +0000323#define EXEXIT 4 /* exit the shell */
Eric Andersen2870d962001-07-02 17:27:21 +0000324
Denis Vlasenko01631112007-12-16 17:20:38 +0000325 smallint isloginsh;
Denis Vlasenkob07a4962008-06-22 13:16:23 +0000326 char nullstr[1]; /* zero length string */
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000327
328 char optlist[NOPTS];
329#define eflag optlist[0]
330#define fflag optlist[1]
331#define Iflag optlist[2]
332#define iflag optlist[3]
333#define mflag optlist[4]
334#define nflag optlist[5]
335#define sflag optlist[6]
336#define xflag optlist[7]
337#define vflag optlist[8]
338#define Cflag optlist[9]
339#define aflag optlist[10]
340#define bflag optlist[11]
341#define uflag optlist[12]
342#define viflag optlist[13]
Michael Abbott359da5e2009-12-04 23:03:29 +0100343#if ENABLE_ASH_BASH_COMPAT
344# define pipefail optlist[14]
345#else
346# define pipefail 0
347#endif
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000348#if DEBUG
Michael Abbott359da5e2009-12-04 23:03:29 +0100349# define nolog optlist[14 + ENABLE_ASH_BASH_COMPAT]
350# define debug optlist[15 + ENABLE_ASH_BASH_COMPAT]
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000351#endif
352
353 /* trap handler commands */
Denis Vlasenko01631112007-12-16 17:20:38 +0000354 /*
355 * Sigmode records the current value of the signal handlers for the various
356 * modes. A value of zero means that the current handler is not known.
Denis Vlasenkof8535cc2008-12-03 10:36:26 +0000357 * S_HARD_IGN indicates that the signal was ignored on entry to the shell.
Denis Vlasenko01631112007-12-16 17:20:38 +0000358 */
359 char sigmode[NSIG - 1];
Denis Vlasenkof8535cc2008-12-03 10:36:26 +0000360#define S_DFL 1 /* default signal handling (SIG_DFL) */
361#define S_CATCH 2 /* signal is caught */
362#define S_IGN 3 /* signal is ignored (SIG_IGN) */
Denys Vlasenkoe5814a52016-07-16 18:33:55 +0200363#define S_HARD_IGN 4 /* signal is ignored permanently */
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +0000364
Denis Vlasenko01631112007-12-16 17:20:38 +0000365 /* indicates specified signal received */
Denis Vlasenko4b875702009-03-19 13:30:04 +0000366 uint8_t gotsig[NSIG - 1]; /* offset by 1: "signal" 0 is meaningless */
Denys Vlasenko238bf182010-05-18 15:49:07 +0200367 uint8_t may_have_traps; /* 0: definitely no traps are set, 1: some traps may be set */
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000368 char *trap[NSIG];
Denys Vlasenko21d87d42009-09-25 00:06:51 +0200369 char **trap_ptr; /* used only by "trap hack" */
Denis Vlasenko448d30e2008-06-27 00:24:11 +0000370
371 /* Rarely referenced stuff */
372#if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenko3ea2e822009-10-09 20:59:04 +0200373 random_t random_gen;
Denis Vlasenko448d30e2008-06-27 00:24:11 +0000374#endif
375 pid_t backgndpid; /* pid of last background process */
Denis Vlasenko01631112007-12-16 17:20:38 +0000376};
Denis Vlasenko574f2f42008-02-27 18:41:59 +0000377extern struct globals_misc *const ash_ptr_to_globals_misc;
378#define G_misc (*ash_ptr_to_globals_misc)
Denys Vlasenko4d12e942016-10-01 16:03:11 +0200379#define exitstatus (G_misc.exitstatus )
380#define back_exitstatus (G_misc.back_exitstatus )
381#define job_warning (G_misc.job_warning)
Denis Vlasenko26bc57d2008-06-27 00:29:34 +0000382#define rootpid (G_misc.rootpid )
383#define shlvl (G_misc.shlvl )
384#define minusc (G_misc.minusc )
385#define curdir (G_misc.curdir )
386#define physdir (G_misc.physdir )
387#define arg0 (G_misc.arg0 )
Denis Vlasenko01631112007-12-16 17:20:38 +0000388#define exception_handler (G_misc.exception_handler)
Denis Vlasenko7f88e342009-03-19 03:36:18 +0000389#define exception_type (G_misc.exception_type )
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200390#define suppress_int (G_misc.suppress_int )
391#define pending_int (G_misc.pending_int )
Denys Vlasenko458c1f22016-10-27 23:51:19 +0200392#define got_sigchld (G_misc.got_sigchld )
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200393#define pending_sig (G_misc.pending_sig )
Denis Vlasenko26bc57d2008-06-27 00:29:34 +0000394#define isloginsh (G_misc.isloginsh )
395#define nullstr (G_misc.nullstr )
396#define optlist (G_misc.optlist )
397#define sigmode (G_misc.sigmode )
398#define gotsig (G_misc.gotsig )
Denys Vlasenko238bf182010-05-18 15:49:07 +0200399#define may_have_traps (G_misc.may_have_traps )
Denis Vlasenko26bc57d2008-06-27 00:29:34 +0000400#define trap (G_misc.trap )
Denys Vlasenko21d87d42009-09-25 00:06:51 +0200401#define trap_ptr (G_misc.trap_ptr )
Denys Vlasenko3ea2e822009-10-09 20:59:04 +0200402#define random_gen (G_misc.random_gen )
Denis Vlasenko448d30e2008-06-27 00:24:11 +0000403#define backgndpid (G_misc.backgndpid )
Denis Vlasenko01631112007-12-16 17:20:38 +0000404#define INIT_G_misc() do { \
Denis Vlasenko574f2f42008-02-27 18:41:59 +0000405 (*(struct globals_misc**)&ash_ptr_to_globals_misc) = xzalloc(sizeof(G_misc)); \
406 barrier(); \
Denis Vlasenko01631112007-12-16 17:20:38 +0000407 curdir = nullstr; \
408 physdir = nullstr; \
Denys Vlasenko21d87d42009-09-25 00:06:51 +0200409 trap_ptr = trap; \
Denis Vlasenko01631112007-12-16 17:20:38 +0000410} while (0)
411
412
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000413/* ============ DEBUG */
414#if DEBUG
415static void trace_printf(const char *fmt, ...);
416static void trace_vprintf(const char *fmt, va_list va);
417# define TRACE(param) trace_printf param
418# define TRACEV(param) trace_vprintf param
Denis Vlasenko1bb3d7e2009-03-20 07:45:36 +0000419# define close(fd) do { \
420 int dfd = (fd); \
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +0000421 if (close(dfd) < 0) \
Denys Vlasenko883cea42009-07-11 15:31:59 +0200422 bb_error_msg("bug on %d: closing %d(0x%x)", \
Denis Vlasenko1bb3d7e2009-03-20 07:45:36 +0000423 __LINE__, dfd, dfd); \
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +0000424} while (0)
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000425#else
426# define TRACE(param)
427# define TRACEV(param)
428#endif
429
430
Denis Vlasenko559691a2008-10-05 18:39:31 +0000431/* ============ Utility functions */
Denys Vlasenko1961aea2013-02-26 00:36:53 +0100432#define is_name(c) ((c) == '_' || isalpha((unsigned char)(c)))
433#define is_in_name(c) ((c) == '_' || isalnum((unsigned char)(c)))
434
Denys Vlasenko37dc08b2016-10-02 04:38:07 +0200435static int
436isdigit_str9(const char *str)
Denis Vlasenko559691a2008-10-05 18:39:31 +0000437{
438 int maxlen = 9 + 1; /* max 9 digits: 999999999 */
439 while (--maxlen && isdigit(*str))
440 str++;
441 return (*str == '\0');
442}
Denis Vlasenko01631112007-12-16 17:20:38 +0000443
Denys Vlasenko37dc08b2016-10-02 04:38:07 +0200444static const char *
445var_end(const char *var)
Denys Vlasenko8837c5d2010-06-02 12:56:18 +0200446{
447 while (*var)
448 if (*var++ == '=')
449 break;
450 return var;
451}
452
Denis Vlasenko559691a2008-10-05 18:39:31 +0000453
454/* ============ Interrupts / exceptions */
Denys Vlasenko66c5b122011-02-08 05:07:02 +0100455
456static void exitshell(void) NORETURN;
457
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +0000458/*
Eric Andersen2870d962001-07-02 17:27:21 +0000459 * These macros allow the user to suspend the handling of interrupt signals
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +0000460 * over a period of time. This is similar to SIGHOLD or to sigblock, but
Eric Andersen2870d962001-07-02 17:27:21 +0000461 * much more efficient and portable. (But hacking the kernel is so much
462 * more fun than worrying about efficiency and portability. :-))
463 */
Denys Vlasenko06b11492016-11-04 16:43:18 +0100464#if DEBUG_INTONOFF
465# define INT_OFF do { \
466 TRACE(("%s:%d INT_OFF(%d)\n", __func__, __LINE__, suppress_int)); \
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200467 suppress_int++; \
Denys Vlasenkode892052016-10-02 01:49:13 +0200468 barrier(); \
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000469} while (0)
Denys Vlasenko06b11492016-11-04 16:43:18 +0100470#else
471# define INT_OFF do { \
472 suppress_int++; \
473 barrier(); \
474} while (0)
475#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +0000476
477/*
478 * Called to raise an exception. Since C doesn't include exceptions, we
479 * just do a longjmp to the exception handler. The type of exception is
Denis Vlasenko4b875702009-03-19 13:30:04 +0000480 * stored in the global variable "exception_type".
Denis Vlasenkob012b102007-02-19 22:43:01 +0000481 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000482static void raise_exception(int) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +0000483static void
484raise_exception(int e)
485{
486#if DEBUG
Denis Vlasenko2da584f2007-02-19 22:44:05 +0000487 if (exception_handler == NULL)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000488 abort();
489#endif
490 INT_OFF;
Denis Vlasenko7f88e342009-03-19 03:36:18 +0000491 exception_type = e;
Denis Vlasenko2da584f2007-02-19 22:44:05 +0000492 longjmp(exception_handler->loc, 1);
Denis Vlasenkob012b102007-02-19 22:43:01 +0000493}
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000494#if DEBUG
495#define raise_exception(e) do { \
496 TRACE(("raising exception %d on line %d\n", (e), __LINE__)); \
497 raise_exception(e); \
498} while (0)
499#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +0000500
501/*
Denys Vlasenkof37e1152016-10-07 03:17:28 +0200502 * Called when a SIGINT is received. (If the user specifies
Denis Vlasenkob012b102007-02-19 22:43:01 +0000503 * that SIGINT is to be trapped or ignored using the trap builtin, then
504 * this routine is not called.) Suppressint is nonzero when interrupts
505 * are held using the INT_OFF macro. (The test for iflag is just
506 * defensive programming.)
507 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000508static void raise_interrupt(void) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +0000509static void
510raise_interrupt(void)
511{
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200512 pending_int = 0;
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +0000513 /* Signal is not automatically unmasked after it is raised,
514 * do it ourself - unmask all signals */
Denis Vlasenko3f165fa2008-03-17 08:29:08 +0000515 sigprocmask_allsigs(SIG_UNBLOCK);
Denys Vlasenko238bf182010-05-18 15:49:07 +0200516 /* pending_sig = 0; - now done in signal_handler() */
Denis Vlasenko7c139b42007-03-21 20:17:27 +0000517
Denys Vlasenkoc0663c72016-10-27 21:09:01 +0200518 if (!(rootshell && iflag)) {
519 /* Kill ourself with SIGINT */
520 signal(SIGINT, SIG_DFL);
521 raise(SIGINT);
Denis Vlasenkob012b102007-02-19 22:43:01 +0000522 }
Denys Vlasenko4d12e942016-10-01 16:03:11 +0200523 /* bash: ^C even on empty command line sets $? */
524 exitstatus = SIGINT + 128;
Denys Vlasenkoc0663c72016-10-27 21:09:01 +0200525 raise_exception(EXINT);
Denis Vlasenkob012b102007-02-19 22:43:01 +0000526 /* NOTREACHED */
527}
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000528#if DEBUG
529#define raise_interrupt() do { \
530 TRACE(("raising interrupt on line %d\n", __LINE__)); \
531 raise_interrupt(); \
532} while (0)
533#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +0000534
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000535static IF_ASH_OPTIMIZE_FOR_SIZE(inline) void
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000536int_on(void)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000537{
Denys Vlasenkode892052016-10-02 01:49:13 +0200538 barrier();
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200539 if (--suppress_int == 0 && pending_int) {
Denis Vlasenkob012b102007-02-19 22:43:01 +0000540 raise_interrupt();
541 }
542}
Denys Vlasenko06b11492016-11-04 16:43:18 +0100543#if DEBUG_INTONOFF
544# define INT_ON do { \
545 TRACE(("%s:%d INT_ON(%d)\n", __func__, __LINE__, suppress_int-1)); \
546 int_on(); \
547} while (0)
548#else
549# define INT_ON int_on()
550#endif
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000551static IF_ASH_OPTIMIZE_FOR_SIZE(inline) void
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000552force_int_on(void)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000553{
Denys Vlasenkode892052016-10-02 01:49:13 +0200554 barrier();
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200555 suppress_int = 0;
556 if (pending_int)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000557 raise_interrupt();
558}
559#define FORCE_INT_ON force_int_on()
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000560
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200561#define SAVE_INT(v) ((v) = suppress_int)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000562
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000563#define RESTORE_INT(v) do { \
Denys Vlasenkode892052016-10-02 01:49:13 +0200564 barrier(); \
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200565 suppress_int = (v); \
566 if (suppress_int == 0 && pending_int) \
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000567 raise_interrupt(); \
568} while (0)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000569
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000570
Denis Vlasenkobc54cff2007-02-23 01:05:52 +0000571/* ============ Stdout/stderr output */
Eric Andersenc470f442003-07-28 09:56:35 +0000572
Eric Andersenc470f442003-07-28 09:56:35 +0000573static void
Denis Vlasenkob012b102007-02-19 22:43:01 +0000574outstr(const char *p, FILE *file)
Denis Vlasenkoe5570da2007-02-19 22:41:55 +0000575{
Denis Vlasenkob012b102007-02-19 22:43:01 +0000576 INT_OFF;
577 fputs(p, file);
578 INT_ON;
579}
580
581static void
582flush_stdout_stderr(void)
583{
584 INT_OFF;
Denys Vlasenko8131eea2009-11-02 14:19:51 +0100585 fflush_all();
Denis Vlasenkob012b102007-02-19 22:43:01 +0000586 INT_ON;
587}
588
Denys Vlasenko9c541002015-10-07 15:44:36 +0200589/* Was called outcslow(c,FILE*), but c was always '\n' */
Denis Vlasenkob012b102007-02-19 22:43:01 +0000590static void
Denys Vlasenko9c541002015-10-07 15:44:36 +0200591newline_and_flush(FILE *dest)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000592{
593 INT_OFF;
Denys Vlasenko9c541002015-10-07 15:44:36 +0200594 putc('\n', dest);
Denis Vlasenkob012b102007-02-19 22:43:01 +0000595 fflush(dest);
596 INT_ON;
597}
598
599static int out1fmt(const char *, ...) __attribute__((__format__(__printf__,1,2)));
600static int
601out1fmt(const char *fmt, ...)
602{
603 va_list ap;
604 int r;
605
606 INT_OFF;
607 va_start(ap, fmt);
608 r = vprintf(fmt, ap);
609 va_end(ap);
610 INT_ON;
611 return r;
612}
613
614static int fmtstr(char *, size_t, const char *, ...) __attribute__((__format__(__printf__,3,4)));
615static int
616fmtstr(char *outbuf, size_t length, const char *fmt, ...)
617{
618 va_list ap;
619 int ret;
620
621 va_start(ap, fmt);
622 INT_OFF;
623 ret = vsnprintf(outbuf, length, fmt, ap);
624 va_end(ap);
625 INT_ON;
626 return ret;
627}
628
629static void
630out1str(const char *p)
631{
632 outstr(p, stdout);
633}
634
635static void
636out2str(const char *p)
637{
638 outstr(p, stderr);
Denys Vlasenko8131eea2009-11-02 14:19:51 +0100639 flush_stdout_stderr();
Denis Vlasenkob012b102007-02-19 22:43:01 +0000640}
641
642
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +0000643/* ============ Parser structures */
Denis Vlasenko4d2183b2007-02-23 01:05:38 +0000644
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000645/* control characters in argument strings */
Denys Vlasenko2ce42e92009-11-29 02:18:13 +0100646#define CTL_FIRST CTLESC
Denys Vlasenkob6c84342009-08-29 20:23:20 +0200647#define CTLESC ((unsigned char)'\201') /* escape next character */
648#define CTLVAR ((unsigned char)'\202') /* variable defn */
649#define CTLENDVAR ((unsigned char)'\203')
650#define CTLBACKQ ((unsigned char)'\204')
Denys Vlasenkob6c84342009-08-29 20:23:20 +0200651#define CTLARI ((unsigned char)'\206') /* arithmetic expression */
652#define CTLENDARI ((unsigned char)'\207')
653#define CTLQUOTEMARK ((unsigned char)'\210')
Denys Vlasenko2ce42e92009-11-29 02:18:13 +0100654#define CTL_LAST CTLQUOTEMARK
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000655
656/* variable substitution byte (follows CTLVAR) */
657#define VSTYPE 0x0f /* type of variable substitution */
658#define VSNUL 0x10 /* colon--treat the empty string as unset */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000659
660/* values of VSTYPE field */
Denis Vlasenko92e13c22008-03-25 01:17:40 +0000661#define VSNORMAL 0x1 /* normal variable: $var or ${var} */
662#define VSMINUS 0x2 /* ${var-text} */
663#define VSPLUS 0x3 /* ${var+text} */
664#define VSQUESTION 0x4 /* ${var?message} */
665#define VSASSIGN 0x5 /* ${var=text} */
666#define VSTRIMRIGHT 0x6 /* ${var%pattern} */
667#define VSTRIMRIGHTMAX 0x7 /* ${var%%pattern} */
668#define VSTRIMLEFT 0x8 /* ${var#pattern} */
669#define VSTRIMLEFTMAX 0x9 /* ${var##pattern} */
670#define VSLENGTH 0xa /* ${#var} */
671#if ENABLE_ASH_BASH_COMPAT
672#define VSSUBSTR 0xc /* ${var:position:length} */
673#define VSREPLACE 0xd /* ${var/pattern/replacement} */
674#define VSREPLACEALL 0xe /* ${var//pattern/replacement} */
675#endif
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000676
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000677static const char dolatstr[] ALIGN1 = {
Ron Yorston549deab2015-05-18 09:57:51 +0200678 CTLQUOTEMARK, CTLVAR, VSNORMAL, '@', '=', CTLQUOTEMARK, '\0'
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000679};
Ron Yorston549deab2015-05-18 09:57:51 +0200680#define DOLATSTRLEN 6
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +0000681
Denis Vlasenko559691a2008-10-05 18:39:31 +0000682#define NCMD 0
683#define NPIPE 1
684#define NREDIR 2
685#define NBACKGND 3
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000686#define NSUBSHELL 4
Denis Vlasenko559691a2008-10-05 18:39:31 +0000687#define NAND 5
688#define NOR 6
689#define NSEMI 7
690#define NIF 8
691#define NWHILE 9
692#define NUNTIL 10
693#define NFOR 11
694#define NCASE 12
695#define NCLIST 13
696#define NDEFUN 14
697#define NARG 15
698#define NTO 16
699#if ENABLE_ASH_BASH_COMPAT
700#define NTO2 17
701#endif
702#define NCLOBBER 18
703#define NFROM 19
704#define NFROMTO 20
705#define NAPPEND 21
706#define NTOFD 22
707#define NFROMFD 23
708#define NHERE 24
709#define NXHERE 25
710#define NNOT 26
Denis Vlasenko340299a2008-11-21 10:36:36 +0000711#define N_NUMBER 27
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000712
713union node;
714
715struct ncmd {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000716 smallint type; /* Nxxxx */
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000717 union node *assign;
718 union node *args;
719 union node *redirect;
720};
721
722struct npipe {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000723 smallint type;
724 smallint pipe_backgnd;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000725 struct nodelist *cmdlist;
726};
727
728struct nredir {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000729 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000730 union node *n;
731 union node *redirect;
732};
733
734struct nbinary {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000735 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000736 union node *ch1;
737 union node *ch2;
738};
739
740struct nif {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000741 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000742 union node *test;
743 union node *ifpart;
744 union node *elsepart;
745};
746
747struct nfor {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000748 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000749 union node *args;
750 union node *body;
751 char *var;
752};
753
754struct ncase {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000755 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000756 union node *expr;
757 union node *cases;
758};
759
760struct nclist {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000761 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000762 union node *next;
763 union node *pattern;
764 union node *body;
765};
766
767struct narg {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000768 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000769 union node *next;
770 char *text;
771 struct nodelist *backquote;
772};
773
Denis Vlasenko559691a2008-10-05 18:39:31 +0000774/* nfile and ndup layout must match!
775 * NTOFD (>&fdnum) uses ndup structure, but we may discover mid-flight
776 * that it is actually NTO2 (>&file), and change its type.
777 */
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000778struct nfile {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000779 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000780 union node *next;
781 int fd;
Denis Vlasenko559691a2008-10-05 18:39:31 +0000782 int _unused_dupfd;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000783 union node *fname;
784 char *expfname;
785};
786
787struct ndup {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000788 smallint type;
Denis Vlasenko559691a2008-10-05 18:39:31 +0000789 union node *next;
790 int fd;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000791 int dupfd;
792 union node *vname;
Denis Vlasenko559691a2008-10-05 18:39:31 +0000793 char *_unused_expfname;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000794};
795
796struct nhere {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000797 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000798 union node *next;
799 int fd;
800 union node *doc;
801};
802
803struct nnot {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000804 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000805 union node *com;
806};
807
808union node {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000809 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000810 struct ncmd ncmd;
811 struct npipe npipe;
812 struct nredir nredir;
813 struct nbinary nbinary;
814 struct nif nif;
815 struct nfor nfor;
816 struct ncase ncase;
817 struct nclist nclist;
818 struct narg narg;
819 struct nfile nfile;
820 struct ndup ndup;
821 struct nhere nhere;
822 struct nnot nnot;
823};
824
Denys Vlasenko86e83ec2009-07-23 22:07:07 +0200825/*
826 * NODE_EOF is returned by parsecmd when it encounters an end of file.
827 * It must be distinct from NULL.
828 */
829#define NODE_EOF ((union node *) -1L)
830
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000831struct nodelist {
832 struct nodelist *next;
833 union node *n;
834};
835
836struct funcnode {
837 int count;
838 union node n;
839};
840
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000841/*
842 * Free a parse tree.
843 */
844static void
845freefunc(struct funcnode *f)
846{
847 if (f && --f->count < 0)
848 free(f);
849}
850
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000851
852/* ============ Debugging output */
853
854#if DEBUG
855
856static FILE *tracefile;
857
858static void
859trace_printf(const char *fmt, ...)
860{
861 va_list va;
862
863 if (debug != 1)
864 return;
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000865 if (DEBUG_TIME)
866 fprintf(tracefile, "%u ", (int) time(NULL));
867 if (DEBUG_PID)
868 fprintf(tracefile, "[%u] ", (int) getpid());
869 if (DEBUG_SIG)
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200870 fprintf(tracefile, "pending s:%d i:%d(supp:%d) ", pending_sig, pending_int, suppress_int);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000871 va_start(va, fmt);
872 vfprintf(tracefile, fmt, va);
873 va_end(va);
874}
875
876static void
877trace_vprintf(const char *fmt, va_list va)
878{
879 if (debug != 1)
880 return;
881 vfprintf(tracefile, fmt, va);
Denys Vlasenko474ed062016-10-30 18:30:29 +0100882 fprintf(tracefile, "\n");
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000883}
884
885static void
886trace_puts(const char *s)
887{
888 if (debug != 1)
889 return;
890 fputs(s, tracefile);
891}
892
893static void
894trace_puts_quoted(char *s)
895{
896 char *p;
897 char c;
898
899 if (debug != 1)
900 return;
901 putc('"', tracefile);
902 for (p = s; *p; p++) {
Denys Vlasenkocd716832009-11-28 22:14:02 +0100903 switch ((unsigned char)*p) {
904 case '\n': c = 'n'; goto backslash;
905 case '\t': c = 't'; goto backslash;
906 case '\r': c = 'r'; goto backslash;
907 case '\"': c = '\"'; goto backslash;
908 case '\\': c = '\\'; goto backslash;
909 case CTLESC: c = 'e'; goto backslash;
910 case CTLVAR: c = 'v'; goto backslash;
Denys Vlasenkocd716832009-11-28 22:14:02 +0100911 case CTLBACKQ: c = 'q'; goto backslash;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000912 backslash:
913 putc('\\', tracefile);
914 putc(c, tracefile);
915 break;
916 default:
917 if (*p >= ' ' && *p <= '~')
918 putc(*p, tracefile);
919 else {
920 putc('\\', tracefile);
Denys Vlasenkocd716832009-11-28 22:14:02 +0100921 putc((*p >> 6) & 03, tracefile);
922 putc((*p >> 3) & 07, tracefile);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000923 putc(*p & 07, tracefile);
924 }
925 break;
926 }
927 }
928 putc('"', tracefile);
929}
930
931static void
932trace_puts_args(char **ap)
933{
934 if (debug != 1)
935 return;
936 if (!*ap)
937 return;
938 while (1) {
939 trace_puts_quoted(*ap);
940 if (!*++ap) {
941 putc('\n', tracefile);
942 break;
943 }
944 putc(' ', tracefile);
945 }
946}
947
948static void
949opentrace(void)
950{
951 char s[100];
952#ifdef O_APPEND
953 int flags;
954#endif
955
956 if (debug != 1) {
957 if (tracefile)
958 fflush(tracefile);
959 /* leave open because libedit might be using it */
960 return;
961 }
962 strcpy(s, "./trace");
963 if (tracefile) {
964 if (!freopen(s, "a", tracefile)) {
965 fprintf(stderr, "Can't re-open %s\n", s);
966 debug = 0;
967 return;
968 }
969 } else {
970 tracefile = fopen(s, "a");
971 if (tracefile == NULL) {
972 fprintf(stderr, "Can't open %s\n", s);
973 debug = 0;
974 return;
975 }
976 }
977#ifdef O_APPEND
Denis Vlasenkod37f2222007-08-19 13:42:08 +0000978 flags = fcntl(fileno(tracefile), F_GETFL);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000979 if (flags >= 0)
980 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
981#endif
982 setlinebuf(tracefile);
983 fputs("\nTracing started.\n", tracefile);
984}
985
986static void
987indent(int amount, char *pfx, FILE *fp)
988{
989 int i;
990
991 for (i = 0; i < amount; i++) {
992 if (pfx && i == amount - 1)
993 fputs(pfx, fp);
994 putc('\t', fp);
995 }
996}
997
998/* little circular references here... */
999static void shtree(union node *n, int ind, char *pfx, FILE *fp);
1000
1001static void
1002sharg(union node *arg, FILE *fp)
1003{
1004 char *p;
1005 struct nodelist *bqlist;
Denys Vlasenkocd716832009-11-28 22:14:02 +01001006 unsigned char subtype;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001007
1008 if (arg->type != NARG) {
1009 out1fmt("<node type %d>\n", arg->type);
1010 abort();
1011 }
1012 bqlist = arg->narg.backquote;
1013 for (p = arg->narg.text; *p; p++) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01001014 switch ((unsigned char)*p) {
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001015 case CTLESC:
Dan Fandrich77d48722010-09-07 23:38:28 -07001016 p++;
1017 putc(*p, fp);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001018 break;
1019 case CTLVAR:
1020 putc('$', fp);
1021 putc('{', fp);
1022 subtype = *++p;
1023 if (subtype == VSLENGTH)
1024 putc('#', fp);
1025
Dan Fandrich77d48722010-09-07 23:38:28 -07001026 while (*p != '=') {
1027 putc(*p, fp);
1028 p++;
1029 }
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001030
1031 if (subtype & VSNUL)
1032 putc(':', fp);
1033
1034 switch (subtype & VSTYPE) {
1035 case VSNORMAL:
1036 putc('}', fp);
1037 break;
1038 case VSMINUS:
1039 putc('-', fp);
1040 break;
1041 case VSPLUS:
1042 putc('+', fp);
1043 break;
1044 case VSQUESTION:
1045 putc('?', fp);
1046 break;
1047 case VSASSIGN:
1048 putc('=', fp);
1049 break;
1050 case VSTRIMLEFT:
1051 putc('#', fp);
1052 break;
1053 case VSTRIMLEFTMAX:
1054 putc('#', fp);
1055 putc('#', fp);
1056 break;
1057 case VSTRIMRIGHT:
1058 putc('%', fp);
1059 break;
1060 case VSTRIMRIGHTMAX:
1061 putc('%', fp);
1062 putc('%', fp);
1063 break;
1064 case VSLENGTH:
1065 break;
1066 default:
1067 out1fmt("<subtype %d>", subtype);
1068 }
1069 break;
1070 case CTLENDVAR:
1071 putc('}', fp);
1072 break;
1073 case CTLBACKQ:
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001074 putc('$', fp);
1075 putc('(', fp);
1076 shtree(bqlist->n, -1, NULL, fp);
1077 putc(')', fp);
1078 break;
1079 default:
1080 putc(*p, fp);
1081 break;
1082 }
1083 }
1084}
1085
Denys Vlasenko641dd7b2009-06-11 19:30:19 +02001086static void
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001087shcmd(union node *cmd, FILE *fp)
1088{
1089 union node *np;
1090 int first;
1091 const char *s;
1092 int dftfd;
1093
1094 first = 1;
1095 for (np = cmd->ncmd.args; np; np = np->narg.next) {
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001096 if (!first)
1097 putc(' ', fp);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001098 sharg(np, fp);
1099 first = 0;
1100 }
1101 for (np = cmd->ncmd.redirect; np; np = np->nfile.next) {
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001102 if (!first)
1103 putc(' ', fp);
1104 dftfd = 0;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001105 switch (np->nfile.type) {
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001106 case NTO: s = ">>"+1; dftfd = 1; break;
1107 case NCLOBBER: s = ">|"; dftfd = 1; break;
1108 case NAPPEND: s = ">>"; dftfd = 1; break;
Denis Vlasenko559691a2008-10-05 18:39:31 +00001109#if ENABLE_ASH_BASH_COMPAT
1110 case NTO2:
1111#endif
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001112 case NTOFD: s = ">&"; dftfd = 1; break;
Denis Vlasenko559691a2008-10-05 18:39:31 +00001113 case NFROM: s = "<"; break;
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001114 case NFROMFD: s = "<&"; break;
1115 case NFROMTO: s = "<>"; break;
1116 default: s = "*error*"; break;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001117 }
1118 if (np->nfile.fd != dftfd)
1119 fprintf(fp, "%d", np->nfile.fd);
1120 fputs(s, fp);
1121 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
1122 fprintf(fp, "%d", np->ndup.dupfd);
1123 } else {
1124 sharg(np->nfile.fname, fp);
1125 }
1126 first = 0;
1127 }
1128}
1129
1130static void
1131shtree(union node *n, int ind, char *pfx, FILE *fp)
1132{
1133 struct nodelist *lp;
1134 const char *s;
1135
1136 if (n == NULL)
1137 return;
1138
1139 indent(ind, pfx, fp);
Denys Vlasenko86e83ec2009-07-23 22:07:07 +02001140
1141 if (n == NODE_EOF) {
1142 fputs("<EOF>", fp);
1143 return;
1144 }
1145
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001146 switch (n->type) {
1147 case NSEMI:
1148 s = "; ";
1149 goto binop;
1150 case NAND:
1151 s = " && ";
1152 goto binop;
1153 case NOR:
1154 s = " || ";
1155 binop:
1156 shtree(n->nbinary.ch1, ind, NULL, fp);
1157 /* if (ind < 0) */
1158 fputs(s, fp);
1159 shtree(n->nbinary.ch2, ind, NULL, fp);
1160 break;
1161 case NCMD:
1162 shcmd(n, fp);
1163 if (ind >= 0)
1164 putc('\n', fp);
1165 break;
1166 case NPIPE:
1167 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
Denys Vlasenko7cee00e2009-07-24 01:08:03 +02001168 shtree(lp->n, 0, NULL, fp);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001169 if (lp->next)
1170 fputs(" | ", fp);
1171 }
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00001172 if (n->npipe.pipe_backgnd)
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001173 fputs(" &", fp);
1174 if (ind >= 0)
1175 putc('\n', fp);
1176 break;
1177 default:
1178 fprintf(fp, "<node type %d>", n->type);
1179 if (ind >= 0)
1180 putc('\n', fp);
1181 break;
1182 }
1183}
1184
1185static void
1186showtree(union node *n)
1187{
1188 trace_puts("showtree called\n");
Denys Vlasenko883cea42009-07-11 15:31:59 +02001189 shtree(n, 1, NULL, stderr);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001190}
1191
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001192#endif /* DEBUG */
1193
1194
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00001195/* ============ Parser data */
1196
1197/*
Denis Vlasenkob012b102007-02-19 22:43:01 +00001198 * ash_vmsg() needs parsefile->fd, hence parsefile definition is moved up.
1199 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001200struct strlist {
1201 struct strlist *next;
1202 char *text;
1203};
1204
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001205struct alias;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001206
Denis Vlasenkob012b102007-02-19 22:43:01 +00001207struct strpush {
1208 struct strpush *prev; /* preceding string on stack */
Denis Vlasenko41eb3002008-11-28 03:42:31 +00001209 char *prev_string;
1210 int prev_left_in_line;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001211#if ENABLE_ASH_ALIAS
1212 struct alias *ap; /* if push was associated with an alias */
1213#endif
1214 char *string; /* remember the string since it may change */
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02001215
1216 /* Remember last two characters for pungetc. */
1217 int lastc[2];
1218
1219 /* Number of outstanding calls to pungetc. */
1220 int unget;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001221};
1222
1223struct parsefile {
1224 struct parsefile *prev; /* preceding file on stack */
1225 int linno; /* current line */
Denys Vlasenko79b3d422010-06-03 04:29:08 +02001226 int pf_fd; /* file descriptor (or -1 if string) */
Denis Vlasenko41eb3002008-11-28 03:42:31 +00001227 int left_in_line; /* number of chars left in this line */
1228 int left_in_buffer; /* number of chars left in this buffer past the line */
1229 char *next_to_pgetc; /* next char in buffer */
Denis Vlasenkob012b102007-02-19 22:43:01 +00001230 char *buf; /* input buffer */
1231 struct strpush *strpush; /* for pushing strings at this level */
1232 struct strpush basestrpush; /* so pushing one is fast */
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02001233
1234 /* Remember last two characters for pungetc. */
1235 int lastc[2];
1236
1237 /* Number of outstanding calls to pungetc. */
1238 int unget;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001239};
1240
Denis Vlasenko448d30e2008-06-27 00:24:11 +00001241static struct parsefile basepf; /* top level input file */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00001242static struct parsefile *g_parsefile = &basepf; /* current input file */
Denis Vlasenkob012b102007-02-19 22:43:01 +00001243static int startlinno; /* line # where last token started */
1244static char *commandname; /* currently executing command */
1245static struct strlist *cmdenviron; /* environment for builtin command */
Denis Vlasenkob012b102007-02-19 22:43:01 +00001246
1247
1248/* ============ Message printing */
1249
1250static void
1251ash_vmsg(const char *msg, va_list ap)
1252{
1253 fprintf(stderr, "%s: ", arg0);
1254 if (commandname) {
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00001255 if (strcmp(arg0, commandname))
1256 fprintf(stderr, "%s: ", commandname);
Denys Vlasenko79b3d422010-06-03 04:29:08 +02001257 if (!iflag || g_parsefile->pf_fd > 0)
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00001258 fprintf(stderr, "line %d: ", startlinno);
Eric Andersenc470f442003-07-28 09:56:35 +00001259 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00001260 vfprintf(stderr, msg, ap);
Denys Vlasenko9c541002015-10-07 15:44:36 +02001261 newline_and_flush(stderr);
Eric Andersenc470f442003-07-28 09:56:35 +00001262}
Denis Vlasenkob012b102007-02-19 22:43:01 +00001263
1264/*
1265 * Exverror is called to raise the error exception. If the second argument
1266 * is not NULL then error prints an error message using printf style
1267 * formatting. It then raises the error exception.
1268 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00001269static void ash_vmsg_and_raise(int, const char *, va_list) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001270static void
1271ash_vmsg_and_raise(int cond, const char *msg, va_list ap)
Eric Andersenc470f442003-07-28 09:56:35 +00001272{
Denis Vlasenkob012b102007-02-19 22:43:01 +00001273#if DEBUG
1274 if (msg) {
Denys Vlasenko474ed062016-10-30 18:30:29 +01001275 TRACE(("ash_vmsg_and_raise(%d):", cond));
Denis Vlasenkob012b102007-02-19 22:43:01 +00001276 TRACEV((msg, ap));
Denis Vlasenkob012b102007-02-19 22:43:01 +00001277 } else
Denys Vlasenko474ed062016-10-30 18:30:29 +01001278 TRACE(("ash_vmsg_and_raise(%d):NULL\n", cond));
Denis Vlasenkob012b102007-02-19 22:43:01 +00001279 if (msg)
1280#endif
1281 ash_vmsg(msg, ap);
1282
1283 flush_stdout_stderr();
1284 raise_exception(cond);
1285 /* NOTREACHED */
Eric Andersenc470f442003-07-28 09:56:35 +00001286}
Denis Vlasenkob012b102007-02-19 22:43:01 +00001287
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00001288static void ash_msg_and_raise_error(const char *, ...) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001289static void
1290ash_msg_and_raise_error(const char *msg, ...)
1291{
1292 va_list ap;
1293
Ron Yorstonea7d2f62017-01-03 11:18:23 +01001294 exitstatus = 2;
1295
Denis Vlasenkob012b102007-02-19 22:43:01 +00001296 va_start(ap, msg);
1297 ash_vmsg_and_raise(EXERROR, msg, ap);
1298 /* NOTREACHED */
1299 va_end(ap);
1300}
1301
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00001302static void raise_error_syntax(const char *) NORETURN;
1303static void
1304raise_error_syntax(const char *msg)
1305{
1306 ash_msg_and_raise_error("syntax error: %s", msg);
1307 /* NOTREACHED */
1308}
1309
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00001310static void ash_msg_and_raise(int, const char *, ...) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001311static void
1312ash_msg_and_raise(int cond, const char *msg, ...)
1313{
1314 va_list ap;
1315
1316 va_start(ap, msg);
1317 ash_vmsg_and_raise(cond, msg, ap);
1318 /* NOTREACHED */
1319 va_end(ap);
1320}
1321
1322/*
1323 * error/warning routines for external builtins
1324 */
1325static void
1326ash_msg(const char *fmt, ...)
1327{
1328 va_list ap;
1329
1330 va_start(ap, fmt);
1331 ash_vmsg(fmt, ap);
1332 va_end(ap);
1333}
1334
1335/*
1336 * Return a string describing an error. The returned string may be a
1337 * pointer to a static buffer that will be overwritten on the next call.
1338 * Action describes the operation that got the error.
1339 */
1340static const char *
1341errmsg(int e, const char *em)
1342{
1343 if (e == ENOENT || e == ENOTDIR) {
1344 return em;
1345 }
1346 return strerror(e);
1347}
1348
1349
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001350/* ============ Memory allocation */
1351
Denys Vlasenkoe7670ff2009-10-11 00:45:25 +02001352#if 0
1353/* I consider these wrappers nearly useless:
1354 * ok, they return you to nearest exception handler, but
1355 * how much memory do you leak in the process, making
1356 * memory starvation worse?
1357 */
1358static void *
1359ckrealloc(void * p, size_t nbytes)
1360{
1361 p = realloc(p, nbytes);
1362 if (!p)
1363 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1364 return p;
1365}
1366
1367static void *
1368ckmalloc(size_t nbytes)
1369{
1370 return ckrealloc(NULL, nbytes);
1371}
1372
1373static void *
1374ckzalloc(size_t nbytes)
1375{
1376 return memset(ckmalloc(nbytes), 0, nbytes);
1377}
1378
1379static char *
1380ckstrdup(const char *s)
1381{
1382 char *p = strdup(s);
1383 if (!p)
1384 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1385 return p;
1386}
1387#else
1388/* Using bbox equivalents. They exit if out of memory */
1389# define ckrealloc xrealloc
1390# define ckmalloc xmalloc
1391# define ckzalloc xzalloc
1392# define ckstrdup xstrdup
1393#endif
1394
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001395/*
1396 * It appears that grabstackstr() will barf with such alignments
1397 * because stalloc() will return a string allocated in a new stackblock.
1398 */
1399#define SHELL_ALIGN(nbytes) (((nbytes) + SHELL_SIZE) & ~SHELL_SIZE)
1400enum {
1401 /* Most machines require the value returned from malloc to be aligned
1402 * in some way. The following macro will get this right
1403 * on many machines. */
Denys Vlasenko0e5e4ea2009-10-11 00:36:20 +02001404 SHELL_SIZE = sizeof(union { int i; char *cp; double d; }) - 1,
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001405 /* Minimum size of a block */
Denis Vlasenko01631112007-12-16 17:20:38 +00001406 MINSIZE = SHELL_ALIGN(504),
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001407};
1408
1409struct stack_block {
1410 struct stack_block *prev;
1411 char space[MINSIZE];
1412};
1413
1414struct stackmark {
1415 struct stack_block *stackp;
1416 char *stacknxt;
1417 size_t stacknleft;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001418};
1419
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001420
Denis Vlasenko01631112007-12-16 17:20:38 +00001421struct globals_memstack {
1422 struct stack_block *g_stackp; // = &stackbase;
Denis Vlasenko01631112007-12-16 17:20:38 +00001423 char *g_stacknxt; // = stackbase.space;
1424 char *sstrend; // = stackbase.space + MINSIZE;
1425 size_t g_stacknleft; // = MINSIZE;
Denis Vlasenko01631112007-12-16 17:20:38 +00001426 struct stack_block stackbase;
1427};
Denis Vlasenko574f2f42008-02-27 18:41:59 +00001428extern struct globals_memstack *const ash_ptr_to_globals_memstack;
1429#define G_memstack (*ash_ptr_to_globals_memstack)
Denis Vlasenko01631112007-12-16 17:20:38 +00001430#define g_stackp (G_memstack.g_stackp )
Denis Vlasenko01631112007-12-16 17:20:38 +00001431#define g_stacknxt (G_memstack.g_stacknxt )
1432#define sstrend (G_memstack.sstrend )
1433#define g_stacknleft (G_memstack.g_stacknleft)
Denis Vlasenko01631112007-12-16 17:20:38 +00001434#define stackbase (G_memstack.stackbase )
1435#define INIT_G_memstack() do { \
Denis Vlasenko574f2f42008-02-27 18:41:59 +00001436 (*(struct globals_memstack**)&ash_ptr_to_globals_memstack) = xzalloc(sizeof(G_memstack)); \
1437 barrier(); \
Denis Vlasenko01631112007-12-16 17:20:38 +00001438 g_stackp = &stackbase; \
1439 g_stacknxt = stackbase.space; \
1440 g_stacknleft = MINSIZE; \
1441 sstrend = stackbase.space + MINSIZE; \
Denis Vlasenko01631112007-12-16 17:20:38 +00001442} while (0)
1443
Denys Vlasenkoe7670ff2009-10-11 00:45:25 +02001444
Denis Vlasenko01631112007-12-16 17:20:38 +00001445#define stackblock() ((void *)g_stacknxt)
1446#define stackblocksize() g_stacknleft
1447
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001448/*
1449 * Parse trees for commands are allocated in lifo order, so we use a stack
1450 * to make this more efficient, and also to avoid all sorts of exception
1451 * handling code to handle interrupts in the middle of a parse.
1452 *
1453 * The size 504 was chosen because the Ultrix malloc handles that size
1454 * well.
1455 */
1456static void *
1457stalloc(size_t nbytes)
1458{
1459 char *p;
1460 size_t aligned;
1461
1462 aligned = SHELL_ALIGN(nbytes);
Denis Vlasenko01631112007-12-16 17:20:38 +00001463 if (aligned > g_stacknleft) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001464 size_t len;
1465 size_t blocksize;
1466 struct stack_block *sp;
1467
1468 blocksize = aligned;
1469 if (blocksize < MINSIZE)
1470 blocksize = MINSIZE;
1471 len = sizeof(struct stack_block) - MINSIZE + blocksize;
1472 if (len < blocksize)
1473 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1474 INT_OFF;
1475 sp = ckmalloc(len);
Denis Vlasenko01631112007-12-16 17:20:38 +00001476 sp->prev = g_stackp;
1477 g_stacknxt = sp->space;
1478 g_stacknleft = blocksize;
1479 sstrend = g_stacknxt + blocksize;
1480 g_stackp = sp;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001481 INT_ON;
1482 }
Denis Vlasenko01631112007-12-16 17:20:38 +00001483 p = g_stacknxt;
1484 g_stacknxt += aligned;
1485 g_stacknleft -= aligned;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001486 return p;
1487}
1488
Denis Vlasenko597906c2008-02-20 16:38:54 +00001489static void *
1490stzalloc(size_t nbytes)
1491{
1492 return memset(stalloc(nbytes), 0, nbytes);
1493}
1494
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001495static void
1496stunalloc(void *p)
1497{
1498#if DEBUG
Denis Vlasenko01631112007-12-16 17:20:38 +00001499 if (!p || (g_stacknxt < (char *)p) || ((char *)p < g_stackp->space)) {
Bernhard Reutner-Fischer5e25ddb2008-05-19 09:48:17 +00001500 write(STDERR_FILENO, "stunalloc\n", 10);
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001501 abort();
1502 }
1503#endif
Denis Vlasenko01631112007-12-16 17:20:38 +00001504 g_stacknleft += g_stacknxt - (char *)p;
1505 g_stacknxt = p;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001506}
1507
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001508/*
1509 * Like strdup but works with the ash stack.
1510 */
1511static char *
Denys Vlasenko8e2bc472016-09-28 23:02:57 +02001512sstrdup(const char *p)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001513{
1514 size_t len = strlen(p) + 1;
1515 return memcpy(stalloc(len), p, len);
1516}
1517
Denys Vlasenkoa318bba2016-10-26 18:26:27 +02001518static inline void
Denys Vlasenko60ca8342016-09-30 11:21:21 +02001519grabstackblock(size_t len)
1520{
Denys Vlasenkoa318bba2016-10-26 18:26:27 +02001521 stalloc(len);
Denys Vlasenko60ca8342016-09-30 11:21:21 +02001522}
1523
1524static void
1525pushstackmark(struct stackmark *mark, size_t len)
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001526{
Denis Vlasenko01631112007-12-16 17:20:38 +00001527 mark->stackp = g_stackp;
1528 mark->stacknxt = g_stacknxt;
1529 mark->stacknleft = g_stacknleft;
Denys Vlasenko60ca8342016-09-30 11:21:21 +02001530 grabstackblock(len);
1531}
1532
1533static void
1534setstackmark(struct stackmark *mark)
1535{
1536 pushstackmark(mark, g_stacknxt == g_stackp->space && g_stackp != &stackbase);
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001537}
1538
1539static void
1540popstackmark(struct stackmark *mark)
1541{
1542 struct stack_block *sp;
1543
Denis Vlasenko93ebd4f2007-03-13 20:55:36 +00001544 if (!mark->stackp)
1545 return;
1546
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001547 INT_OFF;
Denis Vlasenko01631112007-12-16 17:20:38 +00001548 while (g_stackp != mark->stackp) {
1549 sp = g_stackp;
1550 g_stackp = sp->prev;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001551 free(sp);
1552 }
Denis Vlasenko01631112007-12-16 17:20:38 +00001553 g_stacknxt = mark->stacknxt;
1554 g_stacknleft = mark->stacknleft;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001555 sstrend = mark->stacknxt + mark->stacknleft;
1556 INT_ON;
1557}
1558
1559/*
1560 * When the parser reads in a string, it wants to stick the string on the
1561 * stack and only adjust the stack pointer when it knows how big the
1562 * string is. Stackblock (defined in stack.h) returns a pointer to a block
1563 * of space on top of the stack and stackblocklen returns the length of
1564 * this block. Growstackblock will grow this space by at least one byte,
1565 * possibly moving it (like realloc). Grabstackblock actually allocates the
1566 * part of the block that has been used.
1567 */
1568static void
1569growstackblock(void)
1570{
1571 size_t newlen;
1572
Denis Vlasenko01631112007-12-16 17:20:38 +00001573 newlen = g_stacknleft * 2;
1574 if (newlen < g_stacknleft)
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001575 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1576 if (newlen < 128)
1577 newlen += 128;
1578
Denis Vlasenko01631112007-12-16 17:20:38 +00001579 if (g_stacknxt == g_stackp->space && g_stackp != &stackbase) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001580 struct stack_block *sp;
1581 struct stack_block *prevstackp;
1582 size_t grosslen;
1583
1584 INT_OFF;
Denis Vlasenko01631112007-12-16 17:20:38 +00001585 sp = g_stackp;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001586 prevstackp = sp->prev;
1587 grosslen = newlen + sizeof(struct stack_block) - MINSIZE;
1588 sp = ckrealloc(sp, grosslen);
1589 sp->prev = prevstackp;
Denis Vlasenko01631112007-12-16 17:20:38 +00001590 g_stackp = sp;
1591 g_stacknxt = sp->space;
1592 g_stacknleft = newlen;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001593 sstrend = sp->space + newlen;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001594 INT_ON;
1595 } else {
Denis Vlasenko01631112007-12-16 17:20:38 +00001596 char *oldspace = g_stacknxt;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001597 size_t oldlen = g_stacknleft;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001598 char *p = stalloc(newlen);
1599
1600 /* free the space we just allocated */
Denis Vlasenko01631112007-12-16 17:20:38 +00001601 g_stacknxt = memcpy(p, oldspace, oldlen);
1602 g_stacknleft += newlen;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001603 }
1604}
1605
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001606/*
1607 * The following routines are somewhat easier to use than the above.
1608 * The user declares a variable of type STACKSTR, which may be declared
1609 * to be a register. The macro STARTSTACKSTR initializes things. Then
1610 * the user uses the macro STPUTC to add characters to the string. In
1611 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
1612 * grown as necessary. When the user is done, she can just leave the
1613 * string there and refer to it using stackblock(). Or she can allocate
1614 * the space for it using grabstackstr(). If it is necessary to allow
1615 * someone else to use the stack temporarily and then continue to grow
1616 * the string, the user should use grabstack to allocate the space, and
1617 * then call ungrabstr(p) to return to the previous mode of operation.
1618 *
1619 * USTPUTC is like STPUTC except that it doesn't check for overflow.
1620 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
1621 * is space for at least one character.
1622 */
1623static void *
1624growstackstr(void)
1625{
1626 size_t len = stackblocksize();
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001627 growstackblock();
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001628 return (char *)stackblock() + len;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001629}
1630
1631/*
1632 * Called from CHECKSTRSPACE.
1633 */
1634static char *
1635makestrspace(size_t newlen, char *p)
1636{
Denis Vlasenko01631112007-12-16 17:20:38 +00001637 size_t len = p - g_stacknxt;
Denys Vlasenko53d6e032016-09-30 11:24:12 +02001638 size_t size;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001639
1640 for (;;) {
1641 size_t nleft;
1642
1643 size = stackblocksize();
1644 nleft = size - len;
1645 if (nleft >= newlen)
1646 break;
1647 growstackblock();
1648 }
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001649 return (char *)stackblock() + len;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001650}
1651
1652static char *
1653stack_nputstr(const char *s, size_t n, char *p)
1654{
1655 p = makestrspace(n, p);
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001656 p = (char *)memcpy(p, s, n) + n;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001657 return p;
1658}
1659
1660static char *
1661stack_putstr(const char *s, char *p)
1662{
1663 return stack_nputstr(s, strlen(s), p);
1664}
1665
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001666static char *
1667_STPUTC(int c, char *p)
1668{
1669 if (p == sstrend)
1670 p = growstackstr();
1671 *p++ = c;
1672 return p;
1673}
1674
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00001675#define STARTSTACKSTR(p) ((p) = stackblock())
1676#define STPUTC(c, p) ((p) = _STPUTC((c), (p)))
Denis Vlasenko843cbd52008-06-27 00:23:18 +00001677#define CHECKSTRSPACE(n, p) do { \
1678 char *q = (p); \
1679 size_t l = (n); \
1680 size_t m = sstrend - q; \
1681 if (l > m) \
1682 (p) = makestrspace(l, q); \
1683} while (0)
Denis Vlasenkoef527f52008-06-23 01:52:30 +00001684#define USTPUTC(c, p) (*(p)++ = (c))
Denis Vlasenko843cbd52008-06-27 00:23:18 +00001685#define STACKSTRNUL(p) do { \
1686 if ((p) == sstrend) \
1687 (p) = growstackstr(); \
1688 *(p) = '\0'; \
1689} while (0)
Denis Vlasenkoef527f52008-06-23 01:52:30 +00001690#define STUNPUTC(p) (--(p))
1691#define STTOPC(p) ((p)[-1])
1692#define STADJUST(amount, p) ((p) += (amount))
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001693
1694#define grabstackstr(p) stalloc((char *)(p) - (char *)stackblock())
Denis Vlasenkoef527f52008-06-23 01:52:30 +00001695#define ungrabstackstr(s, p) stunalloc(s)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001696#define stackstrend() ((void *)sstrend)
1697
1698
1699/* ============ String helpers */
1700
1701/*
1702 * prefix -- see if pfx is a prefix of string.
1703 */
1704static char *
1705prefix(const char *string, const char *pfx)
1706{
1707 while (*pfx) {
1708 if (*pfx++ != *string++)
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00001709 return NULL;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001710 }
1711 return (char *) string;
1712}
1713
1714/*
1715 * Check for a valid number. This should be elsewhere.
1716 */
1717static int
1718is_number(const char *p)
1719{
1720 do {
1721 if (!isdigit(*p))
1722 return 0;
1723 } while (*++p != '\0');
1724 return 1;
1725}
1726
1727/*
1728 * Convert a string of digits to an integer, printing an error message on
1729 * failure.
1730 */
1731static int
1732number(const char *s)
1733{
1734 if (!is_number(s))
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02001735 ash_msg_and_raise_error(msg_illnum, s);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001736 return atoi(s);
1737}
1738
1739/*
1740 * Produce a possibly single quoted string suitable as input to the shell.
1741 * The return string is allocated on the stack.
1742 */
1743static char *
1744single_quote(const char *s)
1745{
1746 char *p;
1747
1748 STARTSTACKSTR(p);
1749
1750 do {
1751 char *q;
1752 size_t len;
1753
1754 len = strchrnul(s, '\'') - s;
1755
1756 q = p = makestrspace(len + 3, p);
1757
1758 *q++ = '\'';
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001759 q = (char *)memcpy(q, s, len) + len;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001760 *q++ = '\'';
1761 s += len;
1762
1763 STADJUST(q - p, p);
1764
Denys Vlasenkocd716832009-11-28 22:14:02 +01001765 if (*s != '\'')
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001766 break;
Denys Vlasenkocd716832009-11-28 22:14:02 +01001767 len = 0;
1768 do len++; while (*++s == '\'');
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001769
1770 q = p = makestrspace(len + 3, p);
1771
1772 *q++ = '"';
Denys Vlasenkocd716832009-11-28 22:14:02 +01001773 q = (char *)memcpy(q, s - len, len) + len;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001774 *q++ = '"';
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001775
1776 STADJUST(q - p, p);
1777 } while (*s);
1778
Denys Vlasenkocd716832009-11-28 22:14:02 +01001779 USTPUTC('\0', p);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001780
1781 return stackblock();
1782}
1783
1784
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00001785/* ============ nextopt */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001786
1787static char **argptr; /* argument list for builtin commands */
1788static char *optionarg; /* set by nextopt (like getopt) */
1789static char *optptr; /* used by nextopt */
1790
1791/*
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001792 * XXX - should get rid of. Have all builtins use getopt(3).
1793 * The library getopt must have the BSD extension static variable
1794 * "optreset", otherwise it can't be used within the shell safely.
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001795 *
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001796 * Standard option processing (a la getopt) for builtin routines.
1797 * The only argument that is passed to nextopt is the option string;
1798 * the other arguments are unnecessary. It returns the character,
1799 * or '\0' on end of input.
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001800 */
1801static int
1802nextopt(const char *optstring)
1803{
1804 char *p;
1805 const char *q;
1806 char c;
1807
1808 p = optptr;
1809 if (p == NULL || *p == '\0') {
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001810 /* We ate entire "-param", take next one */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001811 p = *argptr;
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001812 if (p == NULL)
1813 return '\0';
1814 if (*p != '-')
1815 return '\0';
1816 if (*++p == '\0') /* just "-" ? */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001817 return '\0';
1818 argptr++;
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001819 if (LONE_DASH(p)) /* "--" ? */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001820 return '\0';
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001821 /* p => next "-param" */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001822 }
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001823 /* p => some option char in the middle of a "-param" */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001824 c = *p++;
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +00001825 for (q = optstring; *q != c;) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001826 if (*q == '\0')
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00001827 ash_msg_and_raise_error("illegal option -%c", c);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001828 if (*++q == ':')
1829 q++;
1830 }
1831 if (*++q == ':') {
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001832 if (*p == '\0') {
1833 p = *argptr++;
1834 if (p == NULL)
1835 ash_msg_and_raise_error("no arg for -%c option", c);
1836 }
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001837 optionarg = p;
1838 p = NULL;
1839 }
1840 optptr = p;
1841 return c;
1842}
1843
1844
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00001845/* ============ Shell variables */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001846
Denis Vlasenko01631112007-12-16 17:20:38 +00001847/*
1848 * The parsefile structure pointed to by the global variable parsefile
1849 * contains information about the current file being read.
1850 */
Denis Vlasenko01631112007-12-16 17:20:38 +00001851struct shparam {
1852 int nparam; /* # of positional parameters (without $0) */
1853#if ENABLE_ASH_GETOPTS
1854 int optind; /* next parameter to be processed by getopts */
1855 int optoff; /* used by getopts */
1856#endif
1857 unsigned char malloced; /* if parameter list dynamically allocated */
1858 char **p; /* parameter list */
1859};
1860
1861/*
1862 * Free the list of positional parameters.
1863 */
1864static void
1865freeparam(volatile struct shparam *param)
1866{
Denis Vlasenko01631112007-12-16 17:20:38 +00001867 if (param->malloced) {
Denis Vlasenko3177ba02008-07-13 20:39:23 +00001868 char **ap, **ap1;
1869 ap = ap1 = param->p;
1870 while (*ap)
1871 free(*ap++);
1872 free(ap1);
Denis Vlasenko01631112007-12-16 17:20:38 +00001873 }
1874}
1875
1876#if ENABLE_ASH_GETOPTS
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02001877static void FAST_FUNC getoptsreset(const char *value);
Denis Vlasenko01631112007-12-16 17:20:38 +00001878#endif
1879
1880struct var {
1881 struct var *next; /* next entry in hash list */
1882 int flags; /* flags are defined above */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001883 const char *var_text; /* name=value */
1884 void (*var_func)(const char *) FAST_FUNC; /* function to be called when */
Denis Vlasenko01631112007-12-16 17:20:38 +00001885 /* the variable gets set/unset */
1886};
1887
1888struct localvar {
1889 struct localvar *next; /* next local variable in list */
1890 struct var *vp; /* the variable that was made local */
1891 int flags; /* saved flags */
1892 const char *text; /* saved text */
1893};
1894
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001895/* flags */
1896#define VEXPORT 0x01 /* variable is exported */
1897#define VREADONLY 0x02 /* variable cannot be modified */
1898#define VSTRFIXED 0x04 /* variable struct is statically allocated */
1899#define VTEXTFIXED 0x08 /* text is statically allocated */
1900#define VSTACK 0x10 /* text is allocated on the stack */
1901#define VUNSET 0x20 /* the variable is not set */
1902#define VNOFUNC 0x40 /* don't call the callback function */
1903#define VNOSET 0x80 /* do not set variable - just readonly test */
1904#define VNOSAVE 0x100 /* when text is on the heap before setvareq */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00001905#if ENABLE_ASH_RANDOM_SUPPORT
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00001906# define VDYNAMIC 0x200 /* dynamic variable */
1907#else
1908# define VDYNAMIC 0
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001909#endif
1910
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00001911
Denis Vlasenko01631112007-12-16 17:20:38 +00001912/* Need to be before varinit_data[] */
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00001913#if ENABLE_LOCALE_SUPPORT
Denys Vlasenko2634bf32009-06-09 18:40:07 +02001914static void FAST_FUNC
Denis Vlasenkoa8915072007-02-23 21:10:06 +00001915change_lc_all(const char *value)
1916{
1917 if (value && *value != '\0')
1918 setlocale(LC_ALL, value);
1919}
Denys Vlasenko2634bf32009-06-09 18:40:07 +02001920static void FAST_FUNC
Denis Vlasenkoa8915072007-02-23 21:10:06 +00001921change_lc_ctype(const char *value)
1922{
1923 if (value && *value != '\0')
1924 setlocale(LC_CTYPE, value);
1925}
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00001926#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001927#if ENABLE_ASH_MAIL
1928static void chkmail(void);
Denys Vlasenko8c52f802011-02-04 17:36:21 +01001929static void changemail(const char *var_value) FAST_FUNC;
1930#else
1931# define chkmail() ((void)0)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001932#endif
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02001933static void changepath(const char *) FAST_FUNC;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001934#if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02001935static void change_random(const char *) FAST_FUNC;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001936#endif
1937
Denis Vlasenko01631112007-12-16 17:20:38 +00001938static const struct {
1939 int flags;
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001940 const char *var_text;
1941 void (*var_func)(const char *) FAST_FUNC;
Denis Vlasenko01631112007-12-16 17:20:38 +00001942} varinit_data[] = {
Denys Vlasenko566a3132012-07-07 21:40:35 +02001943 /*
1944 * Note: VEXPORT would not work correctly here for NOFORK applets:
1945 * some environment strings may be constant.
1946 */
Denis Vlasenko01631112007-12-16 17:20:38 +00001947 { VSTRFIXED|VTEXTFIXED , defifsvar , NULL },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001948#if ENABLE_ASH_MAIL
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001949 { VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL" , changemail },
1950 { VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH" , changemail },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001951#endif
Denis Vlasenko01631112007-12-16 17:20:38 +00001952 { VSTRFIXED|VTEXTFIXED , bb_PATH_root_path, changepath },
1953 { VSTRFIXED|VTEXTFIXED , "PS1=$ " , NULL },
1954 { VSTRFIXED|VTEXTFIXED , "PS2=> " , NULL },
1955 { VSTRFIXED|VTEXTFIXED , "PS4=+ " , NULL },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001956#if ENABLE_ASH_GETOPTS
Denys Vlasenkoe627ac92016-09-30 14:36:59 +02001957 { VSTRFIXED|VTEXTFIXED , defoptindvar, getoptsreset },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001958#endif
1959#if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001960 { VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM", change_random },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001961#endif
1962#if ENABLE_LOCALE_SUPPORT
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001963 { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_ALL" , change_lc_all },
1964 { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_CTYPE" , change_lc_ctype },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001965#endif
1966#if ENABLE_FEATURE_EDITING_SAVEHISTORY
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001967 { VSTRFIXED|VTEXTFIXED|VUNSET, "HISTFILE" , NULL },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001968#endif
1969};
1970
Denis Vlasenko0b769642008-07-24 07:54:57 +00001971struct redirtab;
Denis Vlasenko01631112007-12-16 17:20:38 +00001972
1973struct globals_var {
1974 struct shparam shellparam; /* $@ current positional parameters */
1975 struct redirtab *redirlist;
Denis Vlasenko01631112007-12-16 17:20:38 +00001976 int preverrout_fd; /* save fd2 before print debug if xflag is set. */
1977 struct var *vartab[VTABSIZE];
1978 struct var varinit[ARRAY_SIZE(varinit_data)];
1979};
Denis Vlasenko574f2f42008-02-27 18:41:59 +00001980extern struct globals_var *const ash_ptr_to_globals_var;
1981#define G_var (*ash_ptr_to_globals_var)
Denis Vlasenko01631112007-12-16 17:20:38 +00001982#define shellparam (G_var.shellparam )
Denis Vlasenko0b769642008-07-24 07:54:57 +00001983//#define redirlist (G_var.redirlist )
Denis Vlasenko01631112007-12-16 17:20:38 +00001984#define preverrout_fd (G_var.preverrout_fd)
1985#define vartab (G_var.vartab )
1986#define varinit (G_var.varinit )
1987#define INIT_G_var() do { \
Denis Vlasenko6b06cb82008-05-15 21:30:45 +00001988 unsigned i; \
Denis Vlasenko574f2f42008-02-27 18:41:59 +00001989 (*(struct globals_var**)&ash_ptr_to_globals_var) = xzalloc(sizeof(G_var)); \
1990 barrier(); \
Denis Vlasenko01631112007-12-16 17:20:38 +00001991 for (i = 0; i < ARRAY_SIZE(varinit_data); i++) { \
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001992 varinit[i].flags = varinit_data[i].flags; \
1993 varinit[i].var_text = varinit_data[i].var_text; \
1994 varinit[i].var_func = varinit_data[i].var_func; \
Denis Vlasenko01631112007-12-16 17:20:38 +00001995 } \
1996} while (0)
1997
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00001998#define vifs varinit[0]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001999#if ENABLE_ASH_MAIL
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002000# define vmail (&vifs)[1]
2001# define vmpath (&vmail)[1]
2002# define vpath (&vmpath)[1]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002003#else
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002004# define vpath (&vifs)[1]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002005#endif
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002006#define vps1 (&vpath)[1]
2007#define vps2 (&vps1)[1]
2008#define vps4 (&vps2)[1]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002009#if ENABLE_ASH_GETOPTS
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002010# define voptind (&vps4)[1]
2011# if ENABLE_ASH_RANDOM_SUPPORT
2012# define vrandom (&voptind)[1]
2013# endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002014#else
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002015# if ENABLE_ASH_RANDOM_SUPPORT
2016# define vrandom (&vps4)[1]
2017# endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002018#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002019
2020/*
2021 * The following macros access the values of the above variables.
2022 * They have to skip over the name. They return the null string
2023 * for unset variables.
2024 */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002025#define ifsval() (vifs.var_text + 4)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002026#define ifsset() ((vifs.flags & VUNSET) == 0)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002027#if ENABLE_ASH_MAIL
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002028# define mailval() (vmail.var_text + 5)
2029# define mpathval() (vmpath.var_text + 9)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002030# define mpathset() ((vmpath.flags & VUNSET) == 0)
2031#endif
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002032#define pathval() (vpath.var_text + 5)
2033#define ps1val() (vps1.var_text + 4)
2034#define ps2val() (vps2.var_text + 4)
2035#define ps4val() (vps4.var_text + 4)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002036#if ENABLE_ASH_GETOPTS
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002037# define optindval() (voptind.var_text + 7)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002038#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002039
Denis Vlasenko01631112007-12-16 17:20:38 +00002040#if ENABLE_ASH_GETOPTS
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02002041static void FAST_FUNC
Denis Vlasenko01631112007-12-16 17:20:38 +00002042getoptsreset(const char *value)
2043{
Denys Vlasenkoa513bf32016-10-26 02:03:37 +02002044 shellparam.optind = number(value) ?: 1;
Denis Vlasenko01631112007-12-16 17:20:38 +00002045 shellparam.optoff = -1;
2046}
2047#endif
2048
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002049/*
2050 * Compares two strings up to the first = or '\0'. The first
2051 * string must be terminated by '='; the second may be terminated by
2052 * either '=' or '\0'.
2053 */
2054static int
2055varcmp(const char *p, const char *q)
2056{
2057 int c, d;
2058
2059 while ((c = *p) == (d = *q)) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02002060 if (c == '\0' || c == '=')
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002061 goto out;
2062 p++;
2063 q++;
2064 }
2065 if (c == '=')
Denis Vlasenko9650f362007-02-23 01:04:37 +00002066 c = '\0';
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002067 if (d == '=')
Denis Vlasenko9650f362007-02-23 01:04:37 +00002068 d = '\0';
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002069 out:
2070 return c - d;
2071}
2072
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002073/*
2074 * Find the appropriate entry in the hash table from the name.
2075 */
2076static struct var **
2077hashvar(const char *p)
2078{
2079 unsigned hashval;
2080
2081 hashval = ((unsigned char) *p) << 4;
2082 while (*p && *p != '=')
2083 hashval += (unsigned char) *p++;
2084 return &vartab[hashval % VTABSIZE];
2085}
2086
2087static int
2088vpcmp(const void *a, const void *b)
2089{
2090 return varcmp(*(const char **)a, *(const char **)b);
2091}
2092
2093/*
2094 * This routine initializes the builtin variables.
2095 */
2096static void
2097initvar(void)
2098{
2099 struct var *vp;
2100 struct var *end;
2101 struct var **vpp;
2102
2103 /*
2104 * PS1 depends on uid
2105 */
2106#if ENABLE_FEATURE_EDITING && ENABLE_FEATURE_EDITING_FANCY_PROMPT
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002107 vps1.var_text = "PS1=\\w \\$ ";
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002108#else
2109 if (!geteuid())
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002110 vps1.var_text = "PS1=# ";
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002111#endif
2112 vp = varinit;
Denis Vlasenko80b8b392007-06-25 10:55:35 +00002113 end = vp + ARRAY_SIZE(varinit);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002114 do {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002115 vpp = hashvar(vp->var_text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002116 vp->next = *vpp;
2117 *vpp = vp;
2118 } while (++vp < end);
2119}
2120
2121static struct var **
2122findvar(struct var **vpp, const char *name)
2123{
2124 for (; *vpp; vpp = &(*vpp)->next) {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002125 if (varcmp((*vpp)->var_text, name) == 0) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002126 break;
2127 }
2128 }
2129 return vpp;
2130}
2131
2132/*
2133 * Find the value of a variable. Returns NULL if not set.
2134 */
Denys Vlasenko03dad222010-01-12 23:29:57 +01002135static const char* FAST_FUNC
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002136lookupvar(const char *name)
2137{
2138 struct var *v;
2139
2140 v = *findvar(hashvar(name), name);
2141 if (v) {
Denis Vlasenko448d30e2008-06-27 00:24:11 +00002142#if ENABLE_ASH_RANDOM_SUPPORT
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002143 /*
2144 * Dynamic variables are implemented roughly the same way they are
2145 * in bash. Namely, they're "special" so long as they aren't unset.
2146 * As soon as they're unset, they're no longer dynamic, and dynamic
2147 * lookup will no longer happen at that point. -- PFM.
2148 */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002149 if (v->flags & VDYNAMIC)
2150 v->var_func(NULL);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002151#endif
2152 if (!(v->flags & VUNSET))
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002153 return var_end(v->var_text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002154 }
2155 return NULL;
2156}
2157
Denys Vlasenko0b883582016-12-23 16:49:07 +01002158#if ENABLE_UNICODE_SUPPORT
Denys Vlasenko37dc08b2016-10-02 04:38:07 +02002159static void
2160reinit_unicode_for_ash(void)
Denys Vlasenkoe9ab07c2014-08-13 18:00:08 +02002161{
2162 /* Unicode support should be activated even if LANG is set
2163 * _during_ shell execution, not only if it was set when
2164 * shell was started. Therefore, re-check LANG every time:
2165 */
2166 if (ENABLE_FEATURE_CHECK_UNICODE_IN_ENV
2167 || ENABLE_UNICODE_USING_LOCALE
2168 ) {
2169 const char *s = lookupvar("LC_ALL");
2170 if (!s) s = lookupvar("LC_CTYPE");
2171 if (!s) s = lookupvar("LANG");
2172 reinit_unicode(s);
2173 }
2174}
Denys Vlasenko0b883582016-12-23 16:49:07 +01002175#else
2176# define reinit_unicode_for_ash() ((void)0)
2177#endif
Denys Vlasenkoe9ab07c2014-08-13 18:00:08 +02002178
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002179/*
2180 * Search the environment of a builtin command.
2181 */
Mike Frysinger98c52642009-04-02 10:02:37 +00002182static const char *
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002183bltinlookup(const char *name)
2184{
2185 struct strlist *sp;
2186
2187 for (sp = cmdenviron; sp; sp = sp->next) {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002188 if (varcmp(sp->text, name) == 0)
2189 return var_end(sp->text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002190 }
2191 return lookupvar(name);
2192}
2193
2194/*
2195 * Same as setvar except that the variable and value are passed in
2196 * the first argument as name=value. Since the first argument will
2197 * be actually stored in the table, it should not be a string that
2198 * will go away.
2199 * Called with interrupts off.
2200 */
2201static void
2202setvareq(char *s, int flags)
2203{
2204 struct var *vp, **vpp;
2205
2206 vpp = hashvar(s);
2207 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
2208 vp = *findvar(vpp, s);
2209 if (vp) {
2210 if ((vp->flags & (VREADONLY|VDYNAMIC)) == VREADONLY) {
2211 const char *n;
2212
2213 if (flags & VNOSAVE)
2214 free(s);
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002215 n = vp->var_text;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +02002216 exitstatus = 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002217 ash_msg_and_raise_error("%.*s: is read only", strchrnul(n, '=') - n, n);
2218 }
2219
2220 if (flags & VNOSET)
2221 return;
2222
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002223 if (vp->var_func && !(flags & VNOFUNC))
2224 vp->var_func(var_end(s));
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002225
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002226 if (!(vp->flags & (VTEXTFIXED|VSTACK)))
2227 free((char*)vp->var_text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002228
2229 flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
2230 } else {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002231 /* variable s is not found */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002232 if (flags & VNOSET)
2233 return;
Denis Vlasenko597906c2008-02-20 16:38:54 +00002234 vp = ckzalloc(sizeof(*vp));
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002235 vp->next = *vpp;
Denis Vlasenko597906c2008-02-20 16:38:54 +00002236 /*vp->func = NULL; - ckzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002237 *vpp = vp;
2238 }
2239 if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE)))
2240 s = ckstrdup(s);
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002241 vp->var_text = s;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002242 vp->flags = flags;
2243}
2244
2245/*
2246 * Set the value of a variable. The flags argument is ored with the
2247 * flags of the variable. If val is NULL, the variable is unset.
2248 */
2249static void
2250setvar(const char *name, const char *val, int flags)
2251{
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002252 const char *q;
2253 char *p;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002254 char *nameeq;
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002255 size_t namelen;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002256 size_t vallen;
2257
2258 q = endofname(name);
2259 p = strchrnul(q, '=');
2260 namelen = p - name;
2261 if (!namelen || p != q)
2262 ash_msg_and_raise_error("%.*s: bad variable name", namelen, name);
2263 vallen = 0;
2264 if (val == NULL) {
2265 flags |= VUNSET;
2266 } else {
2267 vallen = strlen(val);
2268 }
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002269
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002270 INT_OFF;
2271 nameeq = ckmalloc(namelen + vallen + 2);
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002272 p = memcpy(nameeq, name, namelen) + namelen;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002273 if (val) {
2274 *p++ = '=';
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002275 p = memcpy(p, val, vallen) + vallen;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002276 }
2277 *p = '\0';
2278 setvareq(nameeq, flags | VNOSAVE);
2279 INT_ON;
2280}
2281
Denys Vlasenko03dad222010-01-12 23:29:57 +01002282static void FAST_FUNC
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02002283setvar0(const char *name, const char *val)
Denys Vlasenko03dad222010-01-12 23:29:57 +01002284{
2285 setvar(name, val, 0);
2286}
2287
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002288/*
2289 * Unset the specified variable.
2290 */
2291static int
2292unsetvar(const char *s)
2293{
2294 struct var **vpp;
2295 struct var *vp;
2296 int retval;
2297
2298 vpp = findvar(hashvar(s), s);
2299 vp = *vpp;
2300 retval = 2;
2301 if (vp) {
2302 int flags = vp->flags;
2303
2304 retval = 1;
2305 if (flags & VREADONLY)
2306 goto out;
Denis Vlasenko448d30e2008-06-27 00:24:11 +00002307#if ENABLE_ASH_RANDOM_SUPPORT
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002308 vp->flags &= ~VDYNAMIC;
2309#endif
2310 if (flags & VUNSET)
2311 goto ok;
2312 if ((flags & VSTRFIXED) == 0) {
2313 INT_OFF;
2314 if ((flags & (VTEXTFIXED|VSTACK)) == 0)
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002315 free((char*)vp->var_text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002316 *vpp = vp->next;
2317 free(vp);
2318 INT_ON;
2319 } else {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02002320 setvar0(s, NULL);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002321 vp->flags &= ~VEXPORT;
2322 }
2323 ok:
2324 retval = 0;
2325 }
2326 out:
2327 return retval;
2328}
2329
2330/*
2331 * Process a linked list of variable assignments.
2332 */
2333static void
2334listsetvar(struct strlist *list_set_var, int flags)
2335{
2336 struct strlist *lp = list_set_var;
2337
2338 if (!lp)
2339 return;
2340 INT_OFF;
2341 do {
2342 setvareq(lp->text, flags);
Denis Vlasenko9650f362007-02-23 01:04:37 +00002343 lp = lp->next;
2344 } while (lp);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002345 INT_ON;
2346}
2347
2348/*
2349 * Generate a list of variables satisfying the given conditions.
2350 */
2351static char **
2352listvars(int on, int off, char ***end)
2353{
2354 struct var **vpp;
2355 struct var *vp;
2356 char **ep;
2357 int mask;
2358
2359 STARTSTACKSTR(ep);
2360 vpp = vartab;
2361 mask = on | off;
2362 do {
2363 for (vp = *vpp; vp; vp = vp->next) {
2364 if ((vp->flags & mask) == on) {
2365 if (ep == stackstrend())
2366 ep = growstackstr();
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002367 *ep++ = (char*)vp->var_text;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002368 }
2369 }
2370 } while (++vpp < vartab + VTABSIZE);
2371 if (ep == stackstrend())
2372 ep = growstackstr();
2373 if (end)
2374 *end = ep;
2375 *ep++ = NULL;
2376 return grabstackstr(ep);
2377}
2378
2379
2380/* ============ Path search helper
2381 *
2382 * The variable path (passed by reference) should be set to the start
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002383 * of the path before the first call; path_advance will update
2384 * this value as it proceeds. Successive calls to path_advance will return
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002385 * the possible path expansions in sequence. If an option (indicated by
2386 * a percent sign) appears in the path entry then the global variable
2387 * pathopt will be set to point to it; otherwise pathopt will be set to
2388 * NULL.
2389 */
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002390static const char *pathopt; /* set by path_advance */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002391
2392static char *
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002393path_advance(const char **path, const char *name)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002394{
2395 const char *p;
2396 char *q;
2397 const char *start;
2398 size_t len;
2399
2400 if (*path == NULL)
2401 return NULL;
2402 start = *path;
Denis Vlasenkof7d56652008-03-25 05:51:41 +00002403 for (p = start; *p && *p != ':' && *p != '%'; p++)
2404 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002405 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
2406 while (stackblocksize() < len)
2407 growstackblock();
2408 q = stackblock();
2409 if (p != start) {
2410 memcpy(q, start, p - start);
2411 q += p - start;
2412 *q++ = '/';
2413 }
2414 strcpy(q, name);
2415 pathopt = NULL;
2416 if (*p == '%') {
2417 pathopt = ++p;
Denis Vlasenkof7d56652008-03-25 05:51:41 +00002418 while (*p && *p != ':')
2419 p++;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002420 }
2421 if (*p == ':')
2422 *path = p + 1;
2423 else
2424 *path = NULL;
2425 return stalloc(len);
2426}
2427
2428
2429/* ============ Prompt */
2430
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +00002431static smallint doprompt; /* if set, prompt the user */
2432static smallint needprompt; /* true if interactive and at start of line */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002433
2434#if ENABLE_FEATURE_EDITING
2435static line_input_t *line_input_state;
2436static const char *cmdedit_prompt;
2437static void
2438putprompt(const char *s)
2439{
2440 if (ENABLE_ASH_EXPAND_PRMT) {
2441 free((char*)cmdedit_prompt);
Denis Vlasenko4222ae42007-02-25 02:37:49 +00002442 cmdedit_prompt = ckstrdup(s);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002443 return;
2444 }
2445 cmdedit_prompt = s;
2446}
2447#else
2448static void
2449putprompt(const char *s)
2450{
2451 out2str(s);
2452}
2453#endif
2454
2455#if ENABLE_ASH_EXPAND_PRMT
2456/* expandstr() needs parsing machinery, so it is far away ahead... */
2457static const char *expandstr(const char *ps);
2458#else
2459#define expandstr(s) s
2460#endif
2461
2462static void
Denys Vlasenko958581a2010-09-12 15:04:27 +02002463setprompt_if(smallint do_set, int whichprompt)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002464{
2465 const char *prompt;
Denys Vlasenko958581a2010-09-12 15:04:27 +02002466 IF_ASH_EXPAND_PRMT(struct stackmark smark;)
2467
2468 if (!do_set)
2469 return;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002470
2471 needprompt = 0;
2472
2473 switch (whichprompt) {
2474 case 1:
2475 prompt = ps1val();
2476 break;
2477 case 2:
2478 prompt = ps2val();
2479 break;
2480 default: /* 0 */
2481 prompt = nullstr;
2482 }
2483#if ENABLE_ASH_EXPAND_PRMT
Denys Vlasenko60ca8342016-09-30 11:21:21 +02002484 pushstackmark(&smark, stackblocksize());
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002485#endif
2486 putprompt(expandstr(prompt));
2487#if ENABLE_ASH_EXPAND_PRMT
2488 popstackmark(&smark);
2489#endif
2490}
2491
2492
2493/* ============ The cd and pwd commands */
2494
2495#define CD_PHYSICAL 1
2496#define CD_PRINT 2
2497
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002498static int
2499cdopt(void)
2500{
2501 int flags = 0;
2502 int i, j;
2503
2504 j = 'L';
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02002505 while ((i = nextopt("LP")) != '\0') {
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002506 if (i != j) {
2507 flags ^= CD_PHYSICAL;
2508 j = i;
2509 }
2510 }
2511
2512 return flags;
2513}
2514
2515/*
2516 * Update curdir (the name of the current directory) in response to a
2517 * cd command.
2518 */
2519static const char *
2520updatepwd(const char *dir)
2521{
2522 char *new;
2523 char *p;
2524 char *cdcomppath;
2525 const char *lim;
2526
Denys Vlasenko8e2bc472016-09-28 23:02:57 +02002527 cdcomppath = sstrdup(dir);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002528 STARTSTACKSTR(new);
2529 if (*dir != '/') {
2530 if (curdir == nullstr)
2531 return 0;
2532 new = stack_putstr(curdir, new);
2533 }
2534 new = makestrspace(strlen(dir) + 2, new);
Denis Vlasenko29eb3592008-05-18 14:06:08 +00002535 lim = (char *)stackblock() + 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002536 if (*dir != '/') {
2537 if (new[-1] != '/')
2538 USTPUTC('/', new);
2539 if (new > lim && *lim == '/')
2540 lim++;
2541 } else {
2542 USTPUTC('/', new);
2543 cdcomppath++;
2544 if (dir[1] == '/' && dir[2] != '/') {
2545 USTPUTC('/', new);
2546 cdcomppath++;
2547 lim++;
2548 }
2549 }
2550 p = strtok(cdcomppath, "/");
2551 while (p) {
2552 switch (*p) {
2553 case '.':
2554 if (p[1] == '.' && p[2] == '\0') {
2555 while (new > lim) {
2556 STUNPUTC(new);
2557 if (new[-1] == '/')
2558 break;
2559 }
2560 break;
Denis Vlasenko16abcd92007-04-13 23:59:52 +00002561 }
2562 if (p[1] == '\0')
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002563 break;
2564 /* fall through */
2565 default:
2566 new = stack_putstr(p, new);
2567 USTPUTC('/', new);
2568 }
Denys Vlasenko00da72b2015-10-23 18:43:16 +02002569 p = strtok(NULL, "/");
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002570 }
2571 if (new > lim)
2572 STUNPUTC(new);
2573 *new = 0;
2574 return stackblock();
2575}
2576
2577/*
2578 * Find out what the current directory is. If we already know the current
2579 * directory, this routine returns immediately.
2580 */
2581static char *
2582getpwd(void)
2583{
Denis Vlasenko01631112007-12-16 17:20:38 +00002584 char *dir = getcwd(NULL, 0); /* huh, using glibc extension? */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002585 return dir ? dir : nullstr;
2586}
2587
2588static void
2589setpwd(const char *val, int setold)
2590{
2591 char *oldcur, *dir;
2592
2593 oldcur = dir = curdir;
2594
2595 if (setold) {
2596 setvar("OLDPWD", oldcur, VEXPORT);
2597 }
2598 INT_OFF;
2599 if (physdir != nullstr) {
2600 if (physdir != oldcur)
2601 free(physdir);
2602 physdir = nullstr;
2603 }
2604 if (oldcur == val || !val) {
2605 char *s = getpwd();
2606 physdir = s;
2607 if (!val)
2608 dir = s;
2609 } else
2610 dir = ckstrdup(val);
2611 if (oldcur != dir && oldcur != nullstr) {
2612 free(oldcur);
2613 }
2614 curdir = dir;
2615 INT_ON;
2616 setvar("PWD", dir, VEXPORT);
2617}
2618
2619static void hashcd(void);
2620
2621/*
Denys Vlasenko70392332016-10-27 02:31:55 +02002622 * Actually do the chdir. We also call hashcd to let other routines
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002623 * know that the current directory has changed.
2624 */
2625static int
2626docd(const char *dest, int flags)
2627{
Denys Vlasenko4b1100e2010-03-05 14:10:54 +01002628 const char *dir = NULL;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002629 int err;
2630
2631 TRACE(("docd(\"%s\", %d) called\n", dest, flags));
2632
2633 INT_OFF;
2634 if (!(flags & CD_PHYSICAL)) {
2635 dir = updatepwd(dest);
2636 if (dir)
2637 dest = dir;
2638 }
2639 err = chdir(dest);
2640 if (err)
2641 goto out;
2642 setpwd(dir, 1);
2643 hashcd();
2644 out:
2645 INT_ON;
2646 return err;
2647}
2648
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02002649static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00002650cdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002651{
2652 const char *dest;
2653 const char *path;
2654 const char *p;
2655 char c;
2656 struct stat statb;
2657 int flags;
2658
2659 flags = cdopt();
2660 dest = *argptr;
2661 if (!dest)
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02002662 dest = bltinlookup("HOME");
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002663 else if (LONE_DASH(dest)) {
2664 dest = bltinlookup("OLDPWD");
2665 flags |= CD_PRINT;
2666 }
2667 if (!dest)
2668 dest = nullstr;
2669 if (*dest == '/')
Denys Vlasenko0e081d02016-10-26 19:56:05 +02002670 goto step6;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002671 if (*dest == '.') {
2672 c = dest[1];
2673 dotdot:
2674 switch (c) {
2675 case '\0':
2676 case '/':
2677 goto step6;
2678 case '.':
2679 c = dest[2];
2680 if (c != '.')
2681 goto dotdot;
2682 }
2683 }
2684 if (!*dest)
2685 dest = ".";
2686 path = bltinlookup("CDPATH");
Denys Vlasenko0e081d02016-10-26 19:56:05 +02002687 while (path) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002688 c = *path;
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002689 p = path_advance(&path, dest);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002690 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
2691 if (c && c != ':')
2692 flags |= CD_PRINT;
2693 docd:
2694 if (!docd(p, flags))
2695 goto out;
Denys Vlasenko0e081d02016-10-26 19:56:05 +02002696 goto err;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002697 }
Denys Vlasenko0e081d02016-10-26 19:56:05 +02002698 }
2699
2700 step6:
2701 p = dest;
2702 goto docd;
2703
2704 err:
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002705 ash_msg_and_raise_error("can't cd to %s", dest);
2706 /* NOTREACHED */
2707 out:
2708 if (flags & CD_PRINT)
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02002709 out1fmt("%s\n", curdir);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002710 return 0;
2711}
2712
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02002713static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00002714pwdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002715{
2716 int flags;
2717 const char *dir = curdir;
2718
2719 flags = cdopt();
2720 if (flags) {
2721 if (physdir == nullstr)
2722 setpwd(dir, 0);
2723 dir = physdir;
2724 }
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02002725 out1fmt("%s\n", dir);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002726 return 0;
2727}
2728
Denis Vlasenko0c032a42007-02-23 01:03:40 +00002729
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00002730/* ============ ... */
Eric Andersenc470f442003-07-28 09:56:35 +00002731
Denis Vlasenko834dee72008-10-07 09:18:30 +00002732
Denys Vlasenko82dd14a2010-05-17 10:10:01 +02002733#define IBUFSIZ (ENABLE_FEATURE_EDITING ? CONFIG_FEATURE_EDITING_MAX_LEN : 1024)
Eric Andersenc470f442003-07-28 09:56:35 +00002734
Eric Andersenc470f442003-07-28 09:56:35 +00002735/* Syntax classes */
Denis Vlasenko834dee72008-10-07 09:18:30 +00002736#define CWORD 0 /* character is nothing special */
2737#define CNL 1 /* newline character */
2738#define CBACK 2 /* a backslash character */
2739#define CSQUOTE 3 /* single quote */
2740#define CDQUOTE 4 /* double quote */
Eric Andersenc470f442003-07-28 09:56:35 +00002741#define CENDQUOTE 5 /* a terminating quote */
Denis Vlasenko834dee72008-10-07 09:18:30 +00002742#define CBQUOTE 6 /* backwards single quote */
2743#define CVAR 7 /* a dollar sign */
2744#define CENDVAR 8 /* a '}' character */
2745#define CLP 9 /* a left paren in arithmetic */
2746#define CRP 10 /* a right paren in arithmetic */
Eric Andersenc470f442003-07-28 09:56:35 +00002747#define CENDFILE 11 /* end of file */
Denis Vlasenko834dee72008-10-07 09:18:30 +00002748#define CCTL 12 /* like CWORD, except it must be escaped */
2749#define CSPCL 13 /* these terminate a word */
2750#define CIGN 14 /* character should be ignored */
Eric Andersenc470f442003-07-28 09:56:35 +00002751
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002752#define PEOF 256
Denis Vlasenko131ae172007-02-18 13:00:19 +00002753#if ENABLE_ASH_ALIAS
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002754# define PEOA 257
Eric Andersenc470f442003-07-28 09:56:35 +00002755#endif
2756
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002757#define USE_SIT_FUNCTION ENABLE_ASH_OPTIMIZE_FOR_SIZE
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002758
Denys Vlasenko0b883582016-12-23 16:49:07 +01002759#if ENABLE_FEATURE_SH_MATH
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002760# define SIT_ITEM(a,b,c,d) (a | (b << 4) | (c << 8) | (d << 12))
Eric Andersenc470f442003-07-28 09:56:35 +00002761#else
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002762# define SIT_ITEM(a,b,c,d) (a | (b << 4) | (c << 8))
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002763#endif
Denys Vlasenko3e134eb2016-04-22 18:09:21 +02002764static const uint16_t S_I_T[] ALIGN2 = {
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002765#if ENABLE_ASH_ALIAS
2766 SIT_ITEM(CSPCL , CIGN , CIGN , CIGN ), /* 0, PEOA */
2767#endif
2768 SIT_ITEM(CSPCL , CWORD , CWORD, CWORD ), /* 1, ' ' */
2769 SIT_ITEM(CNL , CNL , CNL , CNL ), /* 2, \n */
2770 SIT_ITEM(CWORD , CCTL , CCTL , CWORD ), /* 3, !*-/:=?[]~ */
2771 SIT_ITEM(CDQUOTE , CENDQUOTE, CWORD, CWORD ), /* 4, '"' */
2772 SIT_ITEM(CVAR , CVAR , CWORD, CVAR ), /* 5, $ */
2773 SIT_ITEM(CSQUOTE , CWORD , CENDQUOTE, CWORD), /* 6, "'" */
2774 SIT_ITEM(CSPCL , CWORD , CWORD, CLP ), /* 7, ( */
2775 SIT_ITEM(CSPCL , CWORD , CWORD, CRP ), /* 8, ) */
2776 SIT_ITEM(CBACK , CBACK , CCTL , CBACK ), /* 9, \ */
2777 SIT_ITEM(CBQUOTE , CBQUOTE , CWORD, CBQUOTE), /* 10, ` */
2778 SIT_ITEM(CENDVAR , CENDVAR , CWORD, CENDVAR), /* 11, } */
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002779#if !USE_SIT_FUNCTION
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002780 SIT_ITEM(CENDFILE, CENDFILE , CENDFILE, CENDFILE),/* 12, PEOF */
2781 SIT_ITEM(CWORD , CWORD , CWORD, CWORD ), /* 13, 0-9A-Za-z */
2782 SIT_ITEM(CCTL , CCTL , CCTL , CCTL ) /* 14, CTLESC ... */
2783#endif
2784#undef SIT_ITEM
Eric Andersenc470f442003-07-28 09:56:35 +00002785};
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002786/* Constants below must match table above */
2787enum {
2788#if ENABLE_ASH_ALIAS
2789 CSPCL_CIGN_CIGN_CIGN , /* 0 */
2790#endif
2791 CSPCL_CWORD_CWORD_CWORD , /* 1 */
2792 CNL_CNL_CNL_CNL , /* 2 */
2793 CWORD_CCTL_CCTL_CWORD , /* 3 */
2794 CDQUOTE_CENDQUOTE_CWORD_CWORD , /* 4 */
2795 CVAR_CVAR_CWORD_CVAR , /* 5 */
2796 CSQUOTE_CWORD_CENDQUOTE_CWORD , /* 6 */
2797 CSPCL_CWORD_CWORD_CLP , /* 7 */
2798 CSPCL_CWORD_CWORD_CRP , /* 8 */
2799 CBACK_CBACK_CCTL_CBACK , /* 9 */
2800 CBQUOTE_CBQUOTE_CWORD_CBQUOTE , /* 10 */
2801 CENDVAR_CENDVAR_CWORD_CENDVAR , /* 11 */
2802 CENDFILE_CENDFILE_CENDFILE_CENDFILE, /* 12 */
2803 CWORD_CWORD_CWORD_CWORD , /* 13 */
2804 CCTL_CCTL_CCTL_CCTL , /* 14 */
2805};
Eric Andersen2870d962001-07-02 17:27:21 +00002806
Denys Vlasenkocd716832009-11-28 22:14:02 +01002807/* c in SIT(c, syntax) must be an *unsigned char* or PEOA or PEOF,
2808 * caller must ensure proper cast on it if c is *char_ptr!
2809 */
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002810/* Values for syntax param */
2811#define BASESYNTAX 0 /* not in quotes */
2812#define DQSYNTAX 1 /* in double quotes */
2813#define SQSYNTAX 2 /* in single quotes */
2814#define ARISYNTAX 3 /* in arithmetic */
2815#define PSSYNTAX 4 /* prompt. never passed to SIT() */
Denys Vlasenkocd716832009-11-28 22:14:02 +01002816
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002817#if USE_SIT_FUNCTION
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002818
Denis Vlasenko0c032a42007-02-23 01:03:40 +00002819static int
2820SIT(int c, int syntax)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002821{
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02002822 /* Used to also have '/' in this string: "\t\n !\"$&'()*-/:;<=>?[\\]`|}~" */
2823 static const char spec_symbls[] ALIGN1 = "\t\n !\"$&'()*-:;<=>?[\\]`|}~";
2824 /*
2825 * This causes '/' to be prepended with CTLESC in dquoted string,
2826 * making "./file"* treated incorrectly because we feed
2827 * ".\/file*" string to glob(), confusing it (see expandmeta func).
2828 * The "homegrown" glob implementation is okay with that,
2829 * but glibc one isn't. With '/' always treated as CWORD,
2830 * both work fine.
2831 */
Denys Vlasenkocd716832009-11-28 22:14:02 +01002832# if ENABLE_ASH_ALIAS
2833 static const uint8_t syntax_index_table[] ALIGN1 = {
Eric Andersenc470f442003-07-28 09:56:35 +00002834 1, 2, 1, 3, 4, 5, 1, 6, /* "\t\n !\"$&'" */
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02002835 7, 8, 3, 3,/*3,*/3, 1, 1, /* "()*-/:;<" */
Eric Andersenc470f442003-07-28 09:56:35 +00002836 3, 1, 3, 3, 9, 3, 10, 1, /* "=>?[\\]`|" */
2837 11, 3 /* "}~" */
2838 };
Denys Vlasenkocd716832009-11-28 22:14:02 +01002839# else
2840 static const uint8_t syntax_index_table[] ALIGN1 = {
Eric Andersenc470f442003-07-28 09:56:35 +00002841 0, 1, 0, 2, 3, 4, 0, 5, /* "\t\n !\"$&'" */
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02002842 6, 7, 2, 2,/*2,*/2, 0, 0, /* "()*-/:;<" */
Eric Andersenc470f442003-07-28 09:56:35 +00002843 2, 0, 2, 2, 8, 2, 9, 0, /* "=>?[\\]`|" */
2844 10, 2 /* "}~" */
2845 };
Denys Vlasenkocd716832009-11-28 22:14:02 +01002846# endif
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002847 const char *s;
2848 int indx;
2849
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002850 if (c == PEOF)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002851 return CENDFILE;
Denys Vlasenkocd716832009-11-28 22:14:02 +01002852# if ENABLE_ASH_ALIAS
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002853 if (c == PEOA)
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002854 indx = 0;
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002855 else
Denys Vlasenkocd716832009-11-28 22:14:02 +01002856# endif
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002857 {
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002858 /* Cast is purely for paranoia here,
2859 * just in case someone passed signed char to us */
2860 if ((unsigned char)c >= CTL_FIRST
2861 && (unsigned char)c <= CTL_LAST
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002862 ) {
2863 return CCTL;
2864 }
2865 s = strchrnul(spec_symbls, c);
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002866 if (*s == '\0')
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002867 return CWORD;
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002868 indx = syntax_index_table[s - spec_symbls];
2869 }
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002870 return (S_I_T[indx] >> (syntax*4)) & 0xf;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002871}
2872
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00002873#else /* !USE_SIT_FUNCTION */
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002874
Denys Vlasenko3e134eb2016-04-22 18:09:21 +02002875static const uint8_t syntax_index_table[] ALIGN1 = {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002876 /* BASESYNTAX_DQSYNTAX_SQSYNTAX_ARISYNTAX */
Denys Vlasenkocd716832009-11-28 22:14:02 +01002877 /* 0 */ CWORD_CWORD_CWORD_CWORD,
2878 /* 1 */ CWORD_CWORD_CWORD_CWORD,
2879 /* 2 */ CWORD_CWORD_CWORD_CWORD,
2880 /* 3 */ CWORD_CWORD_CWORD_CWORD,
2881 /* 4 */ CWORD_CWORD_CWORD_CWORD,
2882 /* 5 */ CWORD_CWORD_CWORD_CWORD,
2883 /* 6 */ CWORD_CWORD_CWORD_CWORD,
2884 /* 7 */ CWORD_CWORD_CWORD_CWORD,
2885 /* 8 */ CWORD_CWORD_CWORD_CWORD,
2886 /* 9 "\t" */ CSPCL_CWORD_CWORD_CWORD,
2887 /* 10 "\n" */ CNL_CNL_CNL_CNL,
2888 /* 11 */ CWORD_CWORD_CWORD_CWORD,
2889 /* 12 */ CWORD_CWORD_CWORD_CWORD,
2890 /* 13 */ CWORD_CWORD_CWORD_CWORD,
2891 /* 14 */ CWORD_CWORD_CWORD_CWORD,
2892 /* 15 */ CWORD_CWORD_CWORD_CWORD,
2893 /* 16 */ CWORD_CWORD_CWORD_CWORD,
2894 /* 17 */ CWORD_CWORD_CWORD_CWORD,
2895 /* 18 */ CWORD_CWORD_CWORD_CWORD,
2896 /* 19 */ CWORD_CWORD_CWORD_CWORD,
2897 /* 20 */ CWORD_CWORD_CWORD_CWORD,
2898 /* 21 */ CWORD_CWORD_CWORD_CWORD,
2899 /* 22 */ CWORD_CWORD_CWORD_CWORD,
2900 /* 23 */ CWORD_CWORD_CWORD_CWORD,
2901 /* 24 */ CWORD_CWORD_CWORD_CWORD,
2902 /* 25 */ CWORD_CWORD_CWORD_CWORD,
2903 /* 26 */ CWORD_CWORD_CWORD_CWORD,
2904 /* 27 */ CWORD_CWORD_CWORD_CWORD,
2905 /* 28 */ CWORD_CWORD_CWORD_CWORD,
2906 /* 29 */ CWORD_CWORD_CWORD_CWORD,
2907 /* 30 */ CWORD_CWORD_CWORD_CWORD,
2908 /* 31 */ CWORD_CWORD_CWORD_CWORD,
2909 /* 32 " " */ CSPCL_CWORD_CWORD_CWORD,
2910 /* 33 "!" */ CWORD_CCTL_CCTL_CWORD,
2911 /* 34 """ */ CDQUOTE_CENDQUOTE_CWORD_CWORD,
2912 /* 35 "#" */ CWORD_CWORD_CWORD_CWORD,
2913 /* 36 "$" */ CVAR_CVAR_CWORD_CVAR,
2914 /* 37 "%" */ CWORD_CWORD_CWORD_CWORD,
2915 /* 38 "&" */ CSPCL_CWORD_CWORD_CWORD,
2916 /* 39 "'" */ CSQUOTE_CWORD_CENDQUOTE_CWORD,
2917 /* 40 "(" */ CSPCL_CWORD_CWORD_CLP,
2918 /* 41 ")" */ CSPCL_CWORD_CWORD_CRP,
2919 /* 42 "*" */ CWORD_CCTL_CCTL_CWORD,
2920 /* 43 "+" */ CWORD_CWORD_CWORD_CWORD,
2921 /* 44 "," */ CWORD_CWORD_CWORD_CWORD,
2922 /* 45 "-" */ CWORD_CCTL_CCTL_CWORD,
2923 /* 46 "." */ CWORD_CWORD_CWORD_CWORD,
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02002924/* "/" was CWORD_CCTL_CCTL_CWORD, see comment in SIT() function why this is changed: */
2925 /* 47 "/" */ CWORD_CWORD_CWORD_CWORD,
Denys Vlasenkocd716832009-11-28 22:14:02 +01002926 /* 48 "0" */ CWORD_CWORD_CWORD_CWORD,
2927 /* 49 "1" */ CWORD_CWORD_CWORD_CWORD,
2928 /* 50 "2" */ CWORD_CWORD_CWORD_CWORD,
2929 /* 51 "3" */ CWORD_CWORD_CWORD_CWORD,
2930 /* 52 "4" */ CWORD_CWORD_CWORD_CWORD,
2931 /* 53 "5" */ CWORD_CWORD_CWORD_CWORD,
2932 /* 54 "6" */ CWORD_CWORD_CWORD_CWORD,
2933 /* 55 "7" */ CWORD_CWORD_CWORD_CWORD,
2934 /* 56 "8" */ CWORD_CWORD_CWORD_CWORD,
2935 /* 57 "9" */ CWORD_CWORD_CWORD_CWORD,
2936 /* 58 ":" */ CWORD_CCTL_CCTL_CWORD,
2937 /* 59 ";" */ CSPCL_CWORD_CWORD_CWORD,
2938 /* 60 "<" */ CSPCL_CWORD_CWORD_CWORD,
2939 /* 61 "=" */ CWORD_CCTL_CCTL_CWORD,
2940 /* 62 ">" */ CSPCL_CWORD_CWORD_CWORD,
2941 /* 63 "?" */ CWORD_CCTL_CCTL_CWORD,
2942 /* 64 "@" */ CWORD_CWORD_CWORD_CWORD,
2943 /* 65 "A" */ CWORD_CWORD_CWORD_CWORD,
2944 /* 66 "B" */ CWORD_CWORD_CWORD_CWORD,
2945 /* 67 "C" */ CWORD_CWORD_CWORD_CWORD,
2946 /* 68 "D" */ CWORD_CWORD_CWORD_CWORD,
2947 /* 69 "E" */ CWORD_CWORD_CWORD_CWORD,
2948 /* 70 "F" */ CWORD_CWORD_CWORD_CWORD,
2949 /* 71 "G" */ CWORD_CWORD_CWORD_CWORD,
2950 /* 72 "H" */ CWORD_CWORD_CWORD_CWORD,
2951 /* 73 "I" */ CWORD_CWORD_CWORD_CWORD,
2952 /* 74 "J" */ CWORD_CWORD_CWORD_CWORD,
2953 /* 75 "K" */ CWORD_CWORD_CWORD_CWORD,
2954 /* 76 "L" */ CWORD_CWORD_CWORD_CWORD,
2955 /* 77 "M" */ CWORD_CWORD_CWORD_CWORD,
2956 /* 78 "N" */ CWORD_CWORD_CWORD_CWORD,
2957 /* 79 "O" */ CWORD_CWORD_CWORD_CWORD,
2958 /* 80 "P" */ CWORD_CWORD_CWORD_CWORD,
2959 /* 81 "Q" */ CWORD_CWORD_CWORD_CWORD,
2960 /* 82 "R" */ CWORD_CWORD_CWORD_CWORD,
2961 /* 83 "S" */ CWORD_CWORD_CWORD_CWORD,
2962 /* 84 "T" */ CWORD_CWORD_CWORD_CWORD,
2963 /* 85 "U" */ CWORD_CWORD_CWORD_CWORD,
2964 /* 86 "V" */ CWORD_CWORD_CWORD_CWORD,
2965 /* 87 "W" */ CWORD_CWORD_CWORD_CWORD,
2966 /* 88 "X" */ CWORD_CWORD_CWORD_CWORD,
2967 /* 89 "Y" */ CWORD_CWORD_CWORD_CWORD,
2968 /* 90 "Z" */ CWORD_CWORD_CWORD_CWORD,
2969 /* 91 "[" */ CWORD_CCTL_CCTL_CWORD,
2970 /* 92 "\" */ CBACK_CBACK_CCTL_CBACK,
2971 /* 93 "]" */ CWORD_CCTL_CCTL_CWORD,
2972 /* 94 "^" */ CWORD_CWORD_CWORD_CWORD,
2973 /* 95 "_" */ CWORD_CWORD_CWORD_CWORD,
2974 /* 96 "`" */ CBQUOTE_CBQUOTE_CWORD_CBQUOTE,
2975 /* 97 "a" */ CWORD_CWORD_CWORD_CWORD,
2976 /* 98 "b" */ CWORD_CWORD_CWORD_CWORD,
2977 /* 99 "c" */ CWORD_CWORD_CWORD_CWORD,
2978 /* 100 "d" */ CWORD_CWORD_CWORD_CWORD,
2979 /* 101 "e" */ CWORD_CWORD_CWORD_CWORD,
2980 /* 102 "f" */ CWORD_CWORD_CWORD_CWORD,
2981 /* 103 "g" */ CWORD_CWORD_CWORD_CWORD,
2982 /* 104 "h" */ CWORD_CWORD_CWORD_CWORD,
2983 /* 105 "i" */ CWORD_CWORD_CWORD_CWORD,
2984 /* 106 "j" */ CWORD_CWORD_CWORD_CWORD,
2985 /* 107 "k" */ CWORD_CWORD_CWORD_CWORD,
2986 /* 108 "l" */ CWORD_CWORD_CWORD_CWORD,
2987 /* 109 "m" */ CWORD_CWORD_CWORD_CWORD,
2988 /* 110 "n" */ CWORD_CWORD_CWORD_CWORD,
2989 /* 111 "o" */ CWORD_CWORD_CWORD_CWORD,
2990 /* 112 "p" */ CWORD_CWORD_CWORD_CWORD,
2991 /* 113 "q" */ CWORD_CWORD_CWORD_CWORD,
2992 /* 114 "r" */ CWORD_CWORD_CWORD_CWORD,
2993 /* 115 "s" */ CWORD_CWORD_CWORD_CWORD,
2994 /* 116 "t" */ CWORD_CWORD_CWORD_CWORD,
2995 /* 117 "u" */ CWORD_CWORD_CWORD_CWORD,
2996 /* 118 "v" */ CWORD_CWORD_CWORD_CWORD,
2997 /* 119 "w" */ CWORD_CWORD_CWORD_CWORD,
2998 /* 120 "x" */ CWORD_CWORD_CWORD_CWORD,
2999 /* 121 "y" */ CWORD_CWORD_CWORD_CWORD,
3000 /* 122 "z" */ CWORD_CWORD_CWORD_CWORD,
3001 /* 123 "{" */ CWORD_CWORD_CWORD_CWORD,
3002 /* 124 "|" */ CSPCL_CWORD_CWORD_CWORD,
3003 /* 125 "}" */ CENDVAR_CENDVAR_CWORD_CENDVAR,
3004 /* 126 "~" */ CWORD_CCTL_CCTL_CWORD,
3005 /* 127 del */ CWORD_CWORD_CWORD_CWORD,
3006 /* 128 0x80 */ CWORD_CWORD_CWORD_CWORD,
3007 /* 129 CTLESC */ CCTL_CCTL_CCTL_CCTL,
3008 /* 130 CTLVAR */ CCTL_CCTL_CCTL_CCTL,
3009 /* 131 CTLENDVAR */ CCTL_CCTL_CCTL_CCTL,
3010 /* 132 CTLBACKQ */ CCTL_CCTL_CCTL_CCTL,
3011 /* 133 CTLQUOTE */ CCTL_CCTL_CCTL_CCTL,
3012 /* 134 CTLARI */ CCTL_CCTL_CCTL_CCTL,
3013 /* 135 CTLENDARI */ CCTL_CCTL_CCTL_CCTL,
3014 /* 136 CTLQUOTEMARK */ CCTL_CCTL_CCTL_CCTL,
3015 /* 137 */ CWORD_CWORD_CWORD_CWORD,
3016 /* 138 */ CWORD_CWORD_CWORD_CWORD,
3017 /* 139 */ CWORD_CWORD_CWORD_CWORD,
3018 /* 140 */ CWORD_CWORD_CWORD_CWORD,
3019 /* 141 */ CWORD_CWORD_CWORD_CWORD,
3020 /* 142 */ CWORD_CWORD_CWORD_CWORD,
3021 /* 143 */ CWORD_CWORD_CWORD_CWORD,
3022 /* 144 */ CWORD_CWORD_CWORD_CWORD,
3023 /* 145 */ CWORD_CWORD_CWORD_CWORD,
3024 /* 146 */ CWORD_CWORD_CWORD_CWORD,
3025 /* 147 */ CWORD_CWORD_CWORD_CWORD,
3026 /* 148 */ CWORD_CWORD_CWORD_CWORD,
3027 /* 149 */ CWORD_CWORD_CWORD_CWORD,
3028 /* 150 */ CWORD_CWORD_CWORD_CWORD,
3029 /* 151 */ CWORD_CWORD_CWORD_CWORD,
3030 /* 152 */ CWORD_CWORD_CWORD_CWORD,
3031 /* 153 */ CWORD_CWORD_CWORD_CWORD,
3032 /* 154 */ CWORD_CWORD_CWORD_CWORD,
3033 /* 155 */ CWORD_CWORD_CWORD_CWORD,
3034 /* 156 */ CWORD_CWORD_CWORD_CWORD,
3035 /* 157 */ CWORD_CWORD_CWORD_CWORD,
3036 /* 158 */ CWORD_CWORD_CWORD_CWORD,
3037 /* 159 */ CWORD_CWORD_CWORD_CWORD,
3038 /* 160 */ CWORD_CWORD_CWORD_CWORD,
3039 /* 161 */ CWORD_CWORD_CWORD_CWORD,
3040 /* 162 */ CWORD_CWORD_CWORD_CWORD,
3041 /* 163 */ CWORD_CWORD_CWORD_CWORD,
3042 /* 164 */ CWORD_CWORD_CWORD_CWORD,
3043 /* 165 */ CWORD_CWORD_CWORD_CWORD,
3044 /* 166 */ CWORD_CWORD_CWORD_CWORD,
3045 /* 167 */ CWORD_CWORD_CWORD_CWORD,
3046 /* 168 */ CWORD_CWORD_CWORD_CWORD,
3047 /* 169 */ CWORD_CWORD_CWORD_CWORD,
3048 /* 170 */ CWORD_CWORD_CWORD_CWORD,
3049 /* 171 */ CWORD_CWORD_CWORD_CWORD,
3050 /* 172 */ CWORD_CWORD_CWORD_CWORD,
3051 /* 173 */ CWORD_CWORD_CWORD_CWORD,
3052 /* 174 */ CWORD_CWORD_CWORD_CWORD,
3053 /* 175 */ CWORD_CWORD_CWORD_CWORD,
3054 /* 176 */ CWORD_CWORD_CWORD_CWORD,
3055 /* 177 */ CWORD_CWORD_CWORD_CWORD,
3056 /* 178 */ CWORD_CWORD_CWORD_CWORD,
3057 /* 179 */ CWORD_CWORD_CWORD_CWORD,
3058 /* 180 */ CWORD_CWORD_CWORD_CWORD,
3059 /* 181 */ CWORD_CWORD_CWORD_CWORD,
3060 /* 182 */ CWORD_CWORD_CWORD_CWORD,
3061 /* 183 */ CWORD_CWORD_CWORD_CWORD,
3062 /* 184 */ CWORD_CWORD_CWORD_CWORD,
3063 /* 185 */ CWORD_CWORD_CWORD_CWORD,
3064 /* 186 */ CWORD_CWORD_CWORD_CWORD,
3065 /* 187 */ CWORD_CWORD_CWORD_CWORD,
3066 /* 188 */ CWORD_CWORD_CWORD_CWORD,
3067 /* 189 */ CWORD_CWORD_CWORD_CWORD,
3068 /* 190 */ CWORD_CWORD_CWORD_CWORD,
3069 /* 191 */ CWORD_CWORD_CWORD_CWORD,
3070 /* 192 */ CWORD_CWORD_CWORD_CWORD,
3071 /* 193 */ CWORD_CWORD_CWORD_CWORD,
3072 /* 194 */ CWORD_CWORD_CWORD_CWORD,
3073 /* 195 */ CWORD_CWORD_CWORD_CWORD,
3074 /* 196 */ CWORD_CWORD_CWORD_CWORD,
3075 /* 197 */ CWORD_CWORD_CWORD_CWORD,
3076 /* 198 */ CWORD_CWORD_CWORD_CWORD,
3077 /* 199 */ CWORD_CWORD_CWORD_CWORD,
3078 /* 200 */ CWORD_CWORD_CWORD_CWORD,
3079 /* 201 */ CWORD_CWORD_CWORD_CWORD,
3080 /* 202 */ CWORD_CWORD_CWORD_CWORD,
3081 /* 203 */ CWORD_CWORD_CWORD_CWORD,
3082 /* 204 */ CWORD_CWORD_CWORD_CWORD,
3083 /* 205 */ CWORD_CWORD_CWORD_CWORD,
3084 /* 206 */ CWORD_CWORD_CWORD_CWORD,
3085 /* 207 */ CWORD_CWORD_CWORD_CWORD,
3086 /* 208 */ CWORD_CWORD_CWORD_CWORD,
3087 /* 209 */ CWORD_CWORD_CWORD_CWORD,
3088 /* 210 */ CWORD_CWORD_CWORD_CWORD,
3089 /* 211 */ CWORD_CWORD_CWORD_CWORD,
3090 /* 212 */ CWORD_CWORD_CWORD_CWORD,
3091 /* 213 */ CWORD_CWORD_CWORD_CWORD,
3092 /* 214 */ CWORD_CWORD_CWORD_CWORD,
3093 /* 215 */ CWORD_CWORD_CWORD_CWORD,
3094 /* 216 */ CWORD_CWORD_CWORD_CWORD,
3095 /* 217 */ CWORD_CWORD_CWORD_CWORD,
3096 /* 218 */ CWORD_CWORD_CWORD_CWORD,
3097 /* 219 */ CWORD_CWORD_CWORD_CWORD,
3098 /* 220 */ CWORD_CWORD_CWORD_CWORD,
3099 /* 221 */ CWORD_CWORD_CWORD_CWORD,
3100 /* 222 */ CWORD_CWORD_CWORD_CWORD,
3101 /* 223 */ CWORD_CWORD_CWORD_CWORD,
3102 /* 224 */ CWORD_CWORD_CWORD_CWORD,
3103 /* 225 */ CWORD_CWORD_CWORD_CWORD,
3104 /* 226 */ CWORD_CWORD_CWORD_CWORD,
3105 /* 227 */ CWORD_CWORD_CWORD_CWORD,
3106 /* 228 */ CWORD_CWORD_CWORD_CWORD,
3107 /* 229 */ CWORD_CWORD_CWORD_CWORD,
3108 /* 230 */ CWORD_CWORD_CWORD_CWORD,
3109 /* 231 */ CWORD_CWORD_CWORD_CWORD,
3110 /* 232 */ CWORD_CWORD_CWORD_CWORD,
3111 /* 233 */ CWORD_CWORD_CWORD_CWORD,
3112 /* 234 */ CWORD_CWORD_CWORD_CWORD,
3113 /* 235 */ CWORD_CWORD_CWORD_CWORD,
3114 /* 236 */ CWORD_CWORD_CWORD_CWORD,
3115 /* 237 */ CWORD_CWORD_CWORD_CWORD,
3116 /* 238 */ CWORD_CWORD_CWORD_CWORD,
3117 /* 239 */ CWORD_CWORD_CWORD_CWORD,
3118 /* 230 */ CWORD_CWORD_CWORD_CWORD,
3119 /* 241 */ CWORD_CWORD_CWORD_CWORD,
3120 /* 242 */ CWORD_CWORD_CWORD_CWORD,
3121 /* 243 */ CWORD_CWORD_CWORD_CWORD,
3122 /* 244 */ CWORD_CWORD_CWORD_CWORD,
3123 /* 245 */ CWORD_CWORD_CWORD_CWORD,
3124 /* 246 */ CWORD_CWORD_CWORD_CWORD,
3125 /* 247 */ CWORD_CWORD_CWORD_CWORD,
3126 /* 248 */ CWORD_CWORD_CWORD_CWORD,
3127 /* 249 */ CWORD_CWORD_CWORD_CWORD,
3128 /* 250 */ CWORD_CWORD_CWORD_CWORD,
3129 /* 251 */ CWORD_CWORD_CWORD_CWORD,
3130 /* 252 */ CWORD_CWORD_CWORD_CWORD,
3131 /* 253 */ CWORD_CWORD_CWORD_CWORD,
3132 /* 254 */ CWORD_CWORD_CWORD_CWORD,
3133 /* 255 */ CWORD_CWORD_CWORD_CWORD,
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01003134 /* PEOF */ CENDFILE_CENDFILE_CENDFILE_CENDFILE,
Denys Vlasenkocd716832009-11-28 22:14:02 +01003135# if ENABLE_ASH_ALIAS
3136 /* PEOA */ CSPCL_CIGN_CIGN_CIGN,
3137# endif
Eric Andersen2870d962001-07-02 17:27:21 +00003138};
3139
Denys Vlasenko2fe66b12016-12-12 17:39:12 +01003140#if 1
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01003141# define SIT(c, syntax) ((S_I_T[syntax_index_table[c]] >> ((syntax)*4)) & 0xf)
Denys Vlasenko2fe66b12016-12-12 17:39:12 +01003142#else /* debug version, caught one signed char bug */
3143# define SIT(c, syntax) \
3144 ({ \
3145 if ((c) < 0 || (c) > (PEOF + ENABLE_ASH_ALIAS)) \
3146 bb_error_msg_and_die("line:%d c:%d", __LINE__, (c)); \
Denys Vlasenko0b883582016-12-23 16:49:07 +01003147 if ((syntax) < 0 || (syntax) > (2 + ENABLE_FEATURE_SH_MATH)) \
Denys Vlasenko2fe66b12016-12-12 17:39:12 +01003148 bb_error_msg_and_die("line:%d c:%d", __LINE__, (c)); \
3149 ((S_I_T[syntax_index_table[c]] >> ((syntax)*4)) & 0xf); \
3150 })
3151#endif
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00003152
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01003153#endif /* !USE_SIT_FUNCTION */
Eric Andersenc470f442003-07-28 09:56:35 +00003154
Eric Andersen2870d962001-07-02 17:27:21 +00003155
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00003156/* ============ Alias handling */
Denis Vlasenkofc06f292007-02-23 21:09:35 +00003157
Denis Vlasenko131ae172007-02-18 13:00:19 +00003158#if ENABLE_ASH_ALIAS
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00003159
3160#define ALIASINUSE 1
3161#define ALIASDEAD 2
3162
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00003163struct alias {
3164 struct alias *next;
3165 char *name;
3166 char *val;
3167 int flag;
3168};
3169
Denis Vlasenko01631112007-12-16 17:20:38 +00003170
3171static struct alias **atab; // [ATABSIZE];
3172#define INIT_G_alias() do { \
3173 atab = xzalloc(ATABSIZE * sizeof(atab[0])); \
3174} while (0)
3175
Eric Andersen2870d962001-07-02 17:27:21 +00003176
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00003177static struct alias **
Denys Vlasenko37dc08b2016-10-02 04:38:07 +02003178__lookupalias(const char *name)
3179{
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00003180 unsigned int hashval;
3181 struct alias **app;
3182 const char *p;
3183 unsigned int ch;
3184
3185 p = name;
3186
3187 ch = (unsigned char)*p;
3188 hashval = ch << 4;
3189 while (ch) {
3190 hashval += ch;
3191 ch = (unsigned char)*++p;
3192 }
3193 app = &atab[hashval % ATABSIZE];
3194
3195 for (; *app; app = &(*app)->next) {
3196 if (strcmp(name, (*app)->name) == 0) {
3197 break;
3198 }
3199 }
3200
3201 return app;
3202}
3203
3204static struct alias *
3205lookupalias(const char *name, int check)
3206{
3207 struct alias *ap = *__lookupalias(name);
3208
3209 if (check && ap && (ap->flag & ALIASINUSE))
3210 return NULL;
3211 return ap;
3212}
3213
3214static struct alias *
3215freealias(struct alias *ap)
3216{
3217 struct alias *next;
3218
3219 if (ap->flag & ALIASINUSE) {
3220 ap->flag |= ALIASDEAD;
3221 return ap;
3222 }
3223
3224 next = ap->next;
3225 free(ap->name);
3226 free(ap->val);
3227 free(ap);
3228 return next;
3229}
Eric Andersencb57d552001-06-28 07:25:16 +00003230
Eric Andersenc470f442003-07-28 09:56:35 +00003231static void
3232setalias(const char *name, const char *val)
Eric Andersencb57d552001-06-28 07:25:16 +00003233{
3234 struct alias *ap, **app;
3235
3236 app = __lookupalias(name);
3237 ap = *app;
Denis Vlasenkob012b102007-02-19 22:43:01 +00003238 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +00003239 if (ap) {
3240 if (!(ap->flag & ALIASINUSE)) {
Denis Vlasenkob012b102007-02-19 22:43:01 +00003241 free(ap->val);
Eric Andersencb57d552001-06-28 07:25:16 +00003242 }
Denis Vlasenko0c032a42007-02-23 01:03:40 +00003243 ap->val = ckstrdup(val);
Eric Andersencb57d552001-06-28 07:25:16 +00003244 ap->flag &= ~ALIASDEAD;
3245 } else {
3246 /* not found */
Denis Vlasenko597906c2008-02-20 16:38:54 +00003247 ap = ckzalloc(sizeof(struct alias));
Denis Vlasenko0c032a42007-02-23 01:03:40 +00003248 ap->name = ckstrdup(name);
3249 ap->val = ckstrdup(val);
Denis Vlasenko597906c2008-02-20 16:38:54 +00003250 /*ap->flag = 0; - ckzalloc did it */
3251 /*ap->next = NULL;*/
Eric Andersencb57d552001-06-28 07:25:16 +00003252 *app = ap;
3253 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00003254 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +00003255}
3256
Eric Andersenc470f442003-07-28 09:56:35 +00003257static int
3258unalias(const char *name)
Eric Andersen2870d962001-07-02 17:27:21 +00003259{
Eric Andersencb57d552001-06-28 07:25:16 +00003260 struct alias **app;
3261
3262 app = __lookupalias(name);
3263
3264 if (*app) {
Denis Vlasenkob012b102007-02-19 22:43:01 +00003265 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +00003266 *app = freealias(*app);
Denis Vlasenkob012b102007-02-19 22:43:01 +00003267 INT_ON;
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003268 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003269 }
3270
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003271 return 1;
Eric Andersencb57d552001-06-28 07:25:16 +00003272}
3273
Eric Andersenc470f442003-07-28 09:56:35 +00003274static void
3275rmaliases(void)
Eric Andersen2870d962001-07-02 17:27:21 +00003276{
Eric Andersencb57d552001-06-28 07:25:16 +00003277 struct alias *ap, **app;
3278 int i;
3279
Denis Vlasenkob012b102007-02-19 22:43:01 +00003280 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +00003281 for (i = 0; i < ATABSIZE; i++) {
3282 app = &atab[i];
3283 for (ap = *app; ap; ap = *app) {
3284 *app = freealias(*app);
3285 if (ap == *app) {
3286 app = &ap->next;
3287 }
3288 }
3289 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00003290 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +00003291}
3292
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00003293static void
3294printalias(const struct alias *ap)
3295{
3296 out1fmt("%s=%s\n", ap->name, single_quote(ap->val));
3297}
3298
Eric Andersencb57d552001-06-28 07:25:16 +00003299/*
3300 * TODO - sort output
3301 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02003302static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003303aliascmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003304{
3305 char *n, *v;
3306 int ret = 0;
3307 struct alias *ap;
3308
Denis Vlasenko68404f12008-03-17 09:00:54 +00003309 if (!argv[1]) {
Eric Andersencb57d552001-06-28 07:25:16 +00003310 int i;
3311
Denis Vlasenko68404f12008-03-17 09:00:54 +00003312 for (i = 0; i < ATABSIZE; i++) {
Eric Andersencb57d552001-06-28 07:25:16 +00003313 for (ap = atab[i]; ap; ap = ap->next) {
3314 printalias(ap);
3315 }
Denis Vlasenko68404f12008-03-17 09:00:54 +00003316 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003317 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003318 }
3319 while ((n = *++argv) != NULL) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +00003320 v = strchr(n+1, '=');
3321 if (v == NULL) { /* n+1: funny ksh stuff */
3322 ap = *__lookupalias(n);
3323 if (ap == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00003324 fprintf(stderr, "%s: %s not found\n", "alias", n);
Eric Andersencb57d552001-06-28 07:25:16 +00003325 ret = 1;
3326 } else
3327 printalias(ap);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003328 } else {
Eric Andersencb57d552001-06-28 07:25:16 +00003329 *v++ = '\0';
3330 setalias(n, v);
3331 }
3332 }
3333
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003334 return ret;
Eric Andersencb57d552001-06-28 07:25:16 +00003335}
3336
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02003337static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003338unaliascmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +00003339{
3340 int i;
3341
3342 while ((i = nextopt("a")) != '\0') {
3343 if (i == 'a') {
3344 rmaliases();
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003345 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003346 }
3347 }
3348 for (i = 0; *argptr; argptr++) {
3349 if (unalias(*argptr)) {
Eric Andersenc470f442003-07-28 09:56:35 +00003350 fprintf(stderr, "%s: %s not found\n", "unalias", *argptr);
Eric Andersencb57d552001-06-28 07:25:16 +00003351 i = 1;
3352 }
3353 }
3354
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003355 return i;
Eric Andersencb57d552001-06-28 07:25:16 +00003356}
Denis Vlasenkofc06f292007-02-23 21:09:35 +00003357
Denis Vlasenko131ae172007-02-18 13:00:19 +00003358#endif /* ASH_ALIAS */
Eric Andersencb57d552001-06-28 07:25:16 +00003359
Eric Andersenc470f442003-07-28 09:56:35 +00003360
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003361/* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */
Denys Vlasenko285ad152009-12-04 23:02:27 +01003362#define FORK_FG 0
3363#define FORK_BG 1
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003364#define FORK_NOJOB 2
3365
3366/* mode flags for showjob(s) */
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02003367#define SHOW_ONLY_PGID 0x01 /* show only pgid (jobs -p) */
3368#define SHOW_PIDS 0x02 /* show individual pids, not just one line per job */
3369#define SHOW_CHANGED 0x04 /* only jobs whose state has changed */
Denys Vlasenko9c541002015-10-07 15:44:36 +02003370#define SHOW_STDERR 0x08 /* print to stderr (else stdout) */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003371
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003372/*
3373 * A job structure contains information about a job. A job is either a
3374 * single process or a set of processes contained in a pipeline. In the
3375 * latter case, pidlist will be non-NULL, and will point to a -1 terminated
3376 * array of pids.
3377 */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003378struct procstat {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003379 pid_t ps_pid; /* process id */
3380 int ps_status; /* last process status from wait() */
3381 char *ps_cmd; /* text of command being run */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003382};
3383
3384struct job {
3385 struct procstat ps0; /* status of process */
3386 struct procstat *ps; /* status or processes when more than one */
3387#if JOBS
3388 int stopstatus; /* status of a stopped job */
3389#endif
3390 uint32_t
3391 nprocs: 16, /* number of processes */
3392 state: 8,
3393#define JOBRUNNING 0 /* at least one proc running */
3394#define JOBSTOPPED 1 /* all procs are stopped */
3395#define JOBDONE 2 /* all procs are completed */
3396#if JOBS
3397 sigint: 1, /* job was killed by SIGINT */
3398 jobctl: 1, /* job running under job control */
3399#endif
3400 waited: 1, /* true if this entry has been waited for */
3401 used: 1, /* true if this entry is in used */
3402 changed: 1; /* true if status has changed */
3403 struct job *prev_job; /* previous job */
3404};
3405
Denis Vlasenko68404f12008-03-17 09:00:54 +00003406static struct job *makejob(/*union node *,*/ int);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003407static int forkshell(struct job *, union node *, int);
3408static int waitforjob(struct job *);
3409
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00003410#if !JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +00003411enum { doing_jobctl = 0 };
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00003412#define setjobctl(on) do {} while (0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003413#else
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003414static smallint doing_jobctl; //references:8
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003415static void setjobctl(int);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003416#endif
3417
3418/*
Denis Vlasenko4b875702009-03-19 13:30:04 +00003419 * Ignore a signal.
3420 */
3421static void
3422ignoresig(int signo)
3423{
3424 /* Avoid unnecessary system calls. Is it already SIG_IGNed? */
3425 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
3426 /* No, need to do it */
3427 signal(signo, SIG_IGN);
3428 }
3429 sigmode[signo - 1] = S_HARD_IGN;
3430}
3431
3432/*
Denys Vlasenko238bf182010-05-18 15:49:07 +02003433 * Only one usage site - in setsignal()
Denis Vlasenko4b875702009-03-19 13:30:04 +00003434 */
3435static void
Denys Vlasenko238bf182010-05-18 15:49:07 +02003436signal_handler(int signo)
Denis Vlasenko4b875702009-03-19 13:30:04 +00003437{
Denys Vlasenko458c1f22016-10-27 23:51:19 +02003438 if (signo == SIGCHLD) {
3439 got_sigchld = 1;
3440 if (!trap[SIGCHLD])
3441 return;
3442 }
3443
Denis Vlasenko4b875702009-03-19 13:30:04 +00003444 gotsig[signo - 1] = 1;
Denys Vlasenko458c1f22016-10-27 23:51:19 +02003445 pending_sig = signo;
Denis Vlasenko4b875702009-03-19 13:30:04 +00003446
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02003447 if (signo == SIGINT && !trap[SIGINT]) {
3448 if (!suppress_int) {
3449 pending_sig = 0;
Denis Vlasenko4b875702009-03-19 13:30:04 +00003450 raise_interrupt(); /* does not return */
3451 }
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02003452 pending_int = 1;
Denis Vlasenko4b875702009-03-19 13:30:04 +00003453 }
3454}
3455
3456/*
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003457 * Set the signal handler for the specified signal. The routine figures
3458 * out what it should be set to.
3459 */
3460static void
3461setsignal(int signo)
3462{
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003463 char *t;
3464 char cur_act, new_act;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003465 struct sigaction act;
3466
3467 t = trap[signo];
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003468 new_act = S_DFL;
3469 if (t != NULL) { /* trap for this sig is set */
3470 new_act = S_CATCH;
3471 if (t[0] == '\0') /* trap is "": ignore this sig */
3472 new_act = S_IGN;
3473 }
3474
3475 if (rootshell && new_act == S_DFL) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003476 switch (signo) {
3477 case SIGINT:
3478 if (iflag || minusc || sflag == 0)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003479 new_act = S_CATCH;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003480 break;
3481 case SIGQUIT:
3482#if DEBUG
3483 if (debug)
3484 break;
3485#endif
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003486 /* man bash:
3487 * "In all cases, bash ignores SIGQUIT. Non-builtin
3488 * commands run by bash have signal handlers
3489 * set to the values inherited by the shell
3490 * from its parent". */
3491 new_act = S_IGN;
3492 break;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003493 case SIGTERM:
3494 if (iflag)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003495 new_act = S_IGN;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003496 break;
3497#if JOBS
3498 case SIGTSTP:
3499 case SIGTTOU:
3500 if (mflag)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003501 new_act = S_IGN;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003502 break;
3503#endif
3504 }
3505 }
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003506//TODO: if !rootshell, we reset SIGQUIT to DFL,
3507//whereas we have to restore it to what shell got on entry
3508//from the parent. See comment above
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003509
Denys Vlasenko458c1f22016-10-27 23:51:19 +02003510 if (signo == SIGCHLD)
3511 new_act = S_CATCH;
3512
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003513 t = &sigmode[signo - 1];
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003514 cur_act = *t;
3515 if (cur_act == 0) {
3516 /* current setting is not yet known */
3517 if (sigaction(signo, NULL, &act)) {
3518 /* pretend it worked; maybe we should give a warning,
3519 * but other shells don't. We don't alter sigmode,
3520 * so we retry every time.
3521 * btw, in Linux it never fails. --vda */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003522 return;
3523 }
3524 if (act.sa_handler == SIG_IGN) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003525 cur_act = S_HARD_IGN;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003526 if (mflag
3527 && (signo == SIGTSTP || signo == SIGTTIN || signo == SIGTTOU)
3528 ) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003529 cur_act = S_IGN; /* don't hard ignore these */
Denis Vlasenko991a1da2008-02-10 19:02:53 +00003530 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003531 }
3532 }
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003533 if (cur_act == S_HARD_IGN || cur_act == new_act)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003534 return;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003535
Denis Vlasenko991a1da2008-02-10 19:02:53 +00003536 act.sa_handler = SIG_DFL;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003537 switch (new_act) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003538 case S_CATCH:
Denys Vlasenko238bf182010-05-18 15:49:07 +02003539 act.sa_handler = signal_handler;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003540 break;
3541 case S_IGN:
3542 act.sa_handler = SIG_IGN;
3543 break;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003544 }
Ian Wienand89b3cba2011-04-16 20:05:14 +02003545
3546 /* flags and mask matter only if !DFL and !IGN, but we do it
3547 * for all cases for more deterministic behavior:
3548 */
3549 act.sa_flags = 0;
3550 sigfillset(&act.sa_mask);
3551
Denis Vlasenko8e2cfec2008-03-12 23:19:35 +00003552 sigaction_set(signo, &act);
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003553
3554 *t = new_act;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003555}
3556
3557/* mode flags for set_curjob */
3558#define CUR_DELETE 2
3559#define CUR_RUNNING 1
3560#define CUR_STOPPED 0
3561
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003562#if JOBS
3563/* pgrp of shell on invocation */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003564static int initialpgrp; //references:2
3565static int ttyfd = -1; //5
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003566#endif
3567/* array of jobs */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003568static struct job *jobtab; //5
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003569/* size of array */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003570static unsigned njobs; //4
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003571/* current job */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003572static struct job *curjob; //lots
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003573/* number of presumed living untracked jobs */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003574static int jobless; //4
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003575
3576static void
3577set_curjob(struct job *jp, unsigned mode)
3578{
3579 struct job *jp1;
3580 struct job **jpp, **curp;
3581
3582 /* first remove from list */
3583 jpp = curp = &curjob;
Denys Vlasenko940c7202011-03-02 04:07:14 +01003584 while (1) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003585 jp1 = *jpp;
3586 if (jp1 == jp)
3587 break;
3588 jpp = &jp1->prev_job;
Denys Vlasenko940c7202011-03-02 04:07:14 +01003589 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003590 *jpp = jp1->prev_job;
3591
3592 /* Then re-insert in correct position */
3593 jpp = curp;
3594 switch (mode) {
3595 default:
3596#if DEBUG
3597 abort();
3598#endif
3599 case CUR_DELETE:
3600 /* job being deleted */
3601 break;
3602 case CUR_RUNNING:
3603 /* newly created job or backgrounded job,
Denys Vlasenko60cb48c2013-01-14 15:57:44 +01003604 * put after all stopped jobs.
3605 */
Denys Vlasenko940c7202011-03-02 04:07:14 +01003606 while (1) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003607 jp1 = *jpp;
3608#if JOBS
3609 if (!jp1 || jp1->state != JOBSTOPPED)
3610#endif
3611 break;
3612 jpp = &jp1->prev_job;
Denys Vlasenko940c7202011-03-02 04:07:14 +01003613 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003614 /* FALLTHROUGH */
3615#if JOBS
3616 case CUR_STOPPED:
3617#endif
3618 /* newly stopped job - becomes curjob */
3619 jp->prev_job = *jpp;
3620 *jpp = jp;
3621 break;
3622 }
3623}
3624
3625#if JOBS || DEBUG
3626static int
3627jobno(const struct job *jp)
3628{
3629 return jp - jobtab + 1;
3630}
3631#endif
3632
3633/*
3634 * Convert a job name to a job structure.
3635 */
Denis Vlasenko85c24712008-03-17 09:04:04 +00003636#if !JOBS
3637#define getjob(name, getctl) getjob(name)
3638#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003639static struct job *
3640getjob(const char *name, int getctl)
3641{
3642 struct job *jp;
3643 struct job *found;
Denys Vlasenkoffc39202009-08-17 02:12:20 +02003644 const char *err_msg = "%s: no such job";
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003645 unsigned num;
3646 int c;
3647 const char *p;
3648 char *(*match)(const char *, const char *);
3649
3650 jp = curjob;
3651 p = name;
3652 if (!p)
3653 goto currentjob;
3654
3655 if (*p != '%')
3656 goto err;
3657
3658 c = *++p;
3659 if (!c)
3660 goto currentjob;
3661
3662 if (!p[1]) {
3663 if (c == '+' || c == '%') {
3664 currentjob:
3665 err_msg = "No current job";
3666 goto check;
3667 }
3668 if (c == '-') {
3669 if (jp)
3670 jp = jp->prev_job;
3671 err_msg = "No previous job";
3672 check:
3673 if (!jp)
3674 goto err;
3675 goto gotit;
3676 }
3677 }
3678
3679 if (is_number(p)) {
3680 num = atoi(p);
Denys Vlasenko46a45ce2016-09-29 01:10:08 +02003681 if (num > 0 && num <= njobs) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003682 jp = jobtab + num - 1;
3683 if (jp->used)
3684 goto gotit;
3685 goto err;
3686 }
3687 }
3688
3689 match = prefix;
3690 if (*p == '?') {
3691 match = strstr;
3692 p++;
3693 }
3694
Denys Vlasenkoffc39202009-08-17 02:12:20 +02003695 found = NULL;
3696 while (jp) {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003697 if (match(jp->ps[0].ps_cmd, p)) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003698 if (found)
3699 goto err;
3700 found = jp;
3701 err_msg = "%s: ambiguous";
3702 }
3703 jp = jp->prev_job;
3704 }
Denys Vlasenkoffc39202009-08-17 02:12:20 +02003705 if (!found)
3706 goto err;
3707 jp = found;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003708
3709 gotit:
3710#if JOBS
3711 err_msg = "job %s not created under job control";
3712 if (getctl && jp->jobctl == 0)
3713 goto err;
3714#endif
3715 return jp;
3716 err:
3717 ash_msg_and_raise_error(err_msg, name);
3718}
3719
3720/*
3721 * Mark a job structure as unused.
3722 */
3723static void
3724freejob(struct job *jp)
3725{
3726 struct procstat *ps;
3727 int i;
3728
3729 INT_OFF;
3730 for (i = jp->nprocs, ps = jp->ps; --i >= 0; ps++) {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003731 if (ps->ps_cmd != nullstr)
3732 free(ps->ps_cmd);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003733 }
3734 if (jp->ps != &jp->ps0)
3735 free(jp->ps);
3736 jp->used = 0;
3737 set_curjob(jp, CUR_DELETE);
3738 INT_ON;
3739}
3740
3741#if JOBS
3742static void
3743xtcsetpgrp(int fd, pid_t pgrp)
3744{
3745 if (tcsetpgrp(fd, pgrp))
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +00003746 ash_msg_and_raise_error("can't set tty process group (%m)");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003747}
3748
3749/*
3750 * Turn job control on and off.
3751 *
3752 * Note: This code assumes that the third arg to ioctl is a character
3753 * pointer, which is true on Berkeley systems but not System V. Since
3754 * System V doesn't have job control yet, this isn't a problem now.
3755 *
3756 * Called with interrupts off.
3757 */
3758static void
3759setjobctl(int on)
3760{
3761 int fd;
3762 int pgrp;
3763
Denis Vlasenkob07a4962008-06-22 13:16:23 +00003764 if (on == doing_jobctl || rootshell == 0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003765 return;
3766 if (on) {
3767 int ofd;
3768 ofd = fd = open(_PATH_TTY, O_RDWR);
3769 if (fd < 0) {
3770 /* BTW, bash will try to open(ttyname(0)) if open("/dev/tty") fails.
3771 * That sometimes helps to acquire controlling tty.
3772 * Obviously, a workaround for bugs when someone
3773 * failed to provide a controlling tty to bash! :) */
Denis Vlasenkoed270a52007-11-26 05:37:07 +00003774 fd = 2;
3775 while (!isatty(fd))
3776 if (--fd < 0)
3777 goto out;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003778 }
Denys Vlasenko64774602016-10-26 15:24:30 +02003779 /* fd is a tty at this point */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003780 fd = fcntl(fd, F_DUPFD, 10);
Denys Vlasenko64774602016-10-26 15:24:30 +02003781 if (ofd >= 0) /* if it is "/dev/tty", close. If 0/1/2, dont */
Denis Vlasenkoed270a52007-11-26 05:37:07 +00003782 close(ofd);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003783 if (fd < 0)
Denys Vlasenko64774602016-10-26 15:24:30 +02003784 goto out; /* F_DUPFD failed */
Denis Vlasenko96e1b382007-09-30 23:50:48 +00003785 close_on_exec_on(fd);
Denys Vlasenko940c7202011-03-02 04:07:14 +01003786 while (1) { /* while we are in the background */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003787 pgrp = tcgetpgrp(fd);
3788 if (pgrp < 0) {
3789 out:
3790 ash_msg("can't access tty; job control turned off");
3791 mflag = on = 0;
3792 goto close;
3793 }
3794 if (pgrp == getpgrp())
3795 break;
3796 killpg(0, SIGTTIN);
Denys Vlasenko940c7202011-03-02 04:07:14 +01003797 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003798 initialpgrp = pgrp;
3799
3800 setsignal(SIGTSTP);
3801 setsignal(SIGTTOU);
3802 setsignal(SIGTTIN);
3803 pgrp = rootpid;
3804 setpgid(0, pgrp);
3805 xtcsetpgrp(fd, pgrp);
3806 } else {
3807 /* turning job control off */
3808 fd = ttyfd;
3809 pgrp = initialpgrp;
Denis Vlasenko08c8c1d2007-04-28 22:39:02 +00003810 /* was xtcsetpgrp, but this can make exiting ash
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00003811 * loop forever if pty is already deleted */
Denis Vlasenko08c8c1d2007-04-28 22:39:02 +00003812 tcsetpgrp(fd, pgrp);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003813 setpgid(0, pgrp);
3814 setsignal(SIGTSTP);
3815 setsignal(SIGTTOU);
3816 setsignal(SIGTTIN);
3817 close:
Denis Vlasenkoed270a52007-11-26 05:37:07 +00003818 if (fd >= 0)
3819 close(fd);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003820 fd = -1;
3821 }
3822 ttyfd = fd;
Denis Vlasenkob07a4962008-06-22 13:16:23 +00003823 doing_jobctl = on;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003824}
3825
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02003826static int FAST_FUNC
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003827killcmd(int argc, char **argv)
3828{
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003829 if (argv[1] && strcmp(argv[1], "-l") != 0) {
Denys Vlasenkob12553f2011-02-21 03:22:20 +01003830 int i = 1;
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003831 do {
3832 if (argv[i][0] == '%') {
Denys Vlasenkob12553f2011-02-21 03:22:20 +01003833 /*
3834 * "kill %N" - job kill
3835 * Converting to pgrp / pid kill
3836 */
3837 struct job *jp;
3838 char *dst;
3839 int j, n;
3840
3841 jp = getjob(argv[i], 0);
3842 /*
3843 * In jobs started under job control, we signal
3844 * entire process group by kill -PGRP_ID.
3845 * This happens, f.e., in interactive shell.
3846 *
3847 * Otherwise, we signal each child via
3848 * kill PID1 PID2 PID3.
3849 * Testcases:
3850 * sh -c 'sleep 1|sleep 1 & kill %1'
3851 * sh -c 'true|sleep 2 & sleep 1; kill %1'
3852 * sh -c 'true|sleep 1 & sleep 2; kill %1'
3853 */
3854 n = jp->nprocs; /* can't be 0 (I hope) */
3855 if (jp->jobctl)
3856 n = 1;
3857 dst = alloca(n * sizeof(int)*4);
3858 argv[i] = dst;
3859 for (j = 0; j < n; j++) {
3860 struct procstat *ps = &jp->ps[j];
3861 /* Skip non-running and not-stopped members
3862 * (i.e. dead members) of the job
3863 */
3864 if (ps->ps_status != -1 && !WIFSTOPPED(ps->ps_status))
3865 continue;
3866 /*
3867 * kill_main has matching code to expect
3868 * leading space. Needed to not confuse
3869 * negative pids with "kill -SIGNAL_NO" syntax
3870 */
3871 dst += sprintf(dst, jp->jobctl ? " -%u" : " %u", (int)ps->ps_pid);
3872 }
3873 *dst = '\0';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003874 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003875 } while (argv[++i]);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003876 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003877 return kill_main(argc, argv);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003878}
3879
3880static void
Denys Vlasenko285ad152009-12-04 23:02:27 +01003881showpipe(struct job *jp /*, FILE *out*/)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003882{
Denys Vlasenko285ad152009-12-04 23:02:27 +01003883 struct procstat *ps;
3884 struct procstat *psend;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003885
Denys Vlasenko285ad152009-12-04 23:02:27 +01003886 psend = jp->ps + jp->nprocs;
3887 for (ps = jp->ps + 1; ps < psend; ps++)
3888 printf(" | %s", ps->ps_cmd);
Denys Vlasenko9c541002015-10-07 15:44:36 +02003889 newline_and_flush(stdout);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003890 flush_stdout_stderr();
3891}
3892
3893
3894static int
3895restartjob(struct job *jp, int mode)
3896{
3897 struct procstat *ps;
3898 int i;
3899 int status;
3900 pid_t pgid;
3901
3902 INT_OFF;
3903 if (jp->state == JOBDONE)
3904 goto out;
3905 jp->state = JOBRUNNING;
Denys Vlasenko285ad152009-12-04 23:02:27 +01003906 pgid = jp->ps[0].ps_pid;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003907 if (mode == FORK_FG)
3908 xtcsetpgrp(ttyfd, pgid);
3909 killpg(pgid, SIGCONT);
3910 ps = jp->ps;
3911 i = jp->nprocs;
3912 do {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003913 if (WIFSTOPPED(ps->ps_status)) {
3914 ps->ps_status = -1;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003915 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003916 ps++;
3917 } while (--i);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003918 out:
3919 status = (mode == FORK_FG) ? waitforjob(jp) : 0;
3920 INT_ON;
3921 return status;
3922}
3923
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02003924static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003925fg_bgcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003926{
3927 struct job *jp;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003928 int mode;
3929 int retval;
3930
3931 mode = (**argv == 'f') ? FORK_FG : FORK_BG;
3932 nextopt(nullstr);
3933 argv = argptr;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003934 do {
3935 jp = getjob(*argv, 1);
3936 if (mode == FORK_BG) {
3937 set_curjob(jp, CUR_RUNNING);
Denys Vlasenko285ad152009-12-04 23:02:27 +01003938 printf("[%d] ", jobno(jp));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003939 }
Denys Vlasenko285ad152009-12-04 23:02:27 +01003940 out1str(jp->ps[0].ps_cmd);
3941 showpipe(jp /*, stdout*/);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003942 retval = restartjob(jp, mode);
3943 } while (*argv && *++argv);
3944 return retval;
3945}
3946#endif
3947
3948static int
Denys Vlasenko9c541002015-10-07 15:44:36 +02003949sprint_status48(char *s, int status, int sigonly)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003950{
3951 int col;
3952 int st;
3953
3954 col = 0;
3955 if (!WIFEXITED(status)) {
Denys Vlasenko4700fb52015-10-09 15:40:13 +02003956 if (JOBS && WIFSTOPPED(status))
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003957 st = WSTOPSIG(status);
3958 else
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003959 st = WTERMSIG(status);
3960 if (sigonly) {
3961 if (st == SIGINT || st == SIGPIPE)
3962 goto out;
Denys Vlasenko4700fb52015-10-09 15:40:13 +02003963 if (JOBS && WIFSTOPPED(status))
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003964 goto out;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003965 }
3966 st &= 0x7f;
Denys Vlasenko7c6f2462011-02-14 17:17:10 +01003967//TODO: use bbox's get_signame? strsignal adds ~600 bytes to text+rodata
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003968 col = fmtstr(s, 32, strsignal(st));
3969 if (WCOREDUMP(status)) {
Denys Vlasenko9c541002015-10-07 15:44:36 +02003970 strcpy(s + col, " (core dumped)");
3971 col += sizeof(" (core dumped)")-1;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003972 }
3973 } else if (!sigonly) {
3974 st = WEXITSTATUS(status);
Denys Vlasenko9c541002015-10-07 15:44:36 +02003975 col = fmtstr(s, 16, (st ? "Done(%d)" : "Done"), st);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003976 }
3977 out:
3978 return col;
3979}
3980
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003981static int
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02003982wait_block_or_sig(int *status)
Denys Vlasenko458c1f22016-10-27 23:51:19 +02003983{
Denys Vlasenko458c1f22016-10-27 23:51:19 +02003984 int pid;
3985
3986 do {
Denys Vlasenko1ab7c2f2016-11-03 20:17:23 +01003987 sigset_t mask;
3988
Denys Vlasenko458c1f22016-10-27 23:51:19 +02003989 /* Poll all children for changes in their state */
3990 got_sigchld = 0;
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02003991 /* if job control is active, accept stopped processes too */
3992 pid = waitpid(-1, status, doing_jobctl ? (WNOHANG|WUNTRACED) : WNOHANG);
Denys Vlasenko458c1f22016-10-27 23:51:19 +02003993 if (pid != 0)
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02003994 break; /* Error (e.g. EINTR, ECHILD) or pid */
Denys Vlasenko458c1f22016-10-27 23:51:19 +02003995
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02003996 /* Children exist, but none are ready. Sleep until interesting signal */
Denys Vlasenko1ab7c2f2016-11-03 20:17:23 +01003997#if 1
Denys Vlasenko458c1f22016-10-27 23:51:19 +02003998 sigfillset(&mask);
3999 sigprocmask(SIG_SETMASK, &mask, &mask);
4000 while (!got_sigchld && !pending_sig)
4001 sigsuspend(&mask);
4002 sigprocmask(SIG_SETMASK, &mask, NULL);
Denys Vlasenko1ab7c2f2016-11-03 20:17:23 +01004003#else /* unsafe: a signal can set pending_sig after check, but before pause() */
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004004 while (!got_sigchld && !pending_sig)
4005 pause();
4006#endif
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004007
4008 /* If it was SIGCHLD, poll children again */
4009 } while (got_sigchld);
4010
4011 return pid;
4012}
4013
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004014#define DOWAIT_NONBLOCK 0
4015#define DOWAIT_BLOCK 1
4016#define DOWAIT_BLOCK_OR_SIG 2
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004017
4018static int
Denys Vlasenkob543bda2016-10-27 20:08:28 +02004019dowait(int block, struct job *job)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004020{
4021 int pid;
4022 int status;
4023 struct job *jp;
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004024 struct job *thisjob = NULL;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004025
Denys Vlasenkob543bda2016-10-27 20:08:28 +02004026 TRACE(("dowait(0x%x) called\n", block));
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +00004027
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004028 /* It's wrong to call waitpid() outside of INT_OFF region:
4029 * signal can arrive just after syscall return and handler can
4030 * longjmp away, losing stop/exit notification processing.
4031 * Thus, for "jobs" builtin, and for waiting for a fg job,
4032 * we call waitpid() (blocking or non-blocking) inside INT_OFF.
4033 *
4034 * However, for "wait" builtin it is wrong to simply call waitpid()
4035 * in INT_OFF region: "wait" needs to wait for any running job
4036 * to change state, but should exit on any trap too.
4037 * In INT_OFF region, a signal just before syscall entry can set
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004038 * pending_sig variables, but we can't check them, and we would
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004039 * either enter a sleeping waitpid() (BUG), or need to busy-loop.
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004040 *
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004041 * Because of this, we run inside INT_OFF, but use a special routine
Denys Vlasenko1ab7c2f2016-11-03 20:17:23 +01004042 * which combines waitpid() and sigsuspend().
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004043 * This is the reason why we need to have a handler for SIGCHLD:
Denys Vlasenko1ab7c2f2016-11-03 20:17:23 +01004044 * SIG_DFL handler does not wake sigsuspend().
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004045 */
4046 INT_OFF;
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004047 if (block == DOWAIT_BLOCK_OR_SIG) {
4048 pid = wait_block_or_sig(&status);
4049 } else {
4050 int wait_flags = 0;
4051 if (block == DOWAIT_NONBLOCK)
4052 wait_flags = WNOHANG;
4053 /* if job control is active, accept stopped processes too */
4054 if (doing_jobctl)
4055 wait_flags |= WUNTRACED;
4056 /* NB: _not_ safe_waitpid, we need to detect EINTR */
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004057 pid = waitpid(-1, &status, wait_flags);
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004058 }
Denis Vlasenkob21f3792009-03-19 23:09:58 +00004059 TRACE(("wait returns pid=%d, status=0x%x, errno=%d(%s)\n",
4060 pid, status, errno, strerror(errno)));
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004061 if (pid <= 0)
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004062 goto out;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004063
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004064 thisjob = NULL;
4065 for (jp = curjob; jp; jp = jp->prev_job) {
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004066 int jobstate;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004067 struct procstat *ps;
4068 struct procstat *psend;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004069 if (jp->state == JOBDONE)
4070 continue;
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004071 jobstate = JOBDONE;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004072 ps = jp->ps;
4073 psend = ps + jp->nprocs;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004074 do {
Denys Vlasenko285ad152009-12-04 23:02:27 +01004075 if (ps->ps_pid == pid) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004076 TRACE(("Job %d: changing status of proc %d "
4077 "from 0x%x to 0x%x\n",
Denys Vlasenko285ad152009-12-04 23:02:27 +01004078 jobno(jp), pid, ps->ps_status, status));
4079 ps->ps_status = status;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004080 thisjob = jp;
4081 }
Denys Vlasenko285ad152009-12-04 23:02:27 +01004082 if (ps->ps_status == -1)
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004083 jobstate = JOBRUNNING;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004084#if JOBS
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004085 if (jobstate == JOBRUNNING)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004086 continue;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004087 if (WIFSTOPPED(ps->ps_status)) {
4088 jp->stopstatus = ps->ps_status;
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004089 jobstate = JOBSTOPPED;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004090 }
4091#endif
Denys Vlasenko285ad152009-12-04 23:02:27 +01004092 } while (++ps < psend);
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004093 if (!thisjob)
4094 continue;
4095
4096 /* Found the job where one of its processes changed its state.
4097 * Is there at least one live and running process in this job? */
4098 if (jobstate != JOBRUNNING) {
4099 /* No. All live processes in the job are stopped
4100 * (JOBSTOPPED) or there are no live processes (JOBDONE)
4101 */
4102 thisjob->changed = 1;
4103 if (thisjob->state != jobstate) {
4104 TRACE(("Job %d: changing state from %d to %d\n",
4105 jobno(thisjob), thisjob->state, jobstate));
4106 thisjob->state = jobstate;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004107#if JOBS
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004108 if (jobstate == JOBSTOPPED)
4109 set_curjob(thisjob, CUR_STOPPED);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004110#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004111 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004112 }
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004113 goto out;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004114 }
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004115 /* The process wasn't found in job list */
4116 if (JOBS && !WIFSTOPPED(status))
4117 jobless--;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004118 out:
4119 INT_ON;
4120
4121 if (thisjob && thisjob == job) {
4122 char s[48 + 1];
4123 int len;
4124
Denys Vlasenko9c541002015-10-07 15:44:36 +02004125 len = sprint_status48(s, status, 1);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004126 if (len) {
4127 s[len] = '\n';
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004128 s[len + 1] = '\0';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004129 out2str(s);
4130 }
4131 }
4132 return pid;
4133}
4134
4135#if JOBS
4136static void
Denys Vlasenko9c541002015-10-07 15:44:36 +02004137showjob(struct job *jp, int mode)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004138{
4139 struct procstat *ps;
4140 struct procstat *psend;
4141 int col;
Denis Vlasenko40ba9982007-07-14 00:48:29 +00004142 int indent_col;
Denys Vlasenko9c541002015-10-07 15:44:36 +02004143 char s[16 + 16 + 48];
4144 FILE *out = (mode & SHOW_STDERR ? stderr : stdout);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004145
4146 ps = jp->ps;
4147
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004148 if (mode & SHOW_ONLY_PGID) { /* jobs -p */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004149 /* just output process (group) id of pipeline */
Denys Vlasenko285ad152009-12-04 23:02:27 +01004150 fprintf(out, "%d\n", ps->ps_pid);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004151 return;
4152 }
4153
4154 col = fmtstr(s, 16, "[%d] ", jobno(jp));
Denis Vlasenko40ba9982007-07-14 00:48:29 +00004155 indent_col = col;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004156
4157 if (jp == curjob)
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004158 s[col - 3] = '+';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004159 else if (curjob && jp == curjob->prev_job)
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004160 s[col - 3] = '-';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004161
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004162 if (mode & SHOW_PIDS)
Denys Vlasenko285ad152009-12-04 23:02:27 +01004163 col += fmtstr(s + col, 16, "%d ", ps->ps_pid);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004164
4165 psend = ps + jp->nprocs;
4166
4167 if (jp->state == JOBRUNNING) {
4168 strcpy(s + col, "Running");
4169 col += sizeof("Running") - 1;
4170 } else {
Denys Vlasenko285ad152009-12-04 23:02:27 +01004171 int status = psend[-1].ps_status;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004172 if (jp->state == JOBSTOPPED)
4173 status = jp->stopstatus;
Denys Vlasenko9c541002015-10-07 15:44:36 +02004174 col += sprint_status48(s + col, status, 0);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004175 }
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004176 /* By now, "[JOBID]* [maybe PID] STATUS" is printed */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004177
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004178 /* This loop either prints "<cmd1> | <cmd2> | <cmd3>" line
4179 * or prints several "PID | <cmdN>" lines,
4180 * depending on SHOW_PIDS bit.
4181 * We do not print status of individual processes
4182 * between PID and <cmdN>. bash does it, but not very well:
4183 * first line shows overall job status, not process status,
4184 * making it impossible to know 1st process status.
4185 */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004186 goto start;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004187 do {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004188 /* for each process */
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004189 s[0] = '\0';
4190 col = 33;
4191 if (mode & SHOW_PIDS)
Denys Vlasenko285ad152009-12-04 23:02:27 +01004192 col = fmtstr(s, 48, "\n%*c%d ", indent_col, ' ', ps->ps_pid) - 1;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004193 start:
Denys Vlasenko285ad152009-12-04 23:02:27 +01004194 fprintf(out, "%s%*c%s%s",
4195 s,
4196 33 - col >= 0 ? 33 - col : 0, ' ',
4197 ps == jp->ps ? "" : "| ",
4198 ps->ps_cmd
4199 );
4200 } while (++ps != psend);
Denys Vlasenko9c541002015-10-07 15:44:36 +02004201 newline_and_flush(out);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004202
4203 jp->changed = 0;
4204
4205 if (jp->state == JOBDONE) {
4206 TRACE(("showjob: freeing job %d\n", jobno(jp)));
4207 freejob(jp);
4208 }
4209}
4210
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004211/*
4212 * Print a list of jobs. If "change" is nonzero, only print jobs whose
4213 * statuses have changed since the last call to showjobs.
4214 */
4215static void
Denys Vlasenko9c541002015-10-07 15:44:36 +02004216showjobs(int mode)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004217{
4218 struct job *jp;
4219
Denys Vlasenko883cea42009-07-11 15:31:59 +02004220 TRACE(("showjobs(0x%x) called\n", mode));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004221
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004222 /* Handle all finished jobs */
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004223 while (dowait(DOWAIT_NONBLOCK, NULL) > 0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004224 continue;
4225
4226 for (jp = curjob; jp; jp = jp->prev_job) {
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004227 if (!(mode & SHOW_CHANGED) || jp->changed) {
Denys Vlasenko9c541002015-10-07 15:44:36 +02004228 showjob(jp, mode);
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004229 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004230 }
4231}
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004232
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02004233static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00004234jobscmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004235{
4236 int mode, m;
4237
4238 mode = 0;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02004239 while ((m = nextopt("lp")) != '\0') {
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004240 if (m == 'l')
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004241 mode |= SHOW_PIDS;
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004242 else
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004243 mode |= SHOW_ONLY_PGID;
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004244 }
4245
4246 argv = argptr;
4247 if (*argv) {
4248 do
Denys Vlasenko9c541002015-10-07 15:44:36 +02004249 showjob(getjob(*argv, 0), mode);
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004250 while (*++argv);
Denys Vlasenko285ad152009-12-04 23:02:27 +01004251 } else {
Denys Vlasenko9c541002015-10-07 15:44:36 +02004252 showjobs(mode);
Denys Vlasenko285ad152009-12-04 23:02:27 +01004253 }
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004254
4255 return 0;
4256}
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004257#endif /* JOBS */
4258
Michael Abbott359da5e2009-12-04 23:03:29 +01004259/* Called only on finished or stopped jobs (no members are running) */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004260static int
4261getstatus(struct job *job)
4262{
4263 int status;
4264 int retval;
Michael Abbott359da5e2009-12-04 23:03:29 +01004265 struct procstat *ps;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004266
Michael Abbott359da5e2009-12-04 23:03:29 +01004267 /* Fetch last member's status */
4268 ps = job->ps + job->nprocs - 1;
4269 status = ps->ps_status;
4270 if (pipefail) {
4271 /* "set -o pipefail" mode: use last _nonzero_ status */
4272 while (status == 0 && --ps >= job->ps)
4273 status = ps->ps_status;
4274 }
4275
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004276 retval = WEXITSTATUS(status);
4277 if (!WIFEXITED(status)) {
4278#if JOBS
4279 retval = WSTOPSIG(status);
4280 if (!WIFSTOPPED(status))
4281#endif
4282 {
4283 /* XXX: limits number of signals */
4284 retval = WTERMSIG(status);
4285#if JOBS
4286 if (retval == SIGINT)
4287 job->sigint = 1;
4288#endif
4289 }
4290 retval += 128;
4291 }
Denys Vlasenko883cea42009-07-11 15:31:59 +02004292 TRACE(("getstatus: job %d, nproc %d, status 0x%x, retval 0x%x\n",
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004293 jobno(job), job->nprocs, status, retval));
4294 return retval;
4295}
4296
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02004297static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00004298waitcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004299{
4300 struct job *job;
4301 int retval;
4302 struct job *jp;
4303
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004304 nextopt(nullstr);
4305 retval = 0;
4306
4307 argv = argptr;
4308 if (!*argv) {
4309 /* wait for all jobs */
4310 for (;;) {
4311 jp = curjob;
4312 while (1) {
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004313 if (!jp) /* no running procs */
4314 goto ret;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004315 if (jp->state == JOBRUNNING)
4316 break;
4317 jp->waited = 1;
4318 jp = jp->prev_job;
4319 }
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004320 /* man bash:
4321 * "When bash is waiting for an asynchronous command via
4322 * the wait builtin, the reception of a signal for which a trap
4323 * has been set will cause the wait builtin to return immediately
4324 * with an exit status greater than 128, immediately after which
4325 * the trap is executed."
Denys Vlasenko69188112016-10-27 20:18:18 +02004326 */
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004327 dowait(DOWAIT_BLOCK_OR_SIG, NULL);
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02004328 /* if child sends us a signal *and immediately exits*,
4329 * dowait() returns pid > 0. Check this case,
4330 * not "if (dowait() < 0)"!
4331 */
Denys Vlasenko7c1ed9f2010-05-17 04:42:40 +02004332 if (pending_sig)
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02004333 goto sigout;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004334 }
4335 }
4336
4337 retval = 127;
4338 do {
4339 if (**argv != '%') {
4340 pid_t pid = number(*argv);
4341 job = curjob;
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004342 while (1) {
4343 if (!job)
4344 goto repeat;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004345 if (job->ps[job->nprocs - 1].ps_pid == pid)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004346 break;
4347 job = job->prev_job;
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004348 }
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004349 } else {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004350 job = getjob(*argv, 0);
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004351 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004352 /* loop until process terminated or stopped */
Denys Vlasenko69188112016-10-27 20:18:18 +02004353 while (job->state == JOBRUNNING) {
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004354 dowait(DOWAIT_BLOCK_OR_SIG, NULL);
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02004355 if (pending_sig)
4356 goto sigout;
Denys Vlasenko69188112016-10-27 20:18:18 +02004357 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004358 job->waited = 1;
4359 retval = getstatus(job);
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004360 repeat: ;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004361 } while (*++argv);
4362
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004363 ret:
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004364 return retval;
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02004365 sigout:
4366 retval = 128 + pending_sig;
4367 return retval;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004368}
4369
4370static struct job *
4371growjobtab(void)
4372{
4373 size_t len;
4374 ptrdiff_t offset;
4375 struct job *jp, *jq;
4376
4377 len = njobs * sizeof(*jp);
4378 jq = jobtab;
4379 jp = ckrealloc(jq, len + 4 * sizeof(*jp));
4380
4381 offset = (char *)jp - (char *)jq;
4382 if (offset) {
4383 /* Relocate pointers */
4384 size_t l = len;
4385
4386 jq = (struct job *)((char *)jq + l);
4387 while (l) {
4388 l -= sizeof(*jp);
4389 jq--;
4390#define joff(p) ((struct job *)((char *)(p) + l))
4391#define jmove(p) (p) = (void *)((char *)(p) + offset)
4392 if (joff(jp)->ps == &jq->ps0)
4393 jmove(joff(jp)->ps);
4394 if (joff(jp)->prev_job)
4395 jmove(joff(jp)->prev_job);
4396 }
4397 if (curjob)
4398 jmove(curjob);
4399#undef joff
4400#undef jmove
4401 }
4402
4403 njobs += 4;
4404 jobtab = jp;
4405 jp = (struct job *)((char *)jp + len);
4406 jq = jp + 3;
4407 do {
4408 jq->used = 0;
4409 } while (--jq >= jp);
4410 return jp;
4411}
4412
4413/*
4414 * Return a new job structure.
4415 * Called with interrupts off.
4416 */
4417static struct job *
Denis Vlasenko68404f12008-03-17 09:00:54 +00004418makejob(/*union node *node,*/ int nprocs)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004419{
4420 int i;
4421 struct job *jp;
4422
4423 for (i = njobs, jp = jobtab; ; jp++) {
4424 if (--i < 0) {
4425 jp = growjobtab();
4426 break;
4427 }
4428 if (jp->used == 0)
4429 break;
4430 if (jp->state != JOBDONE || !jp->waited)
4431 continue;
4432#if JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +00004433 if (doing_jobctl)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004434 continue;
4435#endif
4436 freejob(jp);
4437 break;
4438 }
4439 memset(jp, 0, sizeof(*jp));
4440#if JOBS
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004441 /* jp->jobctl is a bitfield.
4442 * "jp->jobctl |= jobctl" likely to give awful code */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00004443 if (doing_jobctl)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004444 jp->jobctl = 1;
4445#endif
4446 jp->prev_job = curjob;
4447 curjob = jp;
4448 jp->used = 1;
4449 jp->ps = &jp->ps0;
4450 if (nprocs > 1) {
4451 jp->ps = ckmalloc(nprocs * sizeof(struct procstat));
4452 }
Denis Vlasenko68404f12008-03-17 09:00:54 +00004453 TRACE(("makejob(%d) returns %%%d\n", nprocs,
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004454 jobno(jp)));
4455 return jp;
4456}
4457
4458#if JOBS
4459/*
4460 * Return a string identifying a command (to be printed by the
4461 * jobs command).
4462 */
4463static char *cmdnextc;
4464
4465static void
4466cmdputs(const char *s)
4467{
Denis Vlasenko92e13c22008-03-25 01:17:40 +00004468 static const char vstype[VSTYPE + 1][3] = {
4469 "", "}", "-", "+", "?", "=",
4470 "%", "%%", "#", "##"
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00004471 IF_ASH_BASH_COMPAT(, ":", "/", "//")
Denis Vlasenko92e13c22008-03-25 01:17:40 +00004472 };
4473
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004474 const char *p, *str;
Denys Vlasenko46a14772009-12-10 21:27:13 +01004475 char cc[2];
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004476 char *nextc;
Denys Vlasenkocd716832009-11-28 22:14:02 +01004477 unsigned char c;
4478 unsigned char subtype = 0;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004479 int quoted = 0;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004480
Denys Vlasenko46a14772009-12-10 21:27:13 +01004481 cc[1] = '\0';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004482 nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
4483 p = s;
Denys Vlasenko46a14772009-12-10 21:27:13 +01004484 while ((c = *p++) != '\0') {
Denis Vlasenkoef527f52008-06-23 01:52:30 +00004485 str = NULL;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004486 switch (c) {
4487 case CTLESC:
4488 c = *p++;
4489 break;
4490 case CTLVAR:
4491 subtype = *p++;
4492 if ((subtype & VSTYPE) == VSLENGTH)
4493 str = "${#";
4494 else
4495 str = "${";
Ron Yorston549deab2015-05-18 09:57:51 +02004496 goto dostr;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004497 case CTLENDVAR:
4498 str = "\"}" + !(quoted & 1);
4499 quoted >>= 1;
4500 subtype = 0;
4501 goto dostr;
4502 case CTLBACKQ:
4503 str = "$(...)";
4504 goto dostr;
Denys Vlasenko0b883582016-12-23 16:49:07 +01004505#if ENABLE_FEATURE_SH_MATH
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004506 case CTLARI:
4507 str = "$((";
4508 goto dostr;
4509 case CTLENDARI:
4510 str = "))";
4511 goto dostr;
4512#endif
4513 case CTLQUOTEMARK:
4514 quoted ^= 1;
4515 c = '"';
4516 break;
4517 case '=':
4518 if (subtype == 0)
4519 break;
4520 if ((subtype & VSTYPE) != VSNORMAL)
4521 quoted <<= 1;
4522 str = vstype[subtype & VSTYPE];
4523 if (subtype & VSNUL)
4524 c = ':';
4525 else
4526 goto checkstr;
4527 break;
4528 case '\'':
4529 case '\\':
4530 case '"':
4531 case '$':
4532 /* These can only happen inside quotes */
4533 cc[0] = c;
4534 str = cc;
4535 c = '\\';
4536 break;
4537 default:
4538 break;
4539 }
4540 USTPUTC(c, nextc);
4541 checkstr:
4542 if (!str)
4543 continue;
4544 dostr:
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02004545 while ((c = *str++) != '\0') {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004546 USTPUTC(c, nextc);
4547 }
Denys Vlasenko46a14772009-12-10 21:27:13 +01004548 } /* while *p++ not NUL */
4549
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004550 if (quoted & 1) {
4551 USTPUTC('"', nextc);
4552 }
4553 *nextc = 0;
4554 cmdnextc = nextc;
4555}
4556
4557/* cmdtxt() and cmdlist() call each other */
4558static void cmdtxt(union node *n);
4559
4560static void
4561cmdlist(union node *np, int sep)
4562{
4563 for (; np; np = np->narg.next) {
4564 if (!sep)
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00004565 cmdputs(" ");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004566 cmdtxt(np);
4567 if (sep && np->narg.next)
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00004568 cmdputs(" ");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004569 }
4570}
4571
4572static void
4573cmdtxt(union node *n)
4574{
4575 union node *np;
4576 struct nodelist *lp;
4577 const char *p;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004578
4579 if (!n)
4580 return;
4581 switch (n->type) {
4582 default:
4583#if DEBUG
4584 abort();
4585#endif
4586 case NPIPE:
4587 lp = n->npipe.cmdlist;
4588 for (;;) {
4589 cmdtxt(lp->n);
4590 lp = lp->next;
4591 if (!lp)
4592 break;
4593 cmdputs(" | ");
4594 }
4595 break;
4596 case NSEMI:
4597 p = "; ";
4598 goto binop;
4599 case NAND:
4600 p = " && ";
4601 goto binop;
4602 case NOR:
4603 p = " || ";
4604 binop:
4605 cmdtxt(n->nbinary.ch1);
4606 cmdputs(p);
4607 n = n->nbinary.ch2;
4608 goto donode;
4609 case NREDIR:
4610 case NBACKGND:
4611 n = n->nredir.n;
4612 goto donode;
4613 case NNOT:
4614 cmdputs("!");
4615 n = n->nnot.com;
4616 donode:
4617 cmdtxt(n);
4618 break;
4619 case NIF:
4620 cmdputs("if ");
4621 cmdtxt(n->nif.test);
4622 cmdputs("; then ");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004623 if (n->nif.elsepart) {
Denys Vlasenko7cee00e2009-07-24 01:08:03 +02004624 cmdtxt(n->nif.ifpart);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004625 cmdputs("; else ");
4626 n = n->nif.elsepart;
Denys Vlasenko7cee00e2009-07-24 01:08:03 +02004627 } else {
4628 n = n->nif.ifpart;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004629 }
4630 p = "; fi";
4631 goto dotail;
4632 case NSUBSHELL:
4633 cmdputs("(");
4634 n = n->nredir.n;
4635 p = ")";
4636 goto dotail;
4637 case NWHILE:
4638 p = "while ";
4639 goto until;
4640 case NUNTIL:
4641 p = "until ";
4642 until:
4643 cmdputs(p);
4644 cmdtxt(n->nbinary.ch1);
4645 n = n->nbinary.ch2;
4646 p = "; done";
4647 dodo:
4648 cmdputs("; do ");
4649 dotail:
4650 cmdtxt(n);
4651 goto dotail2;
4652 case NFOR:
4653 cmdputs("for ");
4654 cmdputs(n->nfor.var);
4655 cmdputs(" in ");
4656 cmdlist(n->nfor.args, 1);
4657 n = n->nfor.body;
4658 p = "; done";
4659 goto dodo;
4660 case NDEFUN:
4661 cmdputs(n->narg.text);
4662 p = "() { ... }";
4663 goto dotail2;
4664 case NCMD:
4665 cmdlist(n->ncmd.args, 1);
4666 cmdlist(n->ncmd.redirect, 0);
4667 break;
4668 case NARG:
4669 p = n->narg.text;
4670 dotail2:
4671 cmdputs(p);
4672 break;
4673 case NHERE:
4674 case NXHERE:
4675 p = "<<...";
4676 goto dotail2;
4677 case NCASE:
4678 cmdputs("case ");
4679 cmdputs(n->ncase.expr->narg.text);
4680 cmdputs(" in ");
4681 for (np = n->ncase.cases; np; np = np->nclist.next) {
4682 cmdtxt(np->nclist.pattern);
4683 cmdputs(") ");
4684 cmdtxt(np->nclist.body);
4685 cmdputs(";; ");
4686 }
4687 p = "esac";
4688 goto dotail2;
4689 case NTO:
4690 p = ">";
4691 goto redir;
4692 case NCLOBBER:
4693 p = ">|";
4694 goto redir;
4695 case NAPPEND:
4696 p = ">>";
4697 goto redir;
Denis Vlasenko559691a2008-10-05 18:39:31 +00004698#if ENABLE_ASH_BASH_COMPAT
4699 case NTO2:
4700#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004701 case NTOFD:
4702 p = ">&";
4703 goto redir;
4704 case NFROM:
4705 p = "<";
4706 goto redir;
4707 case NFROMFD:
4708 p = "<&";
4709 goto redir;
4710 case NFROMTO:
4711 p = "<>";
4712 redir:
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00004713 cmdputs(utoa(n->nfile.fd));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004714 cmdputs(p);
4715 if (n->type == NTOFD || n->type == NFROMFD) {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00004716 cmdputs(utoa(n->ndup.dupfd));
4717 break;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004718 }
4719 n = n->nfile.fname;
4720 goto donode;
4721 }
4722}
4723
4724static char *
4725commandtext(union node *n)
4726{
4727 char *name;
4728
4729 STARTSTACKSTR(cmdnextc);
4730 cmdtxt(n);
4731 name = stackblock();
Denys Vlasenko6a94cee2016-10-25 17:40:25 +02004732 TRACE(("commandtext: name %p, end %p\n", name, cmdnextc));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004733 return ckstrdup(name);
4734}
4735#endif /* JOBS */
4736
4737/*
4738 * Fork off a subshell. If we are doing job control, give the subshell its
4739 * own process group. Jp is a job structure that the job is to be added to.
4740 * N is the command that will be evaluated by the child. Both jp and n may
4741 * be NULL. The mode parameter can be one of the following:
4742 * FORK_FG - Fork off a foreground process.
4743 * FORK_BG - Fork off a background process.
4744 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
4745 * process group even if job control is on.
4746 *
4747 * When job control is turned off, background processes have their standard
4748 * input redirected to /dev/null (except for the second and later processes
4749 * in a pipeline).
4750 *
4751 * Called with interrupts off.
4752 */
4753/*
4754 * Clear traps on a fork.
4755 */
4756static void
4757clear_traps(void)
4758{
4759 char **tp;
4760
Denys Vlasenkob4f51d32016-10-27 12:55:09 +02004761 INT_OFF;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004762 for (tp = trap; tp < &trap[NSIG]; tp++) {
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004763 if (*tp && **tp) { /* trap not NULL or "" (SIG_IGN) */
Denys Vlasenkoe305c282009-09-25 02:12:27 +02004764 if (trap_ptr == trap)
4765 free(*tp);
4766 /* else: it "belongs" to trap_ptr vector, don't free */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004767 *tp = NULL;
Denys Vlasenko0800e3a2009-09-24 03:09:26 +02004768 if ((tp - trap) != 0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004769 setsignal(tp - trap);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004770 }
4771 }
Alexander Shishkinccb97712010-07-25 13:07:39 +02004772 may_have_traps = 0;
Denys Vlasenkob4f51d32016-10-27 12:55:09 +02004773 INT_ON;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004774}
Denis Vlasenkobdc406d2007-07-15 01:13:25 +00004775
4776/* Lives far away from here, needed for forkchild */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004777static void closescript(void);
Denis Vlasenko41770222007-10-07 18:02:52 +00004778
Denis Vlasenkobdc406d2007-07-15 01:13:25 +00004779/* Called after fork(), in child */
Denys Vlasenko70392332016-10-27 02:31:55 +02004780/* jp and n are NULL when called by openhere() for heredoc support */
Denys Vlasenko21d87d42009-09-25 00:06:51 +02004781static NOINLINE void
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02004782forkchild(struct job *jp, union node *n, int mode)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004783{
4784 int oldlvl;
4785
4786 TRACE(("Child shell %d\n", getpid()));
4787 oldlvl = shlvl;
4788 shlvl++;
4789
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004790 /* man bash: "Non-builtin commands run by bash have signal handlers
4791 * set to the values inherited by the shell from its parent".
4792 * Do we do it correctly? */
4793
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004794 closescript();
Denys Vlasenko844f9902009-09-23 03:25:52 +02004795
4796 if (mode == FORK_NOJOB /* is it `xxx` ? */
4797 && n && n->type == NCMD /* is it single cmd? */
4798 /* && n->ncmd.args->type == NARG - always true? */
Denys Vlasenko74269202010-02-21 01:26:42 +01004799 && n->ncmd.args && strcmp(n->ncmd.args->narg.text, "trap") == 0
Denys Vlasenko844f9902009-09-23 03:25:52 +02004800 && n->ncmd.args->narg.next == NULL /* "trap" with no arguments */
4801 /* && n->ncmd.args->narg.backquote == NULL - do we need to check this? */
4802 ) {
4803 TRACE(("Trap hack\n"));
4804 /* Awful hack for `trap` or $(trap).
4805 *
4806 * http://www.opengroup.org/onlinepubs/009695399/utilities/trap.html
4807 * contains an example where "trap" is executed in a subshell:
4808 *
4809 * save_traps=$(trap)
4810 * ...
4811 * eval "$save_traps"
4812 *
4813 * Standard does not say that "trap" in subshell shall print
4814 * parent shell's traps. It only says that its output
4815 * must have suitable form, but then, in the above example
4816 * (which is not supposed to be normative), it implies that.
4817 *
4818 * bash (and probably other shell) does implement it
4819 * (traps are reset to defaults, but "trap" still shows them),
4820 * but as a result, "trap" logic is hopelessly messed up:
4821 *
4822 * # trap
4823 * trap -- 'echo Ho' SIGWINCH <--- we have a handler
4824 * # (trap) <--- trap is in subshell - no output (correct, traps are reset)
4825 * # true | trap <--- trap is in subshell - no output (ditto)
4826 * # echo `true | trap` <--- in subshell - output (but traps are reset!)
4827 * trap -- 'echo Ho' SIGWINCH
4828 * # echo `(trap)` <--- in subshell in subshell - output
4829 * trap -- 'echo Ho' SIGWINCH
4830 * # echo `true | (trap)` <--- in subshell in subshell in subshell - output!
4831 * trap -- 'echo Ho' SIGWINCH
4832 *
4833 * The rules when to forget and when to not forget traps
4834 * get really complex and nonsensical.
4835 *
4836 * Our solution: ONLY bare $(trap) or `trap` is special.
4837 */
Denys Vlasenko8f88d852009-09-25 12:12:53 +02004838 /* Save trap handler strings for trap builtin to print */
Ron Yorstond840c5d2015-07-19 23:05:20 +02004839 trap_ptr = xmemdup(trap, sizeof(trap));
Denys Vlasenko8f88d852009-09-25 12:12:53 +02004840 /* Fall through into clearing traps */
Denys Vlasenko844f9902009-09-23 03:25:52 +02004841 }
Denys Vlasenkoe305c282009-09-25 02:12:27 +02004842 clear_traps();
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004843#if JOBS
4844 /* do job control only in root shell */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00004845 doing_jobctl = 0;
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004846 if (mode != FORK_NOJOB && jp->jobctl && oldlvl == 0) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004847 pid_t pgrp;
4848
4849 if (jp->nprocs == 0)
4850 pgrp = getpid();
4851 else
Denys Vlasenko285ad152009-12-04 23:02:27 +01004852 pgrp = jp->ps[0].ps_pid;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004853 /* this can fail because we are doing it in the parent also */
4854 setpgid(0, pgrp);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004855 if (mode == FORK_FG)
4856 xtcsetpgrp(ttyfd, pgrp);
4857 setsignal(SIGTSTP);
4858 setsignal(SIGTTOU);
4859 } else
4860#endif
4861 if (mode == FORK_BG) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004862 /* man bash: "When job control is not in effect,
4863 * asynchronous commands ignore SIGINT and SIGQUIT" */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004864 ignoresig(SIGINT);
4865 ignoresig(SIGQUIT);
4866 if (jp->nprocs == 0) {
4867 close(0);
4868 if (open(bb_dev_null, O_RDONLY) != 0)
Denis Vlasenko9604e1b2009-03-03 18:47:56 +00004869 ash_msg_and_raise_error("can't open '%s'", bb_dev_null);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004870 }
4871 }
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004872 if (oldlvl == 0) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004873 if (iflag) { /* why if iflag only? */
4874 setsignal(SIGINT);
4875 setsignal(SIGTERM);
4876 }
4877 /* man bash:
4878 * "In all cases, bash ignores SIGQUIT. Non-builtin
4879 * commands run by bash have signal handlers
4880 * set to the values inherited by the shell
4881 * from its parent".
4882 * Take care of the second rule: */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004883 setsignal(SIGQUIT);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004884 }
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02004885#if JOBS
Denys Vlasenko844f9902009-09-23 03:25:52 +02004886 if (n && n->type == NCMD
Denys Vlasenko74269202010-02-21 01:26:42 +01004887 && n->ncmd.args && strcmp(n->ncmd.args->narg.text, "jobs") == 0
Denys Vlasenko844f9902009-09-23 03:25:52 +02004888 ) {
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02004889 TRACE(("Job hack\n"));
Denys Vlasenko844f9902009-09-23 03:25:52 +02004890 /* "jobs": we do not want to clear job list for it,
4891 * instead we remove only _its_ own_ job from job list.
4892 * This makes "jobs .... | cat" more useful.
4893 */
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02004894 freejob(curjob);
4895 return;
4896 }
4897#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004898 for (jp = curjob; jp; jp = jp->prev_job)
4899 freejob(jp);
4900 jobless = 0;
4901}
4902
Denis Vlasenkobdc406d2007-07-15 01:13:25 +00004903/* Called after fork(), in parent */
Denis Vlasenko85c24712008-03-17 09:04:04 +00004904#if !JOBS
4905#define forkparent(jp, n, mode, pid) forkparent(jp, mode, pid)
4906#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004907static void
4908forkparent(struct job *jp, union node *n, int mode, pid_t pid)
4909{
4910 TRACE(("In parent shell: child = %d\n", pid));
4911 if (!jp) {
Denys Vlasenko70392332016-10-27 02:31:55 +02004912 /* jp is NULL when called by openhere() for heredoc support */
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004913 while (jobless && dowait(DOWAIT_NONBLOCK, NULL) > 0)
4914 continue;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004915 jobless++;
4916 return;
4917 }
4918#if JOBS
4919 if (mode != FORK_NOJOB && jp->jobctl) {
4920 int pgrp;
4921
4922 if (jp->nprocs == 0)
4923 pgrp = pid;
4924 else
Denys Vlasenko285ad152009-12-04 23:02:27 +01004925 pgrp = jp->ps[0].ps_pid;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004926 /* This can fail because we are doing it in the child also */
4927 setpgid(pid, pgrp);
4928 }
4929#endif
4930 if (mode == FORK_BG) {
4931 backgndpid = pid; /* set $! */
4932 set_curjob(jp, CUR_RUNNING);
4933 }
4934 if (jp) {
4935 struct procstat *ps = &jp->ps[jp->nprocs++];
Denys Vlasenko285ad152009-12-04 23:02:27 +01004936 ps->ps_pid = pid;
4937 ps->ps_status = -1;
4938 ps->ps_cmd = nullstr;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004939#if JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +00004940 if (doing_jobctl && n)
Denys Vlasenko285ad152009-12-04 23:02:27 +01004941 ps->ps_cmd = commandtext(n);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004942#endif
4943 }
4944}
4945
Denys Vlasenko70392332016-10-27 02:31:55 +02004946/* jp and n are NULL when called by openhere() for heredoc support */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004947static int
4948forkshell(struct job *jp, union node *n, int mode)
4949{
4950 int pid;
4951
4952 TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
4953 pid = fork();
4954 if (pid < 0) {
4955 TRACE(("Fork failed, errno=%d", errno));
4956 if (jp)
4957 freejob(jp);
Denis Vlasenkofa0b56d2008-07-01 16:09:07 +00004958 ash_msg_and_raise_error("can't fork");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004959 }
Denys Vlasenko76ace252009-10-12 15:25:01 +02004960 if (pid == 0) {
4961 CLEAR_RANDOM_T(&random_gen); /* or else $RANDOM repeats in child */
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02004962 forkchild(jp, n, mode);
Denys Vlasenko76ace252009-10-12 15:25:01 +02004963 } else {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004964 forkparent(jp, n, mode, pid);
Denys Vlasenko76ace252009-10-12 15:25:01 +02004965 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004966 return pid;
4967}
4968
4969/*
4970 * Wait for job to finish.
4971 *
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004972 * Under job control we have the problem that while a child process
4973 * is running interrupts generated by the user are sent to the child
4974 * but not to the shell. This means that an infinite loop started by
4975 * an interactive user may be hard to kill. With job control turned off,
4976 * an interactive user may place an interactive program inside a loop.
4977 * If the interactive program catches interrupts, the user doesn't want
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004978 * these interrupts to also abort the loop. The approach we take here
4979 * is to have the shell ignore interrupt signals while waiting for a
4980 * foreground process to terminate, and then send itself an interrupt
4981 * signal if the child process was terminated by an interrupt signal.
4982 * Unfortunately, some programs want to do a bit of cleanup and then
4983 * exit on interrupt; unless these processes terminate themselves by
4984 * sending a signal to themselves (instead of calling exit) they will
4985 * confuse this approach.
4986 *
4987 * Called with interrupts off.
4988 */
4989static int
4990waitforjob(struct job *jp)
4991{
4992 int st;
4993
4994 TRACE(("waitforjob(%%%d) called\n", jobno(jp)));
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004995
4996 INT_OFF;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004997 while (jp->state == JOBRUNNING) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004998 /* In non-interactive shells, we _can_ get
4999 * a keyboard signal here and be EINTRed,
5000 * but we just loop back, waiting for command to complete.
5001 *
5002 * man bash:
5003 * "If bash is waiting for a command to complete and receives
5004 * a signal for which a trap has been set, the trap
5005 * will not be executed until the command completes."
5006 *
5007 * Reality is that even if trap is not set, bash
5008 * will not act on the signal until command completes.
5009 * Try this. sleep5intoff.c:
5010 * #include <signal.h>
5011 * #include <unistd.h>
5012 * int main() {
5013 * sigset_t set;
5014 * sigemptyset(&set);
5015 * sigaddset(&set, SIGINT);
5016 * sigaddset(&set, SIGQUIT);
5017 * sigprocmask(SIG_BLOCK, &set, NULL);
5018 * sleep(5);
5019 * return 0;
5020 * }
5021 * $ bash -c './sleep5intoff; echo hi'
5022 * ^C^C^C^C <--- pressing ^C once a second
5023 * $ _
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005024 * $ bash -c './sleep5intoff; echo hi'
5025 * ^\^\^\^\hi <--- pressing ^\ (SIGQUIT)
5026 * $ _
5027 */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005028 dowait(DOWAIT_BLOCK, jp);
5029 }
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005030 INT_ON;
5031
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005032 st = getstatus(jp);
5033#if JOBS
5034 if (jp->jobctl) {
5035 xtcsetpgrp(ttyfd, rootpid);
5036 /*
5037 * This is truly gross.
5038 * If we're doing job control, then we did a TIOCSPGRP which
5039 * caused us (the shell) to no longer be in the controlling
5040 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
5041 * intuit from the subprocess exit status whether a SIGINT
5042 * occurred, and if so interrupt ourselves. Yuck. - mycroft
5043 */
Denis Vlasenko991a1da2008-02-10 19:02:53 +00005044 if (jp->sigint) /* TODO: do the same with all signals */
5045 raise(SIGINT); /* ... by raise(jp->sig) instead? */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005046 }
5047 if (jp->state == JOBDONE)
5048#endif
5049 freejob(jp);
5050 return st;
5051}
5052
5053/*
5054 * return 1 if there are stopped jobs, otherwise 0
5055 */
5056static int
5057stoppedjobs(void)
5058{
5059 struct job *jp;
5060 int retval;
5061
5062 retval = 0;
5063 if (job_warning)
5064 goto out;
5065 jp = curjob;
5066 if (jp && jp->state == JOBSTOPPED) {
5067 out2str("You have stopped jobs.\n");
5068 job_warning = 2;
5069 retval++;
5070 }
5071 out:
5072 return retval;
5073}
5074
5075
Denys Vlasenko70392332016-10-27 02:31:55 +02005076/*
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005077 * Code for dealing with input/output redirection.
5078 */
5079
Denys Vlasenko8d0e0cd2011-01-25 23:21:46 +01005080#undef EMPTY
5081#undef CLOSED
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005082#define EMPTY -2 /* marks an unused slot in redirtab */
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005083#define CLOSED -3 /* marks a slot of previously-closed fd */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005084
5085/*
5086 * Open a file in noclobber mode.
5087 * The code was copied from bash.
5088 */
5089static int
5090noclobberopen(const char *fname)
5091{
5092 int r, fd;
5093 struct stat finfo, finfo2;
5094
5095 /*
5096 * If the file exists and is a regular file, return an error
5097 * immediately.
5098 */
5099 r = stat(fname, &finfo);
5100 if (r == 0 && S_ISREG(finfo.st_mode)) {
5101 errno = EEXIST;
5102 return -1;
5103 }
5104
5105 /*
5106 * If the file was not present (r != 0), make sure we open it
5107 * exclusively so that if it is created before we open it, our open
5108 * will fail. Make sure that we do not truncate an existing file.
5109 * Note that we don't turn on O_EXCL unless the stat failed -- if the
5110 * file was not a regular file, we leave O_EXCL off.
5111 */
5112 if (r != 0)
5113 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
5114 fd = open(fname, O_WRONLY|O_CREAT, 0666);
5115
5116 /* If the open failed, return the file descriptor right away. */
5117 if (fd < 0)
5118 return fd;
5119
5120 /*
5121 * OK, the open succeeded, but the file may have been changed from a
5122 * non-regular file to a regular file between the stat and the open.
5123 * We are assuming that the O_EXCL open handles the case where FILENAME
5124 * did not exist and is symlinked to an existing file between the stat
5125 * and open.
5126 */
5127
5128 /*
5129 * If we can open it and fstat the file descriptor, and neither check
5130 * revealed that it was a regular file, and the file has not been
5131 * replaced, return the file descriptor.
5132 */
Denys Vlasenko8d3e2252010-08-31 12:42:06 +02005133 if (fstat(fd, &finfo2) == 0
5134 && !S_ISREG(finfo2.st_mode)
5135 && finfo.st_dev == finfo2.st_dev
5136 && finfo.st_ino == finfo2.st_ino
5137 ) {
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005138 return fd;
Denys Vlasenko8d3e2252010-08-31 12:42:06 +02005139 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005140
5141 /* The file has been replaced. badness. */
5142 close(fd);
5143 errno = EEXIST;
5144 return -1;
5145}
5146
5147/*
5148 * Handle here documents. Normally we fork off a process to write the
5149 * data to a pipe. If the document is short, we can stuff the data in
5150 * the pipe without forking.
5151 */
5152/* openhere needs this forward reference */
5153static void expandhere(union node *arg, int fd);
5154static int
5155openhere(union node *redir)
5156{
5157 int pip[2];
5158 size_t len = 0;
5159
5160 if (pipe(pip) < 0)
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00005161 ash_msg_and_raise_error("pipe call failed");
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005162 if (redir->type == NHERE) {
5163 len = strlen(redir->nhere.doc->narg.text);
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005164 if (len <= PIPE_BUF) {
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005165 full_write(pip[1], redir->nhere.doc->narg.text, len);
5166 goto out;
5167 }
5168 }
5169 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
Denis Vlasenko0b769642008-07-24 07:54:57 +00005170 /* child */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005171 close(pip[0]);
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005172 ignoresig(SIGINT); //signal(SIGINT, SIG_IGN);
5173 ignoresig(SIGQUIT); //signal(SIGQUIT, SIG_IGN);
5174 ignoresig(SIGHUP); //signal(SIGHUP, SIG_IGN);
5175 ignoresig(SIGTSTP); //signal(SIGTSTP, SIG_IGN);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005176 signal(SIGPIPE, SIG_DFL);
5177 if (redir->type == NHERE)
5178 full_write(pip[1], redir->nhere.doc->narg.text, len);
Denis Vlasenko0b769642008-07-24 07:54:57 +00005179 else /* NXHERE */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005180 expandhere(redir->nhere.doc, pip[1]);
Bernhard Reutner-Fischer636a1f82008-05-19 09:29:47 +00005181 _exit(EXIT_SUCCESS);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005182 }
5183 out:
5184 close(pip[1]);
5185 return pip[0];
5186}
5187
5188static int
5189openredirect(union node *redir)
5190{
5191 char *fname;
5192 int f;
5193
5194 switch (redir->nfile.type) {
Denys Vlasenko557482c2016-09-25 21:24:04 +02005195/* Can't happen, our single caller does this itself */
5196// case NTOFD:
5197// case NFROMFD:
5198// return -1;
5199 case NHERE:
5200 case NXHERE:
5201 return openhere(redir);
5202 }
5203
5204 /* For N[X]HERE, reading redir->nfile.expfname would touch beyond
5205 * allocated space. Do it only when we know it is safe.
5206 */
5207 fname = redir->nfile.expfname;
5208
5209 switch (redir->nfile.type) {
5210 default:
5211#if DEBUG
5212 abort();
5213#endif
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005214 case NFROM:
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005215 f = open(fname, O_RDONLY);
5216 if (f < 0)
5217 goto eopen;
5218 break;
5219 case NFROMTO:
Andreas Bühmannda75f442010-06-24 04:32:37 +02005220 f = open(fname, O_RDWR|O_CREAT, 0666);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005221 if (f < 0)
5222 goto ecreate;
5223 break;
5224 case NTO:
Denis Vlasenko559691a2008-10-05 18:39:31 +00005225#if ENABLE_ASH_BASH_COMPAT
5226 case NTO2:
5227#endif
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005228 /* Take care of noclobber mode. */
5229 if (Cflag) {
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005230 f = noclobberopen(fname);
5231 if (f < 0)
5232 goto ecreate;
5233 break;
5234 }
5235 /* FALLTHROUGH */
5236 case NCLOBBER:
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005237 f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666);
5238 if (f < 0)
5239 goto ecreate;
5240 break;
5241 case NAPPEND:
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005242 f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666);
5243 if (f < 0)
5244 goto ecreate;
5245 break;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005246 }
5247
5248 return f;
5249 ecreate:
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +00005250 ash_msg_and_raise_error("can't create %s: %s", fname, errmsg(errno, "nonexistent directory"));
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005251 eopen:
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +00005252 ash_msg_and_raise_error("can't open %s: %s", fname, errmsg(errno, "no such file"));
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005253}
5254
5255/*
Denys Vlasenko64774602016-10-26 15:24:30 +02005256 * Copy a file descriptor to be >= 10. Throws exception on error.
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005257 */
5258static int
Denys Vlasenko64774602016-10-26 15:24:30 +02005259savefd(int from)
5260{
5261 int newfd;
5262 int err;
5263
5264 newfd = fcntl(from, F_DUPFD, 10);
5265 err = newfd < 0 ? errno : 0;
5266 if (err != EBADF) {
5267 if (err)
5268 ash_msg_and_raise_error("%d: %m", from);
5269 close(from);
5270 fcntl(newfd, F_SETFD, FD_CLOEXEC);
5271 }
5272
5273 return newfd;
5274}
5275static int
5276dup2_or_raise(int from, int to)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005277{
5278 int newfd;
5279
Denys Vlasenko64774602016-10-26 15:24:30 +02005280 newfd = (from != to) ? dup2(from, to) : to;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005281 if (newfd < 0) {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005282 /* Happens when source fd is not open: try "echo >&99" */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005283 ash_msg_and_raise_error("%d: %m", from);
5284 }
5285 return newfd;
5286}
5287
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005288/* Struct def and variable are moved down to the first usage site */
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005289struct two_fd_t {
5290 int orig, copy;
5291};
Denis Vlasenko0b769642008-07-24 07:54:57 +00005292struct redirtab {
5293 struct redirtab *next;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005294 int pair_count;
Denys Vlasenko606291b2009-09-23 23:15:43 +02005295 struct two_fd_t two_fd[];
Denis Vlasenko0b769642008-07-24 07:54:57 +00005296};
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005297#define redirlist (G_var.redirlist)
Denys Vlasenko64774602016-10-26 15:24:30 +02005298enum {
5299 COPYFD_RESTORE = (int)~(INT_MAX),
5300};
Denis Vlasenko0b769642008-07-24 07:54:57 +00005301
Denys Vlasenko37dc08b2016-10-02 04:38:07 +02005302static int
5303need_to_remember(struct redirtab *rp, int fd)
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005304{
5305 int i;
5306
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005307 if (!rp) /* remembering was not requested */
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005308 return 0;
5309
5310 for (i = 0; i < rp->pair_count; i++) {
5311 if (rp->two_fd[i].orig == fd) {
5312 /* already remembered */
5313 return 0;
5314 }
5315 }
5316 return 1;
5317}
5318
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005319/* "hidden" fd is a fd used to read scripts, or a copy of such */
Denys Vlasenko37dc08b2016-10-02 04:38:07 +02005320static int
5321is_hidden_fd(struct redirtab *rp, int fd)
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005322{
5323 int i;
Denis Vlasenko34c73c42008-08-16 11:48:02 +00005324 struct parsefile *pf;
5325
5326 if (fd == -1)
5327 return 0;
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005328 /* Check open scripts' fds */
Denis Vlasenko34c73c42008-08-16 11:48:02 +00005329 pf = g_parsefile;
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005330 while (pf) {
Denys Vlasenko79b3d422010-06-03 04:29:08 +02005331 /* We skip pf_fd == 0 case because of the following case:
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005332 * $ ash # running ash interactively
5333 * $ . ./script.sh
5334 * and in script.sh: "exec 9>&0".
Denys Vlasenko79b3d422010-06-03 04:29:08 +02005335 * Even though top-level pf_fd _is_ 0,
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005336 * it's still ok to use it: "read" builtin uses it,
5337 * why should we cripple "exec" builtin?
5338 */
Denys Vlasenko79b3d422010-06-03 04:29:08 +02005339 if (pf->pf_fd > 0 && fd == pf->pf_fd) {
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005340 return 1;
5341 }
5342 pf = pf->prev;
5343 }
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005344
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005345 if (!rp)
5346 return 0;
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005347 /* Check saved fds of redirects */
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005348 fd |= COPYFD_RESTORE;
5349 for (i = 0; i < rp->pair_count; i++) {
5350 if (rp->two_fd[i].copy == fd) {
5351 return 1;
5352 }
5353 }
5354 return 0;
5355}
5356
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005357/*
5358 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
5359 * old file descriptors are stashed away so that the redirection can be
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005360 * undone by calling popredir.
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005361 */
5362/* flags passed to redirect */
5363#define REDIR_PUSH 01 /* save previous values of file descriptors */
5364#define REDIR_SAVEFD2 03 /* set preverrout */
5365static void
5366redirect(union node *redir, int flags)
5367{
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005368 struct redirtab *sv;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005369 int sv_pos;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005370 int i;
5371 int fd;
5372 int newfd;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005373 int copied_fd2 = -1;
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005374
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005375 if (!redir) {
5376 return;
5377 }
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005378
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005379 sv = NULL;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005380 sv_pos = 0;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005381 INT_OFF;
5382 if (flags & REDIR_PUSH) {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005383 union node *tmp = redir;
5384 do {
5385 sv_pos++;
Denis Vlasenko559691a2008-10-05 18:39:31 +00005386#if ENABLE_ASH_BASH_COMPAT
Chris Metcalfc3c1fb62010-01-08 13:18:06 +01005387 if (tmp->nfile.type == NTO2)
Denis Vlasenko559691a2008-10-05 18:39:31 +00005388 sv_pos++;
5389#endif
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005390 tmp = tmp->nfile.next;
5391 } while (tmp);
5392 sv = ckmalloc(sizeof(*sv) + sv_pos * sizeof(sv->two_fd[0]));
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005393 sv->next = redirlist;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005394 sv->pair_count = sv_pos;
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005395 redirlist = sv;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005396 while (sv_pos > 0) {
5397 sv_pos--;
5398 sv->two_fd[sv_pos].orig = sv->two_fd[sv_pos].copy = EMPTY;
5399 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005400 }
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005401
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005402 do {
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005403 int right_fd = -1;
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00005404 fd = redir->nfile.fd;
Denis Vlasenko0b769642008-07-24 07:54:57 +00005405 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005406 right_fd = redir->ndup.dupfd;
5407 //bb_error_msg("doing %d > %d", fd, right_fd);
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005408 /* redirect from/to same file descriptor? */
5409 if (right_fd == fd)
5410 continue;
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005411 /* "echo >&10" and 10 is a fd opened to a sh script? */
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005412 if (is_hidden_fd(sv, right_fd)) {
5413 errno = EBADF; /* as if it is closed */
5414 ash_msg_and_raise_error("%d: %m", right_fd);
5415 }
Denis Vlasenko0b769642008-07-24 07:54:57 +00005416 newfd = -1;
5417 } else {
5418 newfd = openredirect(redir); /* always >= 0 */
5419 if (fd == newfd) {
5420 /* Descriptor wasn't open before redirect.
5421 * Mark it for close in the future */
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005422 if (need_to_remember(sv, fd)) {
Denis Vlasenko5a867312008-07-24 19:46:38 +00005423 goto remember_to_close;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005424 }
Denis Vlasenko0b769642008-07-24 07:54:57 +00005425 continue;
5426 }
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005427 }
Denis Vlasenko559691a2008-10-05 18:39:31 +00005428#if ENABLE_ASH_BASH_COMPAT
5429 redirect_more:
5430#endif
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005431 if (need_to_remember(sv, fd)) {
Denis Vlasenko0b769642008-07-24 07:54:57 +00005432 /* Copy old descriptor */
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005433 /* Careful to not accidentally "save"
5434 * to the same fd as right side fd in N>&M */
5435 int minfd = right_fd < 10 ? 10 : right_fd + 1;
Denys Vlasenko86584e12017-01-07 10:15:01 +01005436#if defined(F_DUPFD_CLOEXEC)
5437 i = fcntl(fd, F_DUPFD_CLOEXEC, minfd);
5438#else
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005439 i = fcntl(fd, F_DUPFD, minfd);
Denys Vlasenko86584e12017-01-07 10:15:01 +01005440#endif
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005441 if (i == -1) {
5442 i = errno;
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005443 if (i != EBADF) {
5444 /* Strange error (e.g. "too many files" EMFILE?) */
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005445 if (newfd >= 0)
5446 close(newfd);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005447 errno = i;
5448 ash_msg_and_raise_error("%d: %m", fd);
5449 /* NOTREACHED */
5450 }
Denis Vlasenko5a867312008-07-24 19:46:38 +00005451 /* EBADF: it is not open - good, remember to close it */
5452 remember_to_close:
5453 i = CLOSED;
Denis Vlasenko22f74142008-07-24 22:34:43 +00005454 } else { /* fd is open, save its copy */
Denys Vlasenko86584e12017-01-07 10:15:01 +01005455#if !defined(F_DUPFD_CLOEXEC)
5456 fcntl(i, F_SETFD, FD_CLOEXEC);
5457#endif
Denis Vlasenko22f74142008-07-24 22:34:43 +00005458 /* "exec fd>&-" should not close fds
5459 * which point to script file(s).
5460 * Force them to be restored afterwards */
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005461 if (is_hidden_fd(sv, fd))
5462 i |= COPYFD_RESTORE;
Denis Vlasenko22f74142008-07-24 22:34:43 +00005463 }
Denis Vlasenko5a867312008-07-24 19:46:38 +00005464 if (fd == 2)
5465 copied_fd2 = i;
5466 sv->two_fd[sv_pos].orig = fd;
5467 sv->two_fd[sv_pos].copy = i;
5468 sv_pos++;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005469 }
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005470 if (newfd < 0) {
5471 /* NTOFD/NFROMFD: copy redir->ndup.dupfd to fd */
Denis Vlasenko22f74142008-07-24 22:34:43 +00005472 if (redir->ndup.dupfd < 0) { /* "fd>&-" */
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +00005473 /* Don't want to trigger debugging */
5474 if (fd != -1)
5475 close(fd);
Denis Vlasenko5a867312008-07-24 19:46:38 +00005476 } else {
Denys Vlasenko64774602016-10-26 15:24:30 +02005477 dup2_or_raise(redir->ndup.dupfd, fd);
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005478 }
Denis Vlasenko5a867312008-07-24 19:46:38 +00005479 } else if (fd != newfd) { /* move newfd to fd */
Denys Vlasenko64774602016-10-26 15:24:30 +02005480 dup2_or_raise(newfd, fd);
Denis Vlasenko559691a2008-10-05 18:39:31 +00005481#if ENABLE_ASH_BASH_COMPAT
5482 if (!(redir->nfile.type == NTO2 && fd == 2))
5483#endif
5484 close(newfd);
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005485 }
Denis Vlasenko559691a2008-10-05 18:39:31 +00005486#if ENABLE_ASH_BASH_COMPAT
5487 if (redir->nfile.type == NTO2 && fd == 1) {
5488 /* We already redirected it to fd 1, now copy it to 2 */
5489 newfd = 1;
5490 fd = 2;
5491 goto redirect_more;
5492 }
5493#endif
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00005494 } while ((redir = redir->nfile.next) != NULL);
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005495
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005496 INT_ON;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005497 if ((flags & REDIR_SAVEFD2) && copied_fd2 >= 0)
5498 preverrout_fd = copied_fd2;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005499}
5500
5501/*
5502 * Undo the effects of the last redirection.
5503 */
5504static void
Denis Vlasenko34c73c42008-08-16 11:48:02 +00005505popredir(int drop, int restore)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005506{
5507 struct redirtab *rp;
5508 int i;
5509
Denys Vlasenkoeaf94362016-10-25 21:46:03 +02005510 if (redirlist == NULL)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005511 return;
5512 INT_OFF;
5513 rp = redirlist;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005514 for (i = 0; i < rp->pair_count; i++) {
5515 int fd = rp->two_fd[i].orig;
Denis Vlasenko22f74142008-07-24 22:34:43 +00005516 int copy = rp->two_fd[i].copy;
5517 if (copy == CLOSED) {
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005518 if (!drop)
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005519 close(fd);
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005520 continue;
5521 }
Denis Vlasenko22f74142008-07-24 22:34:43 +00005522 if (copy != EMPTY) {
Denis Vlasenko34c73c42008-08-16 11:48:02 +00005523 if (!drop || (restore && (copy & COPYFD_RESTORE))) {
Denis Vlasenko22f74142008-07-24 22:34:43 +00005524 copy &= ~COPYFD_RESTORE;
Denis Vlasenko5a867312008-07-24 19:46:38 +00005525 /*close(fd);*/
Denys Vlasenko64774602016-10-26 15:24:30 +02005526 dup2_or_raise(copy, fd);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005527 }
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +00005528 close(copy & ~COPYFD_RESTORE);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005529 }
5530 }
5531 redirlist = rp->next;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005532 free(rp);
5533 INT_ON;
5534}
5535
5536/*
5537 * Undo all redirections. Called on error or interrupt.
5538 */
5539
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005540static int
5541redirectsafe(union node *redir, int flags)
5542{
5543 int err;
5544 volatile int saveint;
5545 struct jmploc *volatile savehandler = exception_handler;
5546 struct jmploc jmploc;
5547
5548 SAVE_INT(saveint);
Denis Vlasenko5a867312008-07-24 19:46:38 +00005549 /* "echo 9>/dev/null; echo >&9; echo result: $?" - result should be 1, not 2! */
5550 err = setjmp(jmploc.loc); // huh?? was = setjmp(jmploc.loc) * 2;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005551 if (!err) {
5552 exception_handler = &jmploc;
5553 redirect(redir, flags);
5554 }
5555 exception_handler = savehandler;
Denis Vlasenko7f88e342009-03-19 03:36:18 +00005556 if (err && exception_type != EXERROR)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005557 longjmp(exception_handler->loc, 1);
5558 RESTORE_INT(saveint);
5559 return err;
5560}
5561
5562
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005563/* ============ Routines to expand arguments to commands
5564 *
5565 * We have to deal with backquotes, shell variables, and file metacharacters.
5566 */
5567
Denys Vlasenko0b883582016-12-23 16:49:07 +01005568#if ENABLE_FEATURE_SH_MATH
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005569static arith_t
5570ash_arith(const char *s)
5571{
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005572 arith_state_t math_state;
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005573 arith_t result;
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005574
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005575 math_state.lookupvar = lookupvar;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02005576 math_state.setvar = setvar0;
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005577 //math_state.endofname = endofname;
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005578
5579 INT_OFF;
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005580 result = arith(&math_state, s);
Denys Vlasenko063847d2010-09-15 13:33:02 +02005581 if (math_state.errmsg)
5582 ash_msg_and_raise_error(math_state.errmsg);
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005583 INT_ON;
5584
5585 return result;
5586}
Denis Vlasenko448d30e2008-06-27 00:24:11 +00005587#endif
5588
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005589/*
5590 * expandarg flags
5591 */
5592#define EXP_FULL 0x1 /* perform word splitting & file globbing */
5593#define EXP_TILDE 0x2 /* do normal tilde expansion */
5594#define EXP_VARTILDE 0x4 /* expand tildes in an assignment */
5595#define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */
Denys Vlasenkodb74c6c2016-10-24 21:12:33 +02005596/* ^^^^^^^^^^^^^^ this is meant to support constructs such as "cmd >file*.txt"
5597 * POSIX says for this case:
5598 * Pathname expansion shall not be performed on the word by a
5599 * non-interactive shell; an interactive shell may perform it, but shall
5600 * do so only when the expansion would result in one word.
5601 * Currently, our code complies to the above rule by never globbing
5602 * redirection filenames.
5603 * Bash performs globbing, unless it is non-interactive and in POSIX mode.
5604 * (this means that on a typical Linux distro, bash almost always
5605 * performs globbing, and thus diverges from what we do).
5606 */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005607#define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */
Ron Yorston549deab2015-05-18 09:57:51 +02005608#define EXP_QPAT 0x20 /* pattern in quoted parameter expansion */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005609#define EXP_VARTILDE2 0x40 /* expand tildes after colons only */
5610#define EXP_WORD 0x80 /* expand word in parameter expansion */
Ron Yorston3df47f92015-05-18 09:53:26 +02005611#define EXP_QUOTED 0x100 /* expand word in double quotes */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005612/*
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005613 * rmescape() flags
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005614 */
5615#define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
5616#define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005617#define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */
5618#define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */
Ron Yorston417622c2015-05-18 09:59:14 +02005619#define RMESCAPE_SLASH 0x20 /* Stop globbing after slash */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005620
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005621/* Add CTLESC when necessary. */
Ron Yorston549deab2015-05-18 09:57:51 +02005622#define QUOTES_ESC (EXP_FULL | EXP_CASE | EXP_QPAT | EXP_REDIR)
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005623/* Do not skip NUL characters. */
5624#define QUOTES_KEEPNUL EXP_TILDE
5625
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005626/*
5627 * Structure specifying which parts of the string should be searched
5628 * for IFS characters.
5629 */
5630struct ifsregion {
5631 struct ifsregion *next; /* next region in list */
5632 int begoff; /* offset of start of region */
5633 int endoff; /* offset of end of region */
5634 int nulonly; /* search for nul bytes only */
5635};
5636
5637struct arglist {
5638 struct strlist *list;
5639 struct strlist **lastp;
5640};
5641
5642/* output of current string */
5643static char *expdest;
5644/* list of back quote expressions */
5645static struct nodelist *argbackq;
5646/* first struct in list of ifs regions */
5647static struct ifsregion ifsfirst;
5648/* last struct in list */
5649static struct ifsregion *ifslastp;
5650/* holds expanded arg list */
5651static struct arglist exparg;
5652
5653/*
5654 * Our own itoa().
5655 */
Denys Vlasenko0b883582016-12-23 16:49:07 +01005656#if !ENABLE_FEATURE_SH_MATH
Denys Vlasenko26777aa2010-11-22 23:49:10 +01005657/* cvtnum() is used even if math support is off (to prepare $? values and such) */
5658typedef long arith_t;
5659# define ARITH_FMT "%ld"
5660#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005661static int
5662cvtnum(arith_t num)
5663{
5664 int len;
5665
Denys Vlasenko9c541002015-10-07 15:44:36 +02005666 expdest = makestrspace(sizeof(arith_t)*3 + 2, expdest);
5667 len = fmtstr(expdest, sizeof(arith_t)*3 + 2, ARITH_FMT, num);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005668 STADJUST(len, expdest);
5669 return len;
5670}
5671
Denys Vlasenko455e4222016-10-27 14:45:13 +02005672/*
5673 * Break the argument string into pieces based upon IFS and add the
5674 * strings to the argument list. The regions of the string to be
5675 * searched for IFS characters have been stored by recordregion.
5676 */
5677static void
5678ifsbreakup(char *string, struct arglist *arglist)
5679{
5680 struct ifsregion *ifsp;
5681 struct strlist *sp;
5682 char *start;
5683 char *p;
5684 char *q;
5685 const char *ifs, *realifs;
5686 int ifsspc;
5687 int nulonly;
5688
5689 start = string;
5690 if (ifslastp != NULL) {
5691 ifsspc = 0;
5692 nulonly = 0;
5693 realifs = ifsset() ? ifsval() : defifs;
5694 ifsp = &ifsfirst;
5695 do {
5696 p = string + ifsp->begoff;
5697 nulonly = ifsp->nulonly;
5698 ifs = nulonly ? nullstr : realifs;
5699 ifsspc = 0;
5700 while (p < string + ifsp->endoff) {
5701 q = p;
5702 if ((unsigned char)*p == CTLESC)
5703 p++;
5704 if (!strchr(ifs, *p)) {
5705 p++;
5706 continue;
5707 }
5708 if (!nulonly)
5709 ifsspc = (strchr(defifs, *p) != NULL);
5710 /* Ignore IFS whitespace at start */
5711 if (q == start && ifsspc) {
5712 p++;
5713 start = p;
5714 continue;
5715 }
5716 *q = '\0';
5717 sp = stzalloc(sizeof(*sp));
5718 sp->text = start;
5719 *arglist->lastp = sp;
5720 arglist->lastp = &sp->next;
5721 p++;
5722 if (!nulonly) {
5723 for (;;) {
5724 if (p >= string + ifsp->endoff) {
5725 break;
5726 }
5727 q = p;
5728 if ((unsigned char)*p == CTLESC)
5729 p++;
5730 if (strchr(ifs, *p) == NULL) {
5731 p = q;
5732 break;
5733 }
5734 if (strchr(defifs, *p) == NULL) {
5735 if (ifsspc) {
5736 p++;
5737 ifsspc = 0;
5738 } else {
5739 p = q;
5740 break;
5741 }
5742 } else
5743 p++;
5744 }
5745 }
5746 start = p;
5747 } /* while */
5748 ifsp = ifsp->next;
5749 } while (ifsp != NULL);
5750 if (nulonly)
5751 goto add;
5752 }
5753
5754 if (!*start)
5755 return;
5756
5757 add:
5758 sp = stzalloc(sizeof(*sp));
5759 sp->text = start;
5760 *arglist->lastp = sp;
5761 arglist->lastp = &sp->next;
5762}
5763
5764static void
5765ifsfree(void)
5766{
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02005767 struct ifsregion *p = ifsfirst.next;
5768
5769 if (!p)
5770 goto out;
Denys Vlasenko455e4222016-10-27 14:45:13 +02005771
5772 INT_OFF;
Denys Vlasenko455e4222016-10-27 14:45:13 +02005773 do {
5774 struct ifsregion *ifsp;
5775 ifsp = p->next;
5776 free(p);
5777 p = ifsp;
5778 } while (p);
Denys Vlasenko455e4222016-10-27 14:45:13 +02005779 ifsfirst.next = NULL;
5780 INT_ON;
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02005781 out:
5782 ifslastp = NULL;
Denys Vlasenko455e4222016-10-27 14:45:13 +02005783}
5784
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005785static size_t
5786esclen(const char *start, const char *p)
5787{
5788 size_t esc = 0;
5789
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005790 while (p > start && (unsigned char)*--p == CTLESC) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005791 esc++;
5792 }
5793 return esc;
5794}
5795
5796/*
5797 * Remove any CTLESC characters from a string.
5798 */
5799static char *
Denys Vlasenkob6c84342009-08-29 20:23:20 +02005800rmescapes(char *str, int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005801{
Ron Yorston417622c2015-05-18 09:59:14 +02005802 static const char qchars[] ALIGN1 = {
5803 IF_ASH_BASH_COMPAT('/',) CTLESC, CTLQUOTEMARK, '\0' };
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00005804
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005805 char *p, *q, *r;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005806 unsigned inquotes;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005807 unsigned protect_against_glob;
5808 unsigned globbing;
Ron Yorston417622c2015-05-18 09:59:14 +02005809 IF_ASH_BASH_COMPAT(unsigned slash = flag & RMESCAPE_SLASH;)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005810
Ron Yorston417622c2015-05-18 09:59:14 +02005811 p = strpbrk(str, qchars IF_ASH_BASH_COMPAT(+ !slash));
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005812 if (!p)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005813 return str;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005814
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005815 q = p;
5816 r = str;
5817 if (flag & RMESCAPE_ALLOC) {
5818 size_t len = p - str;
5819 size_t fulllen = len + strlen(p) + 1;
5820
5821 if (flag & RMESCAPE_GROW) {
Colin Watson3963d942010-04-26 14:21:27 +02005822 int strloc = str - (char *)stackblock();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005823 r = makestrspace(fulllen, expdest);
Colin Watson3963d942010-04-26 14:21:27 +02005824 /* p and str may be invalidated by makestrspace */
5825 str = (char *)stackblock() + strloc;
5826 p = str + len;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005827 } else if (flag & RMESCAPE_HEAP) {
5828 r = ckmalloc(fulllen);
5829 } else {
5830 r = stalloc(fulllen);
5831 }
5832 q = r;
5833 if (len > 0) {
Denis Vlasenko29eb3592008-05-18 14:06:08 +00005834 q = (char *)memcpy(q, str, len) + len;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005835 }
5836 }
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005837
Ron Yorston549deab2015-05-18 09:57:51 +02005838 inquotes = 0;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005839 globbing = flag & RMESCAPE_GLOB;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005840 protect_against_glob = globbing;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005841 while (*p) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01005842 if ((unsigned char)*p == CTLQUOTEMARK) {
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005843// Note: both inquotes and protect_against_glob only affect whether
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005844 inquotes = ~inquotes;
5845 p++;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005846 protect_against_glob = globbing;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005847 continue;
5848 }
Ron Yorston549deab2015-05-18 09:57:51 +02005849 if ((unsigned char)*p == CTLESC) {
5850 p++;
Denys Vlasenko13f20912016-09-25 20:54:25 +02005851#if DEBUG
5852 if (*p == '\0')
5853 ash_msg_and_raise_error("CTLESC at EOL (shouldn't happen)");
5854#endif
Ron Yorston549deab2015-05-18 09:57:51 +02005855 if (protect_against_glob) {
5856 *q++ = '\\';
5857 }
5858 } else if (*p == '\\' && !inquotes) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005859 /* naked back slash */
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005860 protect_against_glob = 0;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005861 goto copy;
5862 }
Ron Yorston417622c2015-05-18 09:59:14 +02005863#if ENABLE_ASH_BASH_COMPAT
5864 else if (*p == '/' && slash) {
5865 /* stop handling globbing and mark location of slash */
5866 globbing = slash = 0;
5867 *p = CTLESC;
5868 }
5869#endif
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005870 protect_against_glob = globbing;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005871 copy:
5872 *q++ = *p++;
5873 }
5874 *q = '\0';
5875 if (flag & RMESCAPE_GROW) {
5876 expdest = r;
5877 STADJUST(q - r + 1, expdest);
5878 }
5879 return r;
5880}
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005881#define pmatch(a, b) !fnmatch((a), (b), 0)
5882
5883/*
5884 * Prepare a pattern for a expmeta (internal glob(3)) call.
5885 *
5886 * Returns an stalloced string.
5887 */
5888static char *
Ron Yorston549deab2015-05-18 09:57:51 +02005889preglob(const char *pattern, int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005890{
Ron Yorston549deab2015-05-18 09:57:51 +02005891 return rmescapes((char *)pattern, flag | RMESCAPE_GLOB);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005892}
5893
5894/*
5895 * Put a string on the stack.
5896 */
5897static void
5898memtodest(const char *p, size_t len, int syntax, int quotes)
5899{
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005900 char *q;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005901
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005902 if (!len)
5903 return;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005904
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005905 q = makestrspace((quotes & QUOTES_ESC) ? len * 2 : len, expdest);
5906
5907 do {
Denys Vlasenkocd716832009-11-28 22:14:02 +01005908 unsigned char c = *p++;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005909 if (c) {
Denys Vlasenko2fe66b12016-12-12 17:39:12 +01005910 if (quotes & QUOTES_ESC) {
5911 int n = SIT(c, syntax);
5912 if (n == CCTL
5913 || (((quotes & EXP_FULL) || syntax != BASESYNTAX)
5914 && n == CBACK
5915 )
5916 ) {
5917 USTPUTC(CTLESC, q);
5918 }
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02005919 }
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005920 } else if (!(quotes & QUOTES_KEEPNUL))
5921 continue;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005922 USTPUTC(c, q);
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005923 } while (--len);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005924
5925 expdest = q;
5926}
5927
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005928static size_t
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005929strtodest(const char *p, int syntax, int quotes)
5930{
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005931 size_t len = strlen(p);
5932 memtodest(p, len, syntax, quotes);
5933 return len;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005934}
5935
5936/*
5937 * Record the fact that we have to scan this region of the
5938 * string for IFS characters.
5939 */
5940static void
5941recordregion(int start, int end, int nulonly)
5942{
5943 struct ifsregion *ifsp;
5944
5945 if (ifslastp == NULL) {
5946 ifsp = &ifsfirst;
5947 } else {
5948 INT_OFF;
Denis Vlasenko597906c2008-02-20 16:38:54 +00005949 ifsp = ckzalloc(sizeof(*ifsp));
5950 /*ifsp->next = NULL; - ckzalloc did it */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005951 ifslastp->next = ifsp;
5952 INT_ON;
5953 }
5954 ifslastp = ifsp;
5955 ifslastp->begoff = start;
5956 ifslastp->endoff = end;
5957 ifslastp->nulonly = nulonly;
5958}
5959
5960static void
5961removerecordregions(int endoff)
5962{
5963 if (ifslastp == NULL)
5964 return;
5965
5966 if (ifsfirst.endoff > endoff) {
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02005967 while (ifsfirst.next) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005968 struct ifsregion *ifsp;
5969 INT_OFF;
5970 ifsp = ifsfirst.next->next;
5971 free(ifsfirst.next);
5972 ifsfirst.next = ifsp;
5973 INT_ON;
5974 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02005975 if (ifsfirst.begoff > endoff) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005976 ifslastp = NULL;
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02005977 } else {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005978 ifslastp = &ifsfirst;
5979 ifsfirst.endoff = endoff;
5980 }
5981 return;
5982 }
5983
5984 ifslastp = &ifsfirst;
5985 while (ifslastp->next && ifslastp->next->begoff < endoff)
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02005986 ifslastp = ifslastp->next;
5987 while (ifslastp->next) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005988 struct ifsregion *ifsp;
5989 INT_OFF;
5990 ifsp = ifslastp->next->next;
5991 free(ifslastp->next);
5992 ifslastp->next = ifsp;
5993 INT_ON;
5994 }
5995 if (ifslastp->endoff > endoff)
5996 ifslastp->endoff = endoff;
5997}
5998
5999static char *
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006000exptilde(char *startp, char *p, int flags)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006001{
Denys Vlasenkocd716832009-11-28 22:14:02 +01006002 unsigned char c;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006003 char *name;
6004 struct passwd *pw;
6005 const char *home;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006006 int quotes = flags & QUOTES_ESC;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006007
6008 name = p + 1;
6009
6010 while ((c = *++p) != '\0') {
6011 switch (c) {
6012 case CTLESC:
6013 return startp;
6014 case CTLQUOTEMARK:
6015 return startp;
6016 case ':':
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006017 if (flags & EXP_VARTILDE)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006018 goto done;
6019 break;
6020 case '/':
6021 case CTLENDVAR:
6022 goto done;
6023 }
6024 }
6025 done:
6026 *p = '\0';
6027 if (*name == '\0') {
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02006028 home = lookupvar("HOME");
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006029 } else {
6030 pw = getpwnam(name);
6031 if (pw == NULL)
6032 goto lose;
6033 home = pw->pw_dir;
6034 }
6035 if (!home || !*home)
6036 goto lose;
6037 *p = c;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006038 strtodest(home, SQSYNTAX, quotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006039 return p;
6040 lose:
6041 *p = c;
6042 return startp;
6043}
6044
6045/*
6046 * Execute a command inside back quotes. If it's a builtin command, we
6047 * want to save its output in a block obtained from malloc. Otherwise
6048 * we fork off a subprocess and get the output of the command via a pipe.
6049 * Should be called with interrupts off.
6050 */
6051struct backcmd { /* result of evalbackcmd */
6052 int fd; /* file descriptor to read from */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006053 int nleft; /* number of chars in buffer */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00006054 char *buf; /* buffer */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006055 struct job *jp; /* job structure for command */
6056};
6057
6058/* These forward decls are needed to use "eval" code for backticks handling: */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006059#define EV_EXIT 01 /* exit after evaluating tree */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02006060static int evaltree(union node *, int);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006061
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02006062static void FAST_FUNC
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006063evalbackcmd(union node *n, struct backcmd *result)
6064{
Denys Vlasenko579ad102016-10-25 21:10:20 +02006065 int pip[2];
6066 struct job *jp;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006067
6068 result->fd = -1;
6069 result->buf = NULL;
6070 result->nleft = 0;
6071 result->jp = NULL;
Denys Vlasenko579ad102016-10-25 21:10:20 +02006072 if (n == NULL) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006073 goto out;
Denys Vlasenko579ad102016-10-25 21:10:20 +02006074 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006075
Denys Vlasenko579ad102016-10-25 21:10:20 +02006076 if (pipe(pip) < 0)
6077 ash_msg_and_raise_error("pipe call failed");
6078 jp = makejob(/*n,*/ 1);
6079 if (forkshell(jp, n, FORK_NOJOB) == 0) {
Denys Vlasenko70392332016-10-27 02:31:55 +02006080 /* child */
Denys Vlasenko579ad102016-10-25 21:10:20 +02006081 FORCE_INT_ON;
6082 close(pip[0]);
6083 if (pip[1] != 1) {
6084 /*close(1);*/
Denys Vlasenko64774602016-10-26 15:24:30 +02006085 dup2_or_raise(pip[1], 1);
Denys Vlasenko579ad102016-10-25 21:10:20 +02006086 close(pip[1]);
6087 }
Denys Vlasenko960ca382016-10-25 18:12:15 +02006088/* TODO: eflag clearing makes the following not abort:
6089 * ash -c 'set -e; z=$(false;echo foo); echo $z'
6090 * which is what bash does (unless it is in POSIX mode).
6091 * dash deleted "eflag = 0" line in the commit
6092 * Date: Mon, 28 Jun 2010 17:11:58 +1000
6093 * [EVAL] Don't clear eflag in evalbackcmd
6094 * For now, preserve bash-like behavior, it seems to be somewhat more useful:
6095 */
Denys Vlasenko579ad102016-10-25 21:10:20 +02006096 eflag = 0;
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02006097 ifsfree();
Denys Vlasenko579ad102016-10-25 21:10:20 +02006098 evaltree(n, EV_EXIT); /* actually evaltreenr... */
6099 /* NOTREACHED */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006100 }
Denys Vlasenko70392332016-10-27 02:31:55 +02006101 /* parent */
Denys Vlasenko579ad102016-10-25 21:10:20 +02006102 close(pip[1]);
6103 result->fd = pip[0];
6104 result->jp = jp;
6105
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006106 out:
6107 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
6108 result->fd, result->buf, result->nleft, result->jp));
6109}
6110
6111/*
6112 * Expand stuff in backwards quotes.
6113 */
6114static void
Ron Yorston549deab2015-05-18 09:57:51 +02006115expbackq(union node *cmd, int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006116{
6117 struct backcmd in;
6118 int i;
6119 char buf[128];
6120 char *p;
6121 char *dest;
6122 int startloc;
Ron Yorston549deab2015-05-18 09:57:51 +02006123 int syntax = flag & EXP_QUOTED ? DQSYNTAX : BASESYNTAX;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006124 struct stackmark smark;
6125
6126 INT_OFF;
Denys Vlasenko60ca8342016-09-30 11:21:21 +02006127 startloc = expdest - (char *)stackblock();
6128 pushstackmark(&smark, startloc);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006129 evalbackcmd(cmd, &in);
6130 popstackmark(&smark);
6131
6132 p = in.buf;
6133 i = in.nleft;
6134 if (i == 0)
6135 goto read;
6136 for (;;) {
Ron Yorston549deab2015-05-18 09:57:51 +02006137 memtodest(p, i, syntax, flag & QUOTES_ESC);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006138 read:
6139 if (in.fd < 0)
6140 break;
Ron Yorston61d6ae22015-04-19 10:50:25 +01006141 i = nonblock_immune_read(in.fd, buf, sizeof(buf));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006142 TRACE(("expbackq: read returns %d\n", i));
6143 if (i <= 0)
6144 break;
6145 p = buf;
6146 }
6147
Denis Vlasenko60818682007-09-28 22:07:23 +00006148 free(in.buf);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006149 if (in.fd >= 0) {
6150 close(in.fd);
6151 back_exitstatus = waitforjob(in.jp);
6152 }
6153 INT_ON;
6154
6155 /* Eat all trailing newlines */
6156 dest = expdest;
6157 for (; dest > (char *)stackblock() && dest[-1] == '\n';)
6158 STUNPUTC(dest);
6159 expdest = dest;
6160
Ron Yorston549deab2015-05-18 09:57:51 +02006161 if (!(flag & EXP_QUOTED))
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006162 recordregion(startloc, dest - (char *)stackblock(), 0);
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006163 TRACE(("evalbackq: size:%d:'%.*s'\n",
6164 (int)((dest - (char *)stackblock()) - startloc),
6165 (int)((dest - (char *)stackblock()) - startloc),
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006166 stackblock() + startloc));
6167}
6168
Denys Vlasenko0b883582016-12-23 16:49:07 +01006169#if ENABLE_FEATURE_SH_MATH
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006170/*
6171 * Expand arithmetic expression. Backup to start of expression,
6172 * evaluate, place result in (backed up) result, adjust string position.
6173 */
6174static void
Ron Yorston549deab2015-05-18 09:57:51 +02006175expari(int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006176{
6177 char *p, *start;
6178 int begoff;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006179 int len;
6180
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006181 /* ifsfree(); */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006182
6183 /*
6184 * This routine is slightly over-complicated for
6185 * efficiency. Next we scan backwards looking for the
6186 * start of arithmetic.
6187 */
6188 start = stackblock();
6189 p = expdest - 1;
6190 *p = '\0';
6191 p--;
Denys Vlasenko940c7202011-03-02 04:07:14 +01006192 while (1) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006193 int esc;
6194
Denys Vlasenkocd716832009-11-28 22:14:02 +01006195 while ((unsigned char)*p != CTLARI) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006196 p--;
6197#if DEBUG
6198 if (p < start) {
6199 ash_msg_and_raise_error("missing CTLARI (shouldn't happen)");
6200 }
6201#endif
6202 }
6203
6204 esc = esclen(start, p);
6205 if (!(esc % 2)) {
6206 break;
6207 }
6208
6209 p -= esc + 1;
Denys Vlasenko940c7202011-03-02 04:07:14 +01006210 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006211
6212 begoff = p - start;
6213
6214 removerecordregions(begoff);
6215
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006216 expdest = p;
6217
Ron Yorston549deab2015-05-18 09:57:51 +02006218 if (flag & QUOTES_ESC)
6219 rmescapes(p + 1, 0);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006220
Ron Yorston549deab2015-05-18 09:57:51 +02006221 len = cvtnum(ash_arith(p + 1));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006222
Ron Yorston549deab2015-05-18 09:57:51 +02006223 if (!(flag & EXP_QUOTED))
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006224 recordregion(begoff, begoff + len, 0);
6225}
6226#endif
6227
6228/* argstr needs it */
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006229static char *evalvar(char *p, int flags, struct strlist *var_str_list);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006230
6231/*
6232 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
6233 * characters to allow for further processing. Otherwise treat
6234 * $@ like $* since no splitting will be performed.
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006235 *
6236 * var_str_list (can be NULL) is a list of "VAR=val" strings which take precedence
6237 * over shell varables. Needed for "A=a B=$A; echo $B" case - we use it
6238 * for correct expansion of "B=$A" word.
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006239 */
6240static void
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006241argstr(char *p, int flags, struct strlist *var_str_list)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006242{
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00006243 static const char spclchars[] ALIGN1 = {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006244 '=',
6245 ':',
6246 CTLQUOTEMARK,
6247 CTLENDVAR,
6248 CTLESC,
6249 CTLVAR,
6250 CTLBACKQ,
Denys Vlasenko0b883582016-12-23 16:49:07 +01006251#if ENABLE_FEATURE_SH_MATH
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006252 CTLENDARI,
6253#endif
Denys Vlasenkocd716832009-11-28 22:14:02 +01006254 '\0'
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006255 };
6256 const char *reject = spclchars;
Ron Yorston3df47f92015-05-18 09:53:26 +02006257 int breakall = (flags & (EXP_WORD | EXP_QUOTED)) == EXP_WORD;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006258 int inquotes;
6259 size_t length;
6260 int startloc;
6261
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006262 if (!(flags & EXP_VARTILDE)) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006263 reject += 2;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006264 } else if (flags & EXP_VARTILDE2) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006265 reject++;
6266 }
6267 inquotes = 0;
6268 length = 0;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006269 if (flags & EXP_TILDE) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006270 char *q;
6271
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006272 flags &= ~EXP_TILDE;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006273 tilde:
6274 q = p;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006275 if (*q == '~')
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006276 p = exptilde(p, q, flags);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006277 }
6278 start:
6279 startloc = expdest - (char *)stackblock();
6280 for (;;) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006281 unsigned char c;
6282
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006283 length += strcspn(p + length, reject);
Denys Vlasenkocd716832009-11-28 22:14:02 +01006284 c = p[length];
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006285 if (c) {
6286 if (!(c & 0x80)
Denys Vlasenko0b883582016-12-23 16:49:07 +01006287 IF_FEATURE_SH_MATH(|| c == CTLENDARI)
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006288 ) {
6289 /* c == '=' || c == ':' || c == CTLENDARI */
6290 length++;
6291 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006292 }
6293 if (length > 0) {
6294 int newloc;
6295 expdest = stack_nputstr(p, length, expdest);
6296 newloc = expdest - (char *)stackblock();
6297 if (breakall && !inquotes && newloc > startloc) {
6298 recordregion(startloc, newloc, 0);
6299 }
6300 startloc = newloc;
6301 }
6302 p += length + 1;
6303 length = 0;
6304
6305 switch (c) {
6306 case '\0':
6307 goto breakloop;
6308 case '=':
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006309 if (flags & EXP_VARTILDE2) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006310 p--;
6311 continue;
6312 }
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006313 flags |= EXP_VARTILDE2;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006314 reject++;
6315 /* fall through */
6316 case ':':
6317 /*
6318 * sort of a hack - expand tildes in variable
6319 * assignments (after the first '=' and after ':'s).
6320 */
6321 if (*--p == '~') {
6322 goto tilde;
6323 }
6324 continue;
6325 }
6326
6327 switch (c) {
6328 case CTLENDVAR: /* ??? */
6329 goto breakloop;
6330 case CTLQUOTEMARK:
Ron Yorston549deab2015-05-18 09:57:51 +02006331 inquotes ^= EXP_QUOTED;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006332 /* "$@" syntax adherence hack */
Ron Yorston549deab2015-05-18 09:57:51 +02006333 if (inquotes && !memcmp(p, dolatstr + 1, DOLATSTRLEN - 1)) {
6334 p = evalvar(p + 1, flags | inquotes, /* var_str_list: */ NULL) + 1;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006335 goto start;
6336 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006337 addquote:
Ron Yorston549deab2015-05-18 09:57:51 +02006338 if (flags & QUOTES_ESC) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006339 p--;
6340 length++;
6341 startloc++;
6342 }
6343 break;
6344 case CTLESC:
6345 startloc++;
6346 length++;
Ron Yorston549deab2015-05-18 09:57:51 +02006347
6348 /*
6349 * Quoted parameter expansion pattern: remove quote
6350 * unless inside inner quotes or we have a literal
6351 * backslash.
6352 */
6353 if (((flags | inquotes) & (EXP_QPAT | EXP_QUOTED)) ==
6354 EXP_QPAT && *p != '\\')
6355 break;
6356
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006357 goto addquote;
6358 case CTLVAR:
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02006359 TRACE(("argstr: evalvar('%s')\n", p));
Ron Yorston549deab2015-05-18 09:57:51 +02006360 p = evalvar(p, flags | inquotes, var_str_list);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02006361 TRACE(("argstr: evalvar:'%s'\n", (char *)stackblock()));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006362 goto start;
6363 case CTLBACKQ:
Ron Yorston549deab2015-05-18 09:57:51 +02006364 expbackq(argbackq->n, flags | inquotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006365 argbackq = argbackq->next;
6366 goto start;
Denys Vlasenko0b883582016-12-23 16:49:07 +01006367#if ENABLE_FEATURE_SH_MATH
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006368 case CTLENDARI:
6369 p--;
Ron Yorston549deab2015-05-18 09:57:51 +02006370 expari(flags | inquotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006371 goto start;
6372#endif
6373 }
6374 }
Denys Vlasenko958581a2010-09-12 15:04:27 +02006375 breakloop: ;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006376}
6377
6378static char *
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006379scanleft(char *startp, char *rmesc, char *rmescend UNUSED_PARAM,
6380 char *pattern, int quotes, int zero)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006381{
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006382 char *loc, *loc2;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006383 char c;
6384
6385 loc = startp;
6386 loc2 = rmesc;
6387 do {
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006388 int match;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006389 const char *s = loc2;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006390
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006391 c = *loc2;
6392 if (zero) {
6393 *loc2 = '\0';
6394 s = rmesc;
6395 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006396 match = pmatch(pattern, s);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006397
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006398 *loc2 = c;
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006399 if (match)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006400 return loc;
Denys Vlasenkocd716832009-11-28 22:14:02 +01006401 if (quotes && (unsigned char)*loc == CTLESC)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006402 loc++;
6403 loc++;
6404 loc2++;
6405 } while (c);
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006406 return NULL;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006407}
6408
6409static char *
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006410scanright(char *startp, char *rmesc, char *rmescend,
6411 char *pattern, int quotes, int match_at_start)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006412{
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006413#if !ENABLE_ASH_OPTIMIZE_FOR_SIZE
6414 int try2optimize = match_at_start;
6415#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006416 int esc = 0;
6417 char *loc;
6418 char *loc2;
6419
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006420 /* If we called by "${v/pattern/repl}" or "${v//pattern/repl}":
6421 * startp="escaped_value_of_v" rmesc="raw_value_of_v"
6422 * rmescend=""(ptr to NUL in rmesc) pattern="pattern" quotes=match_at_start=1
6423 * Logic:
6424 * loc starts at NUL at the end of startp, loc2 starts at the end of rmesc,
6425 * and on each iteration they go back two/one char until they reach the beginning.
6426 * We try to find a match in "raw_value_of_v", "raw_value_of_", "raw_value_of" etc.
6427 */
6428 /* TODO: document in what other circumstances we are called. */
6429
6430 for (loc = pattern - 1, loc2 = rmescend; loc >= startp; loc2--) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006431 int match;
6432 char c = *loc2;
6433 const char *s = loc2;
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006434 if (match_at_start) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006435 *loc2 = '\0';
6436 s = rmesc;
6437 }
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006438 match = pmatch(pattern, s);
6439 //bb_error_msg("pmatch(pattern:'%s',s:'%s'):%d", pattern, s, match);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006440 *loc2 = c;
6441 if (match)
6442 return loc;
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006443#if !ENABLE_ASH_OPTIMIZE_FOR_SIZE
6444 if (try2optimize) {
6445 /* Maybe we can optimize this:
6446 * if pattern ends with unescaped *, we can avoid checking
6447 * shorter strings: if "foo*" doesnt match "raw_value_of_v",
6448 * it wont match truncated "raw_value_of_" strings too.
6449 */
6450 unsigned plen = strlen(pattern);
6451 /* Does it end with "*"? */
6452 if (plen != 0 && pattern[--plen] == '*') {
6453 /* "xxxx*" is not escaped */
6454 /* "xxx\*" is escaped */
6455 /* "xx\\*" is not escaped */
6456 /* "x\\\*" is escaped */
6457 int slashes = 0;
6458 while (plen != 0 && pattern[--plen] == '\\')
6459 slashes++;
6460 if (!(slashes & 1))
6461 break; /* ends with unescaped "*" */
6462 }
6463 try2optimize = 0;
6464 }
6465#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006466 loc--;
6467 if (quotes) {
6468 if (--esc < 0) {
6469 esc = esclen(startp, loc);
6470 }
6471 if (esc % 2) {
6472 esc--;
6473 loc--;
6474 }
6475 }
6476 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006477 return NULL;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006478}
6479
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00006480static void varunset(const char *, const char *, const char *, int) NORETURN;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006481static void
6482varunset(const char *end, const char *var, const char *umsg, int varflags)
6483{
6484 const char *msg;
6485 const char *tail;
6486
6487 tail = nullstr;
6488 msg = "parameter not set";
6489 if (umsg) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006490 if ((unsigned char)*end == CTLENDVAR) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006491 if (varflags & VSNUL)
6492 tail = " or null";
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006493 } else {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006494 msg = umsg;
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006495 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006496 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006497 ash_msg_and_raise_error("%.*s: %s%s", (int)(end - var - 1), var, msg, tail);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006498}
6499
6500static const char *
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006501subevalvar(char *p, char *varname, int strloc, int subtype,
Ron Yorston549deab2015-05-18 09:57:51 +02006502 int startloc, int varflags, int flag, struct strlist *var_str_list)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006503{
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006504 struct nodelist *saveargbackq = argbackq;
Ron Yorston549deab2015-05-18 09:57:51 +02006505 int quotes = flag & QUOTES_ESC;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006506 char *startp;
6507 char *loc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006508 char *rmesc, *rmescend;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006509 char *str;
Ron Yorston417622c2015-05-18 09:59:14 +02006510 IF_ASH_BASH_COMPAT(char *repl = NULL;)
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00006511 IF_ASH_BASH_COMPAT(int pos, len, orig_len;)
Denys Vlasenko0b4980c2012-09-25 12:49:29 +02006512 int amount, resetloc;
6513 IF_ASH_BASH_COMPAT(int workloc;)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006514 int zero;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006515 char *(*scan)(char*, char*, char*, char*, int, int);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006516
Denys Vlasenko6040fe82010-09-12 15:03:16 +02006517 //bb_error_msg("subevalvar(p:'%s',varname:'%s',strloc:%d,subtype:%d,startloc:%d,varflags:%x,quotes:%d)",
6518 // p, varname, strloc, subtype, startloc, varflags, quotes);
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006519
Ron Yorstoneb6b48b2015-05-18 09:51:35 +02006520 argstr(p, EXP_TILDE | (subtype != VSASSIGN && subtype != VSQUESTION ?
Ron Yorston549deab2015-05-18 09:57:51 +02006521 (flag & (EXP_QUOTED | EXP_QPAT) ? EXP_QPAT : EXP_CASE) : 0),
6522 var_str_list);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006523 STPUTC('\0', expdest);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006524 argbackq = saveargbackq;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006525 startp = (char *)stackblock() + startloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006526
6527 switch (subtype) {
6528 case VSASSIGN:
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02006529 setvar0(varname, startp);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006530 amount = startp - expdest;
6531 STADJUST(amount, expdest);
6532 return startp;
6533
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006534 case VSQUESTION:
6535 varunset(p, varname, startp, varflags);
6536 /* NOTREACHED */
6537
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006538#if ENABLE_ASH_BASH_COMPAT
6539 case VSSUBSTR:
Denys Vlasenkof8ddbe12016-07-25 03:56:00 +02006540//TODO: support more general format ${v:EXPR:EXPR},
6541// where EXPR follows $(()) rules
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006542 loc = str = stackblock() + strloc;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006543 /* Read POS in ${var:POS:LEN} */
6544 pos = atoi(loc); /* number(loc) errors out on "1:4" */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006545 len = str - startp - 1;
6546
6547 /* *loc != '\0', guaranteed by parser */
6548 if (quotes) {
6549 char *ptr;
6550
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006551 /* Adjust the length by the number of escapes */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006552 for (ptr = startp; ptr < (str - 1); ptr++) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006553 if ((unsigned char)*ptr == CTLESC) {
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006554 len--;
6555 ptr++;
6556 }
6557 }
6558 }
6559 orig_len = len;
6560
6561 if (*loc++ == ':') {
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006562 /* ${var::LEN} */
6563 len = number(loc);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006564 } else {
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006565 /* Skip POS in ${var:POS:LEN} */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006566 len = orig_len;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006567 while (*loc && *loc != ':') {
6568 /* TODO?
6569 * bash complains on: var=qwe; echo ${var:1a:123}
6570 if (!isdigit(*loc))
6571 ash_msg_and_raise_error(msg_illnum, str);
6572 */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006573 loc++;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006574 }
6575 if (*loc++ == ':') {
6576 len = number(loc);
6577 }
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006578 }
Denys Vlasenko08a5dab2014-11-17 20:27:18 +01006579 if (pos < 0) {
6580 /* ${VAR:$((-n)):l} starts n chars from the end */
6581 pos = orig_len + pos;
6582 }
6583 if ((unsigned)pos >= orig_len) {
6584 /* apart from obvious ${VAR:999999:l},
6585 * covers ${VAR:$((-9999999)):l} - result is ""
6586 * (bash-compat)
6587 */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006588 pos = 0;
6589 len = 0;
6590 }
6591 if (len > (orig_len - pos))
6592 len = orig_len - pos;
6593
6594 for (str = startp; pos; str++, pos--) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006595 if (quotes && (unsigned char)*str == CTLESC)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006596 str++;
6597 }
6598 for (loc = startp; len; len--) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006599 if (quotes && (unsigned char)*str == CTLESC)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006600 *loc++ = *str++;
6601 *loc++ = *str++;
6602 }
6603 *loc = '\0';
6604 amount = loc - expdest;
6605 STADJUST(amount, expdest);
6606 return loc;
6607#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006608 }
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006609
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006610 resetloc = expdest - (char *)stackblock();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006611
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006612 /* We'll comeback here if we grow the stack while handling
6613 * a VSREPLACE or VSREPLACEALL, since our pointers into the
6614 * stack will need rebasing, and we'll need to remove our work
6615 * areas each time
6616 */
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00006617 IF_ASH_BASH_COMPAT(restart:)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006618
6619 amount = expdest - ((char *)stackblock() + resetloc);
6620 STADJUST(-amount, expdest);
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006621 startp = (char *)stackblock() + startloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006622
6623 rmesc = startp;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006624 rmescend = (char *)stackblock() + strloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006625 if (quotes) {
Denys Vlasenkob6c84342009-08-29 20:23:20 +02006626 rmesc = rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006627 if (rmesc != startp) {
6628 rmescend = expdest;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006629 startp = (char *)stackblock() + startloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006630 }
6631 }
6632 rmescend--;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006633 str = (char *)stackblock() + strloc;
Ron Yorston417622c2015-05-18 09:59:14 +02006634 /*
6635 * Example: v='a\bc'; echo ${v/\\b/_\\_\z_}
6636 * The result is a_\_z_c (not a\_\_z_c)!
6637 *
6638 * The search pattern and replace string treat backslashes differently!
6639 * RMESCAPE_SLASH causes preglob to work differently on the pattern
6640 * and string. It's only used on the first call.
6641 */
6642 preglob(str, IF_ASH_BASH_COMPAT(
6643 (subtype == VSREPLACE || subtype == VSREPLACEALL) && !repl ?
6644 RMESCAPE_SLASH :) 0);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006645
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006646#if ENABLE_ASH_BASH_COMPAT
Denys Vlasenko0b4980c2012-09-25 12:49:29 +02006647 workloc = expdest - (char *)stackblock();
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006648 if (subtype == VSREPLACE || subtype == VSREPLACEALL) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006649 char *idx, *end;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006650
Denis Vlasenkod6855d12008-09-27 14:03:25 +00006651 if (!repl) {
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02006652 repl = strchr(str, CTLESC);
6653 if (repl)
Ron Yorston417622c2015-05-18 09:59:14 +02006654 *repl++ = '\0';
6655 else
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006656 repl = nullstr;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006657 }
Ron Yorston417622c2015-05-18 09:59:14 +02006658 //bb_error_msg("str:'%s' repl:'%s'", str, repl);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006659
6660 /* If there's no pattern to match, return the expansion unmolested */
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006661 if (str[0] == '\0')
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006662 return NULL;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006663
6664 len = 0;
6665 idx = startp;
6666 end = str - 1;
6667 while (idx < end) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006668 try_to_match:
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006669 loc = scanright(idx, rmesc, rmescend, str, quotes, 1);
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006670 //bb_error_msg("scanright('%s'):'%s'", str, loc);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006671 if (!loc) {
6672 /* No match, advance */
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006673 char *restart_detect = stackblock();
6674 skip_matching:
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006675 STPUTC(*idx, expdest);
Denys Vlasenkocd716832009-11-28 22:14:02 +01006676 if (quotes && (unsigned char)*idx == CTLESC) {
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006677 idx++;
6678 len++;
6679 STPUTC(*idx, expdest);
6680 }
6681 if (stackblock() != restart_detect)
6682 goto restart;
6683 idx++;
6684 len++;
6685 rmesc++;
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006686 /* continue; - prone to quadratic behavior, smarter code: */
6687 if (idx >= end)
6688 break;
6689 if (str[0] == '*') {
6690 /* Pattern is "*foo". If "*foo" does not match "long_string",
6691 * it would never match "ong_string" etc, no point in trying.
6692 */
6693 goto skip_matching;
6694 }
6695 goto try_to_match;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006696 }
6697
6698 if (subtype == VSREPLACEALL) {
6699 while (idx < loc) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006700 if (quotes && (unsigned char)*idx == CTLESC)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006701 idx++;
6702 idx++;
6703 rmesc++;
6704 }
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006705 } else {
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006706 idx = loc;
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006707 }
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006708
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006709 //bb_error_msg("repl:'%s'", repl);
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006710 for (loc = (char*)repl; *loc; loc++) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006711 char *restart_detect = stackblock();
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006712 if (quotes && *loc == '\\') {
6713 STPUTC(CTLESC, expdest);
6714 len++;
6715 }
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006716 STPUTC(*loc, expdest);
6717 if (stackblock() != restart_detect)
6718 goto restart;
6719 len++;
6720 }
6721
6722 if (subtype == VSREPLACE) {
Denys Vlasenkof02c82f2010-08-06 19:14:47 +02006723 //bb_error_msg("tail:'%s', quotes:%x", idx, quotes);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006724 while (*idx) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006725 char *restart_detect = stackblock();
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006726 STPUTC(*idx, expdest);
6727 if (stackblock() != restart_detect)
6728 goto restart;
6729 len++;
6730 idx++;
6731 }
6732 break;
6733 }
6734 }
6735
6736 /* We've put the replaced text into a buffer at workloc, now
6737 * move it to the right place and adjust the stack.
6738 */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006739 STPUTC('\0', expdest);
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006740 startp = (char *)stackblock() + startloc;
6741 memmove(startp, (char *)stackblock() + workloc, len + 1);
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006742 //bb_error_msg("startp:'%s'", startp);
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006743 amount = expdest - (startp + len);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006744 STADJUST(-amount, expdest);
6745 return startp;
6746 }
6747#endif /* ENABLE_ASH_BASH_COMPAT */
6748
6749 subtype -= VSTRIMRIGHT;
6750#if DEBUG
6751 if (subtype < 0 || subtype > 7)
6752 abort();
6753#endif
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006754 /* zero = (subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX) */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006755 zero = subtype >> 1;
6756 /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */
6757 scan = (subtype & 1) ^ zero ? scanleft : scanright;
6758
6759 loc = scan(startp, rmesc, rmescend, str, quotes, zero);
6760 if (loc) {
6761 if (zero) {
6762 memmove(startp, loc, str - loc);
6763 loc = startp + (str - loc) - 1;
6764 }
6765 *loc = '\0';
6766 amount = loc - expdest;
6767 STADJUST(amount, expdest);
6768 }
6769 return loc;
6770}
6771
6772/*
6773 * Add the value of a specialized variable to the stack string.
Denys Vlasenko4d8873f2009-10-04 03:14:41 +02006774 * name parameter (examples):
6775 * ash -c 'echo $1' name:'1='
6776 * ash -c 'echo $qwe' name:'qwe='
6777 * ash -c 'echo $$' name:'$='
6778 * ash -c 'echo ${$}' name:'$='
6779 * ash -c 'echo ${$##q}' name:'$=q'
6780 * ash -c 'echo ${#$}' name:'$='
6781 * note: examples with bad shell syntax:
6782 * ash -c 'echo ${#$1}' name:'$=1'
6783 * ash -c 'echo ${#1#}' name:'1=#'
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006784 */
Denys Vlasenkoadf922e2009-10-08 14:35:37 +02006785static NOINLINE ssize_t
Denys Vlasenko0dd8e452016-10-01 21:02:06 +02006786varvalue(char *name, int varflags, int flags, struct strlist *var_str_list, int *quotedp)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006787{
Mike Frysinger98c52642009-04-02 10:02:37 +00006788 const char *p;
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006789 int num;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006790 int i;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006791 ssize_t len = 0;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006792 int sep;
Denys Vlasenko0dd8e452016-10-01 21:02:06 +02006793 int quoted = *quotedp;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006794 int subtype = varflags & VSTYPE;
6795 int discard = subtype == VSPLUS || subtype == VSLENGTH;
6796 int quotes = (discard ? 0 : (flags & QUOTES_ESC)) | QUOTES_KEEPNUL;
Denys Vlasenko0aaaa502016-10-02 02:46:56 +02006797 int syntax;
6798
6799 sep = (flags & EXP_FULL) << CHAR_BIT;
6800 syntax = quoted ? DQSYNTAX : BASESYNTAX;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006801
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006802 switch (*name) {
6803 case '$':
6804 num = rootpid;
6805 goto numvar;
6806 case '?':
6807 num = exitstatus;
6808 goto numvar;
6809 case '#':
6810 num = shellparam.nparam;
6811 goto numvar;
6812 case '!':
6813 num = backgndpid;
6814 if (num == 0)
6815 return -1;
6816 numvar:
6817 len = cvtnum(num);
Denys Vlasenko4d8873f2009-10-04 03:14:41 +02006818 goto check_1char_name;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006819 case '-':
Mike Frysinger98c52642009-04-02 10:02:37 +00006820 expdest = makestrspace(NOPTS, expdest);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006821 for (i = NOPTS - 1; i >= 0; i--) {
6822 if (optlist[i]) {
Mike Frysinger98c52642009-04-02 10:02:37 +00006823 USTPUTC(optletters(i), expdest);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006824 len++;
6825 }
6826 }
Denys Vlasenko4d8873f2009-10-04 03:14:41 +02006827 check_1char_name:
6828#if 0
6829 /* handles cases similar to ${#$1} */
6830 if (name[2] != '\0')
6831 raise_error_syntax("bad substitution");
6832#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006833 break;
Denys Vlasenko0aaaa502016-10-02 02:46:56 +02006834 case '@':
6835 if (quoted && sep)
6836 goto param;
6837 /* fall through */
6838 case '*': {
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006839 char **ap;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006840 char sepc;
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006841
Denys Vlasenko0aaaa502016-10-02 02:46:56 +02006842 if (quoted)
6843 sep = 0;
6844 sep |= ifsset() ? ifsval()[0] : ' ';
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006845 param:
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006846 sepc = sep;
Denys Vlasenko0dd8e452016-10-01 21:02:06 +02006847 *quotedp = !sepc;
6848 ap = shellparam.p;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006849 if (!ap)
6850 return -1;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006851 while ((p = *ap++) != NULL) {
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006852 len += strtodest(p, syntax, quotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006853
6854 if (*ap && sep) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006855 len++;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006856 memtodest(&sepc, 1, syntax, quotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006857 }
6858 }
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006859 break;
Denys Vlasenko0aaaa502016-10-02 02:46:56 +02006860 } /* case '*' */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006861 case '0':
6862 case '1':
6863 case '2':
6864 case '3':
6865 case '4':
6866 case '5':
6867 case '6':
6868 case '7':
6869 case '8':
6870 case '9':
Denys Vlasenkoa00329c2009-08-30 20:05:10 +02006871 num = atoi(name); /* number(name) fails on ${N#str} etc */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006872 if (num < 0 || num > shellparam.nparam)
6873 return -1;
6874 p = num ? shellparam.p[num - 1] : arg0;
6875 goto value;
6876 default:
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006877 /* NB: name has form "VAR=..." */
6878
6879 /* "A=a B=$A" case: var_str_list is a list of "A=a" strings
6880 * which should be considered before we check variables. */
6881 if (var_str_list) {
6882 unsigned name_len = (strchrnul(name, '=') - name) + 1;
6883 p = NULL;
6884 do {
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00006885 char *str, *eq;
6886 str = var_str_list->text;
6887 eq = strchr(str, '=');
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006888 if (!eq) /* stop at first non-assignment */
6889 break;
6890 eq++;
Denis Vlasenko6b06cb82008-05-15 21:30:45 +00006891 if (name_len == (unsigned)(eq - str)
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006892 && strncmp(str, name, name_len) == 0
6893 ) {
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006894 p = eq;
6895 /* goto value; - WRONG! */
6896 /* think "A=1 A=2 B=$A" */
6897 }
6898 var_str_list = var_str_list->next;
6899 } while (var_str_list);
6900 if (p)
6901 goto value;
6902 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006903 p = lookupvar(name);
6904 value:
6905 if (!p)
6906 return -1;
6907
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006908 len = strtodest(p, syntax, quotes);
Denys Vlasenkoc76236f2014-12-29 00:04:18 +01006909#if ENABLE_UNICODE_SUPPORT
6910 if (subtype == VSLENGTH && len > 0) {
6911 reinit_unicode_for_ash();
6912 if (unicode_status == UNICODE_ON) {
Ron Yorston3e3bfb82016-03-18 11:29:19 +00006913 STADJUST(-len, expdest);
6914 discard = 0;
Denys Vlasenkoc76236f2014-12-29 00:04:18 +01006915 len = unicode_strlen(p);
6916 }
6917 }
6918#endif
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006919 break;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006920 }
6921
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006922 if (discard)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006923 STADJUST(-len, expdest);
6924 return len;
6925}
6926
6927/*
6928 * Expand a variable, and return a pointer to the next character in the
6929 * input string.
6930 */
6931static char *
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02006932evalvar(char *p, int flag, struct strlist *var_str_list)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006933{
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006934 char varflags;
6935 char subtype;
Ron Yorston549deab2015-05-18 09:57:51 +02006936 int quoted;
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006937 char easy;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006938 char *var;
6939 int patloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006940 int startloc;
6941 ssize_t varlen;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006942
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006943 varflags = (unsigned char) *p++;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006944 subtype = varflags & VSTYPE;
Denys Vlasenko88e15702016-10-26 01:55:56 +02006945
6946 if (!subtype)
6947 raise_error_syntax("bad substitution");
6948
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02006949 quoted = flag & EXP_QUOTED;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006950 var = p;
6951 easy = (!quoted || (*var == '@' && shellparam.nparam));
6952 startloc = expdest - (char *)stackblock();
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02006953 p = strchr(p, '=') + 1; //TODO: use var_end(p)?
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006954
6955 again:
Denys Vlasenko0dd8e452016-10-01 21:02:06 +02006956 varlen = varvalue(var, varflags, flag, var_str_list, &quoted);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006957 if (varflags & VSNUL)
6958 varlen--;
6959
6960 if (subtype == VSPLUS) {
6961 varlen = -1 - varlen;
6962 goto vsplus;
6963 }
6964
6965 if (subtype == VSMINUS) {
6966 vsplus:
6967 if (varlen < 0) {
6968 argstr(
Denys Vlasenko6040fe82010-09-12 15:03:16 +02006969 p,
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02006970 flag | EXP_TILDE | EXP_WORD,
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006971 var_str_list
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006972 );
6973 goto end;
6974 }
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02006975 goto record;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006976 }
6977
6978 if (subtype == VSASSIGN || subtype == VSQUESTION) {
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02006979 if (varlen >= 0)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006980 goto record;
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02006981
6982 subevalvar(p, var, 0, subtype, startloc, varflags,
6983 flag & ~QUOTES_ESC, var_str_list);
6984 varflags &= ~VSNUL;
6985 /*
6986 * Remove any recorded regions beyond
6987 * start of variable
6988 */
6989 removerecordregions(startloc);
6990 goto again;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006991 }
6992
6993 if (varlen < 0 && uflag)
6994 varunset(p, var, 0, 0);
6995
6996 if (subtype == VSLENGTH) {
Denys Vlasenkoc76236f2014-12-29 00:04:18 +01006997 cvtnum(varlen > 0 ? varlen : 0);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006998 goto record;
6999 }
7000
7001 if (subtype == VSNORMAL) {
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007002 record:
7003 if (!easy)
7004 goto end;
Denys Vlasenko0dd8e452016-10-01 21:02:06 +02007005 recordregion(startloc, expdest - (char *)stackblock(), quoted);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007006 goto end;
7007 }
7008
7009#if DEBUG
7010 switch (subtype) {
7011 case VSTRIMLEFT:
7012 case VSTRIMLEFTMAX:
7013 case VSTRIMRIGHT:
7014 case VSTRIMRIGHTMAX:
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007015#if ENABLE_ASH_BASH_COMPAT
7016 case VSSUBSTR:
7017 case VSREPLACE:
7018 case VSREPLACEALL:
7019#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007020 break;
7021 default:
7022 abort();
7023 }
7024#endif
7025
7026 if (varlen >= 0) {
7027 /*
7028 * Terminate the string and start recording the pattern
7029 * right after it
7030 */
7031 STPUTC('\0', expdest);
7032 patloc = expdest - (char *)stackblock();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02007033 if (NULL == subevalvar(p, /* varname: */ NULL, patloc, subtype,
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007034 startloc, varflags, flag, var_str_list)) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007035 int amount = expdest - (
7036 (char *)stackblock() + patloc - 1
7037 );
7038 STADJUST(-amount, expdest);
7039 }
7040 /* Remove any recorded regions beyond start of variable */
7041 removerecordregions(startloc);
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007042 goto record;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007043 }
7044
7045 end:
7046 if (subtype != VSNORMAL) { /* skip to end of alternative */
7047 int nesting = 1;
7048 for (;;) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01007049 unsigned char c = *p++;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007050 if (c == CTLESC)
7051 p++;
Ron Yorston549deab2015-05-18 09:57:51 +02007052 else if (c == CTLBACKQ) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007053 if (varlen >= 0)
7054 argbackq = argbackq->next;
7055 } else if (c == CTLVAR) {
7056 if ((*p++ & VSTYPE) != VSNORMAL)
7057 nesting++;
7058 } else if (c == CTLENDVAR) {
7059 if (--nesting == 0)
7060 break;
7061 }
7062 }
7063 }
7064 return p;
7065}
7066
7067/*
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007068 * Add a file name to the list.
7069 */
7070static void
7071addfname(const char *name)
7072{
7073 struct strlist *sp;
7074
Denis Vlasenko597906c2008-02-20 16:38:54 +00007075 sp = stzalloc(sizeof(*sp));
Denys Vlasenko8e2bc472016-09-28 23:02:57 +02007076 sp->text = sstrdup(name);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007077 *exparg.lastp = sp;
7078 exparg.lastp = &sp->next;
7079}
7080
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007081/* If we want to use glob() from libc... */
Denys Vlasenko514b51d2016-10-01 14:33:08 +02007082#if !ENABLE_ASH_INTERNAL_GLOB
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007083
7084/* Add the result of glob() to the list */
7085static void
7086addglob(const glob_t *pglob)
7087{
7088 char **p = pglob->gl_pathv;
7089
7090 do {
7091 addfname(*p);
7092 } while (*++p);
7093}
7094static void
7095expandmeta(struct strlist *str /*, int flag*/)
7096{
7097 /* TODO - EXP_REDIR */
7098
7099 while (str) {
7100 char *p;
7101 glob_t pglob;
7102 int i;
7103
7104 if (fflag)
7105 goto nometa;
Denys Vlasenkod4f3db92016-10-30 18:41:01 +01007106
7107 /* Avoid glob() (and thus, stat() et al) for words like "echo" */
7108 p = str->text;
7109 while (*p) {
7110 if (*p == '*')
7111 goto need_glob;
7112 if (*p == '?')
7113 goto need_glob;
7114 if (*p == '[')
7115 goto need_glob;
7116 p++;
7117 }
7118 goto nometa;
7119
7120 need_glob:
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007121 INT_OFF;
7122 p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP);
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007123// GLOB_NOMAGIC (GNU): if no *?[ chars in pattern, return it even if no match
7124// GLOB_NOCHECK: if no match, return unchanged pattern (sans \* escapes?)
7125//
7126// glibc 2.24.90 glob(GLOB_NOMAGIC) does not remove backslashes used for escaping:
7127// if you pass it "file\?", it returns "file\?", not "file?", if no match.
7128// Which means you need to unescape the string, right? Not so fast:
7129// if there _is_ a file named "file\?" (with backslash), it is returned
7130// as "file\?" too (whichever pattern you used to find it, say, "file*").
7131// You DONT KNOW by looking at the result whether you need to unescape it.
7132//
7133// Worse, globbing of "file\?" in a directory with two files, "file?" and "file\?",
7134// returns "file\?" - which is WRONG: "file\?" pattern matches "file?" file.
7135// Without GLOB_NOMAGIC, this works correctly ("file?" is returned as a match).
7136// With GLOB_NOMAGIC | GLOB_NOCHECK, this also works correctly.
7137// i = glob(p, GLOB_NOMAGIC | GLOB_NOCHECK, NULL, &pglob);
7138// i = glob(p, GLOB_NOMAGIC, NULL, &pglob);
7139 i = glob(p, 0, NULL, &pglob);
7140 //bb_error_msg("glob('%s'):%d '%s'...", p, i, pglob.gl_pathv ? pglob.gl_pathv[0] : "-");
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007141 if (p != str->text)
7142 free(p);
7143 switch (i) {
7144 case 0:
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007145#if 0 // glibc 2.24.90 bug? Patterns like "*/file", when match, don't set GLOB_MAGCHAR
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007146 /* GLOB_MAGCHAR is set if *?[ chars were seen (GNU) */
7147 if (!(pglob.gl_flags & GLOB_MAGCHAR))
7148 goto nometa2;
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007149#endif
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007150 addglob(&pglob);
7151 globfree(&pglob);
7152 INT_ON;
7153 break;
7154 case GLOB_NOMATCH:
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007155 //nometa2:
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007156 globfree(&pglob);
7157 INT_ON;
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007158 nometa:
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007159 *exparg.lastp = str;
7160 rmescapes(str->text, 0);
7161 exparg.lastp = &str->next;
7162 break;
7163 default: /* GLOB_NOSPACE */
7164 globfree(&pglob);
7165 INT_ON;
7166 ash_msg_and_raise_error(bb_msg_memory_exhausted);
7167 }
7168 str = str->next;
7169 }
7170}
7171
7172#else
Denys Vlasenko514b51d2016-10-01 14:33:08 +02007173/* ENABLE_ASH_INTERNAL_GLOB: Homegrown globbing code. (dash also has both, uses homegrown one.) */
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007174
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007175/*
7176 * Do metacharacter (i.e. *, ?, [...]) expansion.
7177 */
7178static void
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007179expmeta(char *expdir, char *enddir, char *name)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007180{
7181 char *p;
7182 const char *cp;
7183 char *start;
7184 char *endname;
7185 int metaflag;
7186 struct stat statb;
7187 DIR *dirp;
7188 struct dirent *dp;
7189 int atend;
7190 int matchdot;
Ron Yorstonca25af92015-09-04 10:32:41 +01007191 int esc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007192
7193 metaflag = 0;
7194 start = name;
Ron Yorstonca25af92015-09-04 10:32:41 +01007195 for (p = name; esc = 0, *p; p += esc + 1) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007196 if (*p == '*' || *p == '?')
7197 metaflag = 1;
7198 else if (*p == '[') {
7199 char *q = p + 1;
7200 if (*q == '!')
7201 q++;
7202 for (;;) {
7203 if (*q == '\\')
7204 q++;
7205 if (*q == '/' || *q == '\0')
7206 break;
7207 if (*++q == ']') {
7208 metaflag = 1;
7209 break;
7210 }
7211 }
Ron Yorstonca25af92015-09-04 10:32:41 +01007212 } else {
7213 if (*p == '\\')
7214 esc++;
7215 if (p[esc] == '/') {
7216 if (metaflag)
7217 break;
7218 start = p + esc + 1;
7219 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007220 }
7221 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007222 if (metaflag == 0) { /* we've reached the end of the file name */
7223 if (enddir != expdir)
7224 metaflag++;
7225 p = name;
7226 do {
7227 if (*p == '\\')
7228 p++;
7229 *enddir++ = *p;
7230 } while (*p++);
7231 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
7232 addfname(expdir);
7233 return;
7234 }
7235 endname = p;
7236 if (name < start) {
7237 p = name;
7238 do {
7239 if (*p == '\\')
7240 p++;
7241 *enddir++ = *p++;
7242 } while (p < start);
7243 }
7244 if (enddir == expdir) {
7245 cp = ".";
7246 } else if (enddir == expdir + 1 && *expdir == '/') {
7247 cp = "/";
7248 } else {
7249 cp = expdir;
7250 enddir[-1] = '\0';
7251 }
7252 dirp = opendir(cp);
7253 if (dirp == NULL)
7254 return;
7255 if (enddir != expdir)
7256 enddir[-1] = '/';
7257 if (*endname == 0) {
7258 atend = 1;
7259 } else {
7260 atend = 0;
Ron Yorstonca25af92015-09-04 10:32:41 +01007261 *endname = '\0';
7262 endname += esc + 1;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007263 }
7264 matchdot = 0;
7265 p = start;
7266 if (*p == '\\')
7267 p++;
7268 if (*p == '.')
7269 matchdot++;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02007270 while (!pending_int && (dp = readdir(dirp)) != NULL) {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00007271 if (dp->d_name[0] == '.' && !matchdot)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007272 continue;
7273 if (pmatch(start, dp->d_name)) {
7274 if (atend) {
7275 strcpy(enddir, dp->d_name);
7276 addfname(expdir);
7277 } else {
7278 for (p = enddir, cp = dp->d_name; (*p++ = *cp++) != '\0';)
7279 continue;
7280 p[-1] = '/';
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007281 expmeta(expdir, p, endname);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007282 }
7283 }
7284 }
7285 closedir(dirp);
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00007286 if (!atend)
Ron Yorstonca25af92015-09-04 10:32:41 +01007287 endname[-esc - 1] = esc ? '\\' : '/';
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007288}
7289
7290static struct strlist *
7291msort(struct strlist *list, int len)
7292{
7293 struct strlist *p, *q = NULL;
7294 struct strlist **lpp;
7295 int half;
7296 int n;
7297
7298 if (len <= 1)
7299 return list;
7300 half = len >> 1;
7301 p = list;
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +00007302 for (n = half; --n >= 0;) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007303 q = p;
7304 p = p->next;
7305 }
7306 q->next = NULL; /* terminate first half of list */
7307 q = msort(list, half); /* sort first half of list */
7308 p = msort(p, len - half); /* sort second half */
7309 lpp = &list;
7310 for (;;) {
7311#if ENABLE_LOCALE_SUPPORT
7312 if (strcoll(p->text, q->text) < 0)
7313#else
7314 if (strcmp(p->text, q->text) < 0)
7315#endif
7316 {
7317 *lpp = p;
7318 lpp = &p->next;
7319 p = *lpp;
7320 if (p == NULL) {
7321 *lpp = q;
7322 break;
7323 }
7324 } else {
7325 *lpp = q;
7326 lpp = &q->next;
7327 q = *lpp;
7328 if (q == NULL) {
7329 *lpp = p;
7330 break;
7331 }
7332 }
7333 }
7334 return list;
7335}
7336
7337/*
7338 * Sort the results of file name expansion. It calculates the number of
7339 * strings to sort and then calls msort (short for merge sort) to do the
7340 * work.
7341 */
7342static struct strlist *
7343expsort(struct strlist *str)
7344{
7345 int len;
7346 struct strlist *sp;
7347
7348 len = 0;
7349 for (sp = str; sp; sp = sp->next)
7350 len++;
7351 return msort(str, len);
7352}
7353
7354static void
Denis Vlasenko68404f12008-03-17 09:00:54 +00007355expandmeta(struct strlist *str /*, int flag*/)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007356{
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00007357 static const char metachars[] ALIGN1 = {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007358 '*', '?', '[', 0
7359 };
7360 /* TODO - EXP_REDIR */
7361
7362 while (str) {
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007363 char *expdir;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007364 struct strlist **savelastp;
7365 struct strlist *sp;
7366 char *p;
7367
7368 if (fflag)
7369 goto nometa;
7370 if (!strpbrk(str->text, metachars))
7371 goto nometa;
7372 savelastp = exparg.lastp;
7373
7374 INT_OFF;
Ron Yorston549deab2015-05-18 09:57:51 +02007375 p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007376 {
7377 int i = strlen(str->text);
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007378//BUGGY estimation of how long expanded name can be
7379 expdir = ckmalloc(i < 2048 ? 2048 : i+1);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007380 }
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007381 expmeta(expdir, expdir, p);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007382 free(expdir);
7383 if (p != str->text)
7384 free(p);
7385 INT_ON;
7386 if (exparg.lastp == savelastp) {
7387 /*
7388 * no matches
7389 */
7390 nometa:
7391 *exparg.lastp = str;
Denys Vlasenkob6c84342009-08-29 20:23:20 +02007392 rmescapes(str->text, 0);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007393 exparg.lastp = &str->next;
7394 } else {
7395 *exparg.lastp = NULL;
7396 *savelastp = sp = expsort(*savelastp);
7397 while (sp->next != NULL)
7398 sp = sp->next;
7399 exparg.lastp = &sp->next;
7400 }
7401 str = str->next;
7402 }
7403}
Denys Vlasenko514b51d2016-10-01 14:33:08 +02007404#endif /* ENABLE_ASH_INTERNAL_GLOB */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007405
7406/*
7407 * Perform variable substitution and command substitution on an argument,
7408 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
7409 * perform splitting and file name expansion. When arglist is NULL, perform
7410 * here document expansion.
7411 */
7412static void
7413expandarg(union node *arg, struct arglist *arglist, int flag)
7414{
7415 struct strlist *sp;
7416 char *p;
7417
7418 argbackq = arg->narg.backquote;
7419 STARTSTACKSTR(expdest);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02007420 TRACE(("expandarg: argstr('%s',flags:%x)\n", arg->narg.text, flag));
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00007421 argstr(arg->narg.text, flag,
7422 /* var_str_list: */ arglist ? arglist->list : NULL);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007423 p = _STPUTC('\0', expdest);
7424 expdest = p - 1;
7425 if (arglist == NULL) {
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02007426 /* here document expanded */
7427 goto out;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007428 }
7429 p = grabstackstr(p);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02007430 TRACE(("expandarg: p:'%s'\n", p));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007431 exparg.lastp = &exparg.list;
7432 /*
7433 * TODO - EXP_REDIR
7434 */
7435 if (flag & EXP_FULL) {
7436 ifsbreakup(p, &exparg);
7437 *exparg.lastp = NULL;
7438 exparg.lastp = &exparg.list;
Denis Vlasenko68404f12008-03-17 09:00:54 +00007439 expandmeta(exparg.list /*, flag*/);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007440 } else {
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02007441 if (flag & EXP_REDIR) { /*XXX - for now, just remove escapes */
Denys Vlasenkob6c84342009-08-29 20:23:20 +02007442 rmescapes(p, 0);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02007443 TRACE(("expandarg: rmescapes:'%s'\n", p));
7444 }
Denis Vlasenko597906c2008-02-20 16:38:54 +00007445 sp = stzalloc(sizeof(*sp));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007446 sp->text = p;
7447 *exparg.lastp = sp;
7448 exparg.lastp = &sp->next;
7449 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007450 *exparg.lastp = NULL;
7451 if (exparg.list) {
7452 *arglist->lastp = exparg.list;
7453 arglist->lastp = exparg.lastp;
7454 }
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02007455
7456 out:
7457 ifsfree();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007458}
7459
7460/*
7461 * Expand shell variables and backquotes inside a here document.
7462 */
7463static void
7464expandhere(union node *arg, int fd)
7465{
Ron Yorston549deab2015-05-18 09:57:51 +02007466 expandarg(arg, (struct arglist *)NULL, EXP_QUOTED);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007467 full_write(fd, stackblock(), expdest - (char *)stackblock());
7468}
7469
7470/*
7471 * Returns true if the pattern matches the string.
7472 */
7473static int
7474patmatch(char *pattern, const char *string)
7475{
Ron Yorston549deab2015-05-18 09:57:51 +02007476 return pmatch(preglob(pattern, 0), string);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007477}
7478
7479/*
7480 * See if a pattern matches in a case statement.
7481 */
7482static int
7483casematch(union node *pattern, char *val)
7484{
7485 struct stackmark smark;
7486 int result;
7487
7488 setstackmark(&smark);
7489 argbackq = pattern->narg.backquote;
7490 STARTSTACKSTR(expdest);
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00007491 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE,
7492 /* var_str_list: */ NULL);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007493 STACKSTRNUL(expdest);
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02007494 ifsfree();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007495 result = patmatch(stackblock(), val);
7496 popstackmark(&smark);
7497 return result;
7498}
7499
7500
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007501/* ============ find_command */
7502
7503struct builtincmd {
7504 const char *name;
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02007505 int (*builtin)(int, char **) FAST_FUNC;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007506 /* unsigned flags; */
7507};
7508#define IS_BUILTIN_SPECIAL(b) ((b)->name[0] & 1)
Denis Vlasenkoe26b2782008-02-12 07:40:29 +00007509/* "regular" builtins always take precedence over commands,
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007510 * regardless of PATH=....%builtin... position */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007511#define IS_BUILTIN_REGULAR(b) ((b)->name[0] & 2)
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007512#define IS_BUILTIN_ASSIGN(b) ((b)->name[0] & 4)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007513
7514struct cmdentry {
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00007515 smallint cmdtype; /* CMDxxx */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007516 union param {
7517 int index;
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00007518 /* index >= 0 for commands without path (slashes) */
7519 /* (TODO: what exactly does the value mean? PATH position?) */
7520 /* index == -1 for commands with slashes */
7521 /* index == (-2 - applet_no) for NOFORK applets */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007522 const struct builtincmd *cmd;
7523 struct funcnode *func;
7524 } u;
7525};
7526/* values of cmdtype */
7527#define CMDUNKNOWN -1 /* no entry in table for command */
7528#define CMDNORMAL 0 /* command is an executable program */
7529#define CMDFUNCTION 1 /* command is a shell function */
7530#define CMDBUILTIN 2 /* command is a shell builtin */
7531
7532/* action to find_command() */
7533#define DO_ERR 0x01 /* prints errors */
7534#define DO_ABS 0x02 /* checks absolute paths */
7535#define DO_NOFUNC 0x04 /* don't return shell functions, for command */
7536#define DO_ALTPATH 0x08 /* using alternate path */
7537#define DO_ALTBLTIN 0x20 /* %builtin in alt. path */
7538
7539static void find_command(char *, struct cmdentry *, int, const char *);
7540
7541
7542/* ============ Hashing commands */
7543
7544/*
7545 * When commands are first encountered, they are entered in a hash table.
7546 * This ensures that a full path search will not have to be done for them
7547 * on each invocation.
7548 *
7549 * We should investigate converting to a linear search, even though that
7550 * would make the command name "hash" a misnomer.
7551 */
7552
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007553struct tblentry {
7554 struct tblentry *next; /* next entry in hash chain */
7555 union param param; /* definition of builtin function */
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00007556 smallint cmdtype; /* CMDxxx */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007557 char rehash; /* if set, cd done since entry created */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00007558 char cmdname[1]; /* name of command */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007559};
7560
Denis Vlasenko01631112007-12-16 17:20:38 +00007561static struct tblentry **cmdtable;
7562#define INIT_G_cmdtable() do { \
7563 cmdtable = xzalloc(CMDTABLESIZE * sizeof(cmdtable[0])); \
7564} while (0)
7565
7566static int builtinloc = -1; /* index in path of %builtin, or -1 */
7567
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007568
7569static void
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00007570tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) char *cmd, char **argv, char **envp)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007571{
Denis Vlasenko80d14be2007-04-10 23:03:30 +00007572#if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007573 if (applet_no >= 0) {
Denis Vlasenkob7304742008-10-20 08:15:51 +00007574 if (APPLET_IS_NOEXEC(applet_no)) {
Denys Vlasenko7df28bb2010-06-18 14:23:47 +02007575 clearenv();
Denis Vlasenkob7304742008-10-20 08:15:51 +00007576 while (*envp)
7577 putenv(*envp++);
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007578 run_applet_no_and_exit(applet_no, argv);
Denis Vlasenkob7304742008-10-20 08:15:51 +00007579 }
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007580 /* re-exec ourselves with the new arguments */
7581 execve(bb_busybox_exec_path, argv, envp);
7582 /* If they called chroot or otherwise made the binary no longer
7583 * executable, fall through */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007584 }
7585#endif
7586
7587 repeat:
7588#ifdef SYSV
7589 do {
7590 execve(cmd, argv, envp);
7591 } while (errno == EINTR);
7592#else
7593 execve(cmd, argv, envp);
7594#endif
Denys Vlasenko65a8b852016-10-26 22:29:11 +02007595 if (cmd != (char*) bb_busybox_exec_path && errno == ENOEXEC) {
Denys Vlasenkoaefe1c22011-03-07 12:02:40 +01007596 /* Run "cmd" as a shell script:
7597 * http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html
7598 * "If the execve() function fails with ENOEXEC, the shell
7599 * shall execute a command equivalent to having a shell invoked
7600 * with the command name as its first operand,
7601 * with any remaining arguments passed to the new shell"
7602 *
7603 * That is, do not use $SHELL, user's shell, or /bin/sh;
7604 * just call ourselves.
Denys Vlasenko2bef5262011-12-16 00:25:17 +01007605 *
7606 * Note that bash reads ~80 chars of the file, and if it sees
7607 * a zero byte before it sees newline, it doesn't try to
7608 * interpret it, but fails with "cannot execute binary file"
Denys Vlasenkocda6ea92011-12-16 00:44:36 +01007609 * message and exit code 126. For one, this prevents attempts
7610 * to interpret foreign ELF binaries as shell scripts.
Denys Vlasenkoaefe1c22011-03-07 12:02:40 +01007611 */
Denys Vlasenko65a8b852016-10-26 22:29:11 +02007612 argv[0] = cmd;
Denys Vlasenkoaefe1c22011-03-07 12:02:40 +01007613 cmd = (char*) bb_busybox_exec_path;
Denys Vlasenko65a8b852016-10-26 22:29:11 +02007614 /* NB: this is only possible because all callers of shellexec()
7615 * ensure that the argv[-1] slot exists!
7616 */
7617 argv--;
7618 argv[0] = (char*) "ash";
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007619 goto repeat;
7620 }
7621}
7622
7623/*
7624 * Exec a program. Never returns. If you change this routine, you may
7625 * have to change the find_command routine as well.
Denys Vlasenko65a8b852016-10-26 22:29:11 +02007626 * argv[-1] must exist and be writable! See tryexec() for why.
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007627 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00007628static void shellexec(char **, const char *, int) NORETURN;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007629static void
7630shellexec(char **argv, const char *path, int idx)
7631{
7632 char *cmdname;
7633 int e;
7634 char **envp;
7635 int exerrno;
Denys Vlasenko83f103b2011-12-20 06:10:35 +01007636 int applet_no = -1; /* used only by FEATURE_SH_STANDALONE */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007637
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +02007638 envp = listvars(VEXPORT, VUNSET, /*end:*/ NULL);
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007639 if (strchr(argv[0], '/') != NULL
Denis Vlasenko80d14be2007-04-10 23:03:30 +00007640#if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007641 || (applet_no = find_applet_by_name(argv[0])) >= 0
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007642#endif
7643 ) {
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00007644 tryexec(IF_FEATURE_SH_STANDALONE(applet_no,) argv[0], argv, envp);
Denys Vlasenko83f103b2011-12-20 06:10:35 +01007645 if (applet_no >= 0) {
7646 /* We tried execing ourself, but it didn't work.
7647 * Maybe /proc/self/exe doesn't exist?
7648 * Try $PATH search.
7649 */
7650 goto try_PATH;
7651 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007652 e = errno;
7653 } else {
Denys Vlasenko83f103b2011-12-20 06:10:35 +01007654 try_PATH:
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007655 e = ENOENT;
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02007656 while ((cmdname = path_advance(&path, argv[0])) != NULL) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007657 if (--idx < 0 && pathopt == NULL) {
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00007658 tryexec(IF_FEATURE_SH_STANDALONE(-1,) cmdname, argv, envp);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007659 if (errno != ENOENT && errno != ENOTDIR)
7660 e = errno;
7661 }
7662 stunalloc(cmdname);
7663 }
7664 }
7665
7666 /* Map to POSIX errors */
7667 switch (e) {
7668 case EACCES:
7669 exerrno = 126;
7670 break;
7671 case ENOENT:
7672 exerrno = 127;
7673 break;
7674 default:
7675 exerrno = 2;
7676 break;
7677 }
7678 exitstatus = exerrno;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02007679 TRACE(("shellexec failed for %s, errno %d, suppress_int %d\n",
7680 argv[0], e, suppress_int));
Denys Vlasenko061a0902016-10-25 17:24:25 +02007681 ash_msg_and_raise(EXEXIT, "%s: %s", argv[0], errmsg(e, "not found"));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007682 /* NOTREACHED */
7683}
7684
7685static void
7686printentry(struct tblentry *cmdp)
7687{
7688 int idx;
7689 const char *path;
7690 char *name;
7691
7692 idx = cmdp->param.index;
7693 path = pathval();
7694 do {
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02007695 name = path_advance(&path, cmdp->cmdname);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007696 stunalloc(name);
7697 } while (--idx >= 0);
7698 out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr));
7699}
7700
7701/*
7702 * Clear out command entries. The argument specifies the first entry in
7703 * PATH which has changed.
7704 */
7705static void
7706clearcmdentry(int firstchange)
7707{
7708 struct tblentry **tblp;
7709 struct tblentry **pp;
7710 struct tblentry *cmdp;
7711
7712 INT_OFF;
7713 for (tblp = cmdtable; tblp < &cmdtable[CMDTABLESIZE]; tblp++) {
7714 pp = tblp;
7715 while ((cmdp = *pp) != NULL) {
7716 if ((cmdp->cmdtype == CMDNORMAL &&
7717 cmdp->param.index >= firstchange)
7718 || (cmdp->cmdtype == CMDBUILTIN &&
7719 builtinloc >= firstchange)
7720 ) {
7721 *pp = cmdp->next;
7722 free(cmdp);
7723 } else {
7724 pp = &cmdp->next;
7725 }
7726 }
7727 }
7728 INT_ON;
7729}
7730
7731/*
7732 * Locate a command in the command hash table. If "add" is nonzero,
7733 * add the command to the table if it is not already present. The
7734 * variable "lastcmdentry" is set to point to the address of the link
7735 * pointing to the entry, so that delete_cmd_entry can delete the
7736 * entry.
7737 *
7738 * Interrupts must be off if called with add != 0.
7739 */
7740static struct tblentry **lastcmdentry;
7741
7742static struct tblentry *
7743cmdlookup(const char *name, int add)
7744{
7745 unsigned int hashval;
7746 const char *p;
7747 struct tblentry *cmdp;
7748 struct tblentry **pp;
7749
7750 p = name;
7751 hashval = (unsigned char)*p << 4;
7752 while (*p)
7753 hashval += (unsigned char)*p++;
7754 hashval &= 0x7FFF;
7755 pp = &cmdtable[hashval % CMDTABLESIZE];
7756 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
7757 if (strcmp(cmdp->cmdname, name) == 0)
7758 break;
7759 pp = &cmdp->next;
7760 }
7761 if (add && cmdp == NULL) {
Denis Vlasenkob07a4962008-06-22 13:16:23 +00007762 cmdp = *pp = ckzalloc(sizeof(struct tblentry)
7763 + strlen(name)
7764 /* + 1 - already done because
7765 * tblentry::cmdname is char[1] */);
Denis Vlasenko597906c2008-02-20 16:38:54 +00007766 /*cmdp->next = NULL; - ckzalloc did it */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007767 cmdp->cmdtype = CMDUNKNOWN;
7768 strcpy(cmdp->cmdname, name);
7769 }
7770 lastcmdentry = pp;
7771 return cmdp;
7772}
7773
7774/*
7775 * Delete the command entry returned on the last lookup.
7776 */
7777static void
7778delete_cmd_entry(void)
7779{
7780 struct tblentry *cmdp;
7781
7782 INT_OFF;
7783 cmdp = *lastcmdentry;
7784 *lastcmdentry = cmdp->next;
7785 if (cmdp->cmdtype == CMDFUNCTION)
7786 freefunc(cmdp->param.func);
7787 free(cmdp);
7788 INT_ON;
7789}
7790
7791/*
7792 * Add a new command entry, replacing any existing command entry for
7793 * the same name - except special builtins.
7794 */
7795static void
7796addcmdentry(char *name, struct cmdentry *entry)
7797{
7798 struct tblentry *cmdp;
7799
7800 cmdp = cmdlookup(name, 1);
7801 if (cmdp->cmdtype == CMDFUNCTION) {
7802 freefunc(cmdp->param.func);
7803 }
7804 cmdp->cmdtype = entry->cmdtype;
7805 cmdp->param = entry->u;
7806 cmdp->rehash = 0;
7807}
7808
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02007809static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00007810hashcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007811{
7812 struct tblentry **pp;
7813 struct tblentry *cmdp;
7814 int c;
7815 struct cmdentry entry;
7816 char *name;
7817
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007818 if (nextopt("r") != '\0') {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007819 clearcmdentry(0);
7820 return 0;
7821 }
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007822
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007823 if (*argptr == NULL) {
7824 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
7825 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
7826 if (cmdp->cmdtype == CMDNORMAL)
7827 printentry(cmdp);
7828 }
7829 }
7830 return 0;
7831 }
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007832
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007833 c = 0;
7834 while ((name = *argptr) != NULL) {
7835 cmdp = cmdlookup(name, 0);
7836 if (cmdp != NULL
7837 && (cmdp->cmdtype == CMDNORMAL
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007838 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))
7839 ) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007840 delete_cmd_entry();
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007841 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007842 find_command(name, &entry, DO_ERR, pathval());
7843 if (entry.cmdtype == CMDUNKNOWN)
7844 c = 1;
7845 argptr++;
7846 }
7847 return c;
7848}
7849
7850/*
7851 * Called when a cd is done. Marks all commands so the next time they
7852 * are executed they will be rehashed.
7853 */
7854static void
7855hashcd(void)
7856{
7857 struct tblentry **pp;
7858 struct tblentry *cmdp;
7859
7860 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
7861 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007862 if (cmdp->cmdtype == CMDNORMAL
7863 || (cmdp->cmdtype == CMDBUILTIN
Denys Vlasenkoe4dcba12010-10-28 18:57:19 +02007864 && !IS_BUILTIN_REGULAR(cmdp->param.cmd)
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007865 && builtinloc > 0)
7866 ) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007867 cmdp->rehash = 1;
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007868 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007869 }
7870 }
7871}
7872
7873/*
7874 * Fix command hash table when PATH changed.
7875 * Called before PATH is changed. The argument is the new value of PATH;
7876 * pathval() still returns the old value at this point.
7877 * Called with interrupts off.
7878 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02007879static void FAST_FUNC
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007880changepath(const char *new)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007881{
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007882 const char *old;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007883 int firstchange;
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007884 int idx;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007885 int idx_bltin;
7886
7887 old = pathval();
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007888 firstchange = 9999; /* assume no change */
7889 idx = 0;
7890 idx_bltin = -1;
7891 for (;;) {
7892 if (*old != *new) {
7893 firstchange = idx;
7894 if ((*old == '\0' && *new == ':')
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +02007895 || (*old == ':' && *new == '\0')
7896 ) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007897 firstchange++;
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +02007898 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007899 old = new; /* ignore subsequent differences */
7900 }
7901 if (*new == '\0')
7902 break;
7903 if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin"))
7904 idx_bltin = idx;
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007905 if (*new == ':')
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007906 idx++;
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +02007907 new++;
7908 old++;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007909 }
7910 if (builtinloc < 0 && idx_bltin >= 0)
7911 builtinloc = idx_bltin; /* zap builtins */
7912 if (builtinloc >= 0 && idx_bltin < 0)
7913 firstchange = 0;
7914 clearcmdentry(firstchange);
7915 builtinloc = idx_bltin;
7916}
Ron Yorston95ebcf72015-11-03 09:42:23 +00007917enum {
7918 TEOF,
7919 TNL,
7920 TREDIR,
7921 TWORD,
7922 TSEMI,
7923 TBACKGND,
7924 TAND,
7925 TOR,
7926 TPIPE,
7927 TLP,
7928 TRP,
7929 TENDCASE,
7930 TENDBQUOTE,
7931 TNOT,
7932 TCASE,
7933 TDO,
7934 TDONE,
7935 TELIF,
7936 TELSE,
7937 TESAC,
7938 TFI,
7939 TFOR,
7940#if ENABLE_ASH_BASH_COMPAT
7941 TFUNCTION,
7942#endif
7943 TIF,
7944 TIN,
7945 TTHEN,
7946 TUNTIL,
7947 TWHILE,
7948 TBEGIN,
7949 TEND
7950};
Denis Vlasenkob07a4962008-06-22 13:16:23 +00007951typedef smallint token_id_t;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007952
Denys Vlasenko888527c2016-10-02 16:54:17 +02007953/* Nth bit indicates if token marks the end of a list */
7954enum {
7955 tokendlist = 0
7956 /* 0 */ | (1u << TEOF)
7957 /* 1 */ | (0u << TNL)
7958 /* 2 */ | (0u << TREDIR)
7959 /* 3 */ | (0u << TWORD)
7960 /* 4 */ | (0u << TSEMI)
7961 /* 5 */ | (0u << TBACKGND)
7962 /* 6 */ | (0u << TAND)
7963 /* 7 */ | (0u << TOR)
7964 /* 8 */ | (0u << TPIPE)
7965 /* 9 */ | (0u << TLP)
7966 /* 10 */ | (1u << TRP)
7967 /* 11 */ | (1u << TENDCASE)
7968 /* 12 */ | (1u << TENDBQUOTE)
7969 /* 13 */ | (0u << TNOT)
7970 /* 14 */ | (0u << TCASE)
7971 /* 15 */ | (1u << TDO)
7972 /* 16 */ | (1u << TDONE)
7973 /* 17 */ | (1u << TELIF)
7974 /* 18 */ | (1u << TELSE)
7975 /* 19 */ | (1u << TESAC)
7976 /* 20 */ | (1u << TFI)
7977 /* 21 */ | (0u << TFOR)
7978#if ENABLE_ASH_BASH_COMPAT
7979 /* 22 */ | (0u << TFUNCTION)
Denys Vlasenko80729a42016-10-02 22:33:15 +02007980#endif
Denys Vlasenko888527c2016-10-02 16:54:17 +02007981 /* 23 */ | (0u << TIF)
7982 /* 24 */ | (0u << TIN)
7983 /* 25 */ | (1u << TTHEN)
7984 /* 26 */ | (0u << TUNTIL)
7985 /* 27 */ | (0u << TWHILE)
7986 /* 28 */ | (0u << TBEGIN)
7987 /* 29 */ | (1u << TEND)
7988 , /* thus far 29 bits used */
7989};
7990
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007991static const char *const tokname_array[] = {
Denys Vlasenko888527c2016-10-02 16:54:17 +02007992 "end of file",
7993 "newline",
7994 "redirection",
7995 "word",
7996 ";",
7997 "&",
7998 "&&",
7999 "||",
8000 "|",
8001 "(",
8002 ")",
8003 ";;",
8004 "`",
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008005#define KWDOFFSET 13
8006 /* the following are keywords */
Denys Vlasenko888527c2016-10-02 16:54:17 +02008007 "!",
8008 "case",
8009 "do",
8010 "done",
8011 "elif",
8012 "else",
8013 "esac",
8014 "fi",
8015 "for",
Ron Yorston95ebcf72015-11-03 09:42:23 +00008016#if ENABLE_ASH_BASH_COMPAT
Denys Vlasenko888527c2016-10-02 16:54:17 +02008017 "function",
Ron Yorston95ebcf72015-11-03 09:42:23 +00008018#endif
Denys Vlasenko888527c2016-10-02 16:54:17 +02008019 "if",
8020 "in",
8021 "then",
8022 "until",
8023 "while",
8024 "{",
8025 "}",
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008026};
8027
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008028/* Wrapper around strcmp for qsort/bsearch/... */
8029static int
8030pstrcmp(const void *a, const void *b)
8031{
Denys Vlasenko888527c2016-10-02 16:54:17 +02008032 return strcmp((char*)a, *(char**)b);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008033}
8034
8035static const char *const *
8036findkwd(const char *s)
8037{
8038 return bsearch(s, tokname_array + KWDOFFSET,
Denis Vlasenko80b8b392007-06-25 10:55:35 +00008039 ARRAY_SIZE(tokname_array) - KWDOFFSET,
8040 sizeof(tokname_array[0]), pstrcmp);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008041}
8042
8043/*
8044 * Locate and print what a word is...
8045 */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008046static int
Ron Yorston3f221112015-08-03 13:47:33 +01008047describe_command(char *command, const char *path, int describe_command_verbose)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008048{
8049 struct cmdentry entry;
8050 struct tblentry *cmdp;
8051#if ENABLE_ASH_ALIAS
8052 const struct alias *ap;
8053#endif
Ron Yorston3f221112015-08-03 13:47:33 +01008054
8055 path = path ? path : pathval();
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008056
8057 if (describe_command_verbose) {
8058 out1str(command);
8059 }
8060
8061 /* First look at the keywords */
8062 if (findkwd(command)) {
8063 out1str(describe_command_verbose ? " is a shell keyword" : command);
8064 goto out;
8065 }
8066
8067#if ENABLE_ASH_ALIAS
8068 /* Then look at the aliases */
8069 ap = lookupalias(command, 0);
8070 if (ap != NULL) {
Denis Vlasenko46846e22007-05-20 13:08:31 +00008071 if (!describe_command_verbose) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008072 out1str("alias ");
8073 printalias(ap);
8074 return 0;
8075 }
Denis Vlasenko46846e22007-05-20 13:08:31 +00008076 out1fmt(" is an alias for %s", ap->val);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008077 goto out;
8078 }
8079#endif
8080 /* Then check if it is a tracked alias */
8081 cmdp = cmdlookup(command, 0);
8082 if (cmdp != NULL) {
8083 entry.cmdtype = cmdp->cmdtype;
8084 entry.u = cmdp->param;
8085 } else {
8086 /* Finally use brute force */
8087 find_command(command, &entry, DO_ABS, path);
8088 }
8089
8090 switch (entry.cmdtype) {
8091 case CMDNORMAL: {
8092 int j = entry.u.index;
8093 char *p;
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00008094 if (j < 0) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008095 p = command;
8096 } else {
8097 do {
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02008098 p = path_advance(&path, command);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008099 stunalloc(p);
8100 } while (--j >= 0);
8101 }
8102 if (describe_command_verbose) {
8103 out1fmt(" is%s %s",
8104 (cmdp ? " a tracked alias for" : nullstr), p
8105 );
8106 } else {
8107 out1str(p);
8108 }
8109 break;
8110 }
8111
8112 case CMDFUNCTION:
8113 if (describe_command_verbose) {
8114 out1str(" is a shell function");
8115 } else {
8116 out1str(command);
8117 }
8118 break;
8119
8120 case CMDBUILTIN:
8121 if (describe_command_verbose) {
8122 out1fmt(" is a %sshell builtin",
8123 IS_BUILTIN_SPECIAL(entry.u.cmd) ?
8124 "special " : nullstr
8125 );
8126 } else {
8127 out1str(command);
8128 }
8129 break;
8130
8131 default:
8132 if (describe_command_verbose) {
8133 out1str(": not found\n");
8134 }
8135 return 127;
8136 }
8137 out:
Denys Vlasenko285ad152009-12-04 23:02:27 +01008138 out1str("\n");
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008139 return 0;
8140}
8141
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02008142static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00008143typecmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008144{
Denis Vlasenko46846e22007-05-20 13:08:31 +00008145 int i = 1;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008146 int err = 0;
Denis Vlasenko46846e22007-05-20 13:08:31 +00008147 int verbose = 1;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008148
Denis Vlasenko46846e22007-05-20 13:08:31 +00008149 /* type -p ... ? (we don't bother checking for 'p') */
Denis Vlasenko1fc62382007-06-25 22:55:34 +00008150 if (argv[1] && argv[1][0] == '-') {
Denis Vlasenko46846e22007-05-20 13:08:31 +00008151 i++;
8152 verbose = 0;
8153 }
Denis Vlasenko68404f12008-03-17 09:00:54 +00008154 while (argv[i]) {
Ron Yorston3f221112015-08-03 13:47:33 +01008155 err |= describe_command(argv[i++], NULL, verbose);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008156 }
8157 return err;
8158}
8159
8160#if ENABLE_ASH_CMDCMD
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008161/* Is it "command [-p] PROG ARGS" bltin, no other opts? Return ptr to "PROG" if yes */
8162static char **
8163parse_command_args(char **argv, const char **path)
8164{
8165 char *cp, c;
8166
8167 for (;;) {
8168 cp = *++argv;
8169 if (!cp)
8170 return NULL;
8171 if (*cp++ != '-')
8172 break;
8173 c = *cp++;
8174 if (!c)
8175 break;
8176 if (c == '-' && !*cp) {
8177 if (!*++argv)
8178 return NULL;
8179 break;
8180 }
8181 do {
8182 switch (c) {
8183 case 'p':
8184 *path = bb_default_path;
8185 break;
8186 default:
8187 /* run 'typecmd' for other options */
8188 return NULL;
8189 }
8190 c = *cp++;
8191 } while (c);
8192 }
8193 return argv;
8194}
8195
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02008196static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00008197commandcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008198{
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008199 char *cmd;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008200 int c;
8201 enum {
8202 VERIFY_BRIEF = 1,
8203 VERIFY_VERBOSE = 2,
8204 } verify = 0;
Ron Yorston3f221112015-08-03 13:47:33 +01008205 const char *path = NULL;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008206
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008207 /* "command [-p] PROG ARGS" (that is, without -V or -v)
8208 * never reaches this function.
8209 */
8210
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008211 while ((c = nextopt("pvV")) != '\0')
8212 if (c == 'V')
8213 verify |= VERIFY_VERBOSE;
8214 else if (c == 'v')
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008215 /*verify |= VERIFY_BRIEF*/;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008216#if DEBUG
8217 else if (c != 'p')
8218 abort();
8219#endif
Ron Yorston3f221112015-08-03 13:47:33 +01008220 else
8221 path = bb_default_path;
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008222
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00008223 /* Mimic bash: just "command -v" doesn't complain, it's a nop */
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008224 cmd = *argptr;
8225 if (/*verify && */ cmd)
8226 return describe_command(cmd, path, verify /* - VERIFY_BRIEF*/);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008227
8228 return 0;
8229}
8230#endif
8231
8232
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008233/*static int funcblocksize; // size of structures in function */
8234/*static int funcstringsize; // size of strings in node */
Denis Vlasenko340299a2008-11-21 10:36:36 +00008235static void *funcblock; /* block to allocate function from */
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008236static char *funcstring_end; /* end of block to allocate strings from */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008237
Eric Andersencb57d552001-06-28 07:25:16 +00008238/* flags in argument to evaltree */
Denis Vlasenko340299a2008-11-21 10:36:36 +00008239#define EV_EXIT 01 /* exit after evaluating tree */
8240#define EV_TESTED 02 /* exit status is checked; ignore -e flag */
Eric Andersencb57d552001-06-28 07:25:16 +00008241
Denys Vlasenko3e134eb2016-04-22 18:09:21 +02008242static const uint8_t nodesize[N_NUMBER] ALIGN1 = {
Denis Vlasenko340299a2008-11-21 10:36:36 +00008243 [NCMD ] = SHELL_ALIGN(sizeof(struct ncmd)),
8244 [NPIPE ] = SHELL_ALIGN(sizeof(struct npipe)),
8245 [NREDIR ] = SHELL_ALIGN(sizeof(struct nredir)),
8246 [NBACKGND ] = SHELL_ALIGN(sizeof(struct nredir)),
8247 [NSUBSHELL] = SHELL_ALIGN(sizeof(struct nredir)),
8248 [NAND ] = SHELL_ALIGN(sizeof(struct nbinary)),
8249 [NOR ] = SHELL_ALIGN(sizeof(struct nbinary)),
8250 [NSEMI ] = SHELL_ALIGN(sizeof(struct nbinary)),
8251 [NIF ] = SHELL_ALIGN(sizeof(struct nif)),
8252 [NWHILE ] = SHELL_ALIGN(sizeof(struct nbinary)),
8253 [NUNTIL ] = SHELL_ALIGN(sizeof(struct nbinary)),
8254 [NFOR ] = SHELL_ALIGN(sizeof(struct nfor)),
8255 [NCASE ] = SHELL_ALIGN(sizeof(struct ncase)),
8256 [NCLIST ] = SHELL_ALIGN(sizeof(struct nclist)),
8257 [NDEFUN ] = SHELL_ALIGN(sizeof(struct narg)),
8258 [NARG ] = SHELL_ALIGN(sizeof(struct narg)),
8259 [NTO ] = SHELL_ALIGN(sizeof(struct nfile)),
Denis Vlasenkocc5feab2008-11-22 01:32:40 +00008260#if ENABLE_ASH_BASH_COMPAT
Denis Vlasenko340299a2008-11-21 10:36:36 +00008261 [NTO2 ] = SHELL_ALIGN(sizeof(struct nfile)),
Denis Vlasenkocc5feab2008-11-22 01:32:40 +00008262#endif
Denis Vlasenko340299a2008-11-21 10:36:36 +00008263 [NCLOBBER ] = SHELL_ALIGN(sizeof(struct nfile)),
8264 [NFROM ] = SHELL_ALIGN(sizeof(struct nfile)),
8265 [NFROMTO ] = SHELL_ALIGN(sizeof(struct nfile)),
8266 [NAPPEND ] = SHELL_ALIGN(sizeof(struct nfile)),
8267 [NTOFD ] = SHELL_ALIGN(sizeof(struct ndup)),
8268 [NFROMFD ] = SHELL_ALIGN(sizeof(struct ndup)),
8269 [NHERE ] = SHELL_ALIGN(sizeof(struct nhere)),
8270 [NXHERE ] = SHELL_ALIGN(sizeof(struct nhere)),
8271 [NNOT ] = SHELL_ALIGN(sizeof(struct nnot)),
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008272};
8273
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008274static int calcsize(int funcblocksize, union node *n);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008275
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008276static int
8277sizenodelist(int funcblocksize, struct nodelist *lp)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008278{
8279 while (lp) {
8280 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008281 funcblocksize = calcsize(funcblocksize, lp->n);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008282 lp = lp->next;
8283 }
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008284 return funcblocksize;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008285}
8286
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008287static int
8288calcsize(int funcblocksize, union node *n)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008289{
8290 if (n == NULL)
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008291 return funcblocksize;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008292 funcblocksize += nodesize[n->type];
8293 switch (n->type) {
8294 case NCMD:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008295 funcblocksize = calcsize(funcblocksize, n->ncmd.redirect);
8296 funcblocksize = calcsize(funcblocksize, n->ncmd.args);
8297 funcblocksize = calcsize(funcblocksize, n->ncmd.assign);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008298 break;
8299 case NPIPE:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008300 funcblocksize = sizenodelist(funcblocksize, n->npipe.cmdlist);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008301 break;
8302 case NREDIR:
8303 case NBACKGND:
8304 case NSUBSHELL:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008305 funcblocksize = calcsize(funcblocksize, n->nredir.redirect);
8306 funcblocksize = calcsize(funcblocksize, n->nredir.n);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008307 break;
8308 case NAND:
8309 case NOR:
8310 case NSEMI:
8311 case NWHILE:
8312 case NUNTIL:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008313 funcblocksize = calcsize(funcblocksize, n->nbinary.ch2);
8314 funcblocksize = calcsize(funcblocksize, n->nbinary.ch1);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008315 break;
8316 case NIF:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008317 funcblocksize = calcsize(funcblocksize, n->nif.elsepart);
8318 funcblocksize = calcsize(funcblocksize, n->nif.ifpart);
8319 funcblocksize = calcsize(funcblocksize, n->nif.test);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008320 break;
8321 case NFOR:
Denys Vlasenko561639a2016-10-07 04:28:33 +02008322 funcblocksize += SHELL_ALIGN(strlen(n->nfor.var) + 1); /* was funcstringsize += ... */
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008323 funcblocksize = calcsize(funcblocksize, n->nfor.body);
8324 funcblocksize = calcsize(funcblocksize, n->nfor.args);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008325 break;
8326 case NCASE:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008327 funcblocksize = calcsize(funcblocksize, n->ncase.cases);
8328 funcblocksize = calcsize(funcblocksize, n->ncase.expr);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008329 break;
8330 case NCLIST:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008331 funcblocksize = calcsize(funcblocksize, n->nclist.body);
8332 funcblocksize = calcsize(funcblocksize, n->nclist.pattern);
8333 funcblocksize = calcsize(funcblocksize, n->nclist.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008334 break;
8335 case NDEFUN:
8336 case NARG:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008337 funcblocksize = sizenodelist(funcblocksize, n->narg.backquote);
Denys Vlasenko561639a2016-10-07 04:28:33 +02008338 funcblocksize += SHELL_ALIGN(strlen(n->narg.text) + 1); /* was funcstringsize += ... */
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008339 funcblocksize = calcsize(funcblocksize, n->narg.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008340 break;
8341 case NTO:
Denis Vlasenko559691a2008-10-05 18:39:31 +00008342#if ENABLE_ASH_BASH_COMPAT
8343 case NTO2:
8344#endif
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008345 case NCLOBBER:
8346 case NFROM:
8347 case NFROMTO:
8348 case NAPPEND:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008349 funcblocksize = calcsize(funcblocksize, n->nfile.fname);
8350 funcblocksize = calcsize(funcblocksize, n->nfile.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008351 break;
8352 case NTOFD:
8353 case NFROMFD:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008354 funcblocksize = calcsize(funcblocksize, n->ndup.vname);
8355 funcblocksize = calcsize(funcblocksize, n->ndup.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008356 break;
8357 case NHERE:
8358 case NXHERE:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008359 funcblocksize = calcsize(funcblocksize, n->nhere.doc);
8360 funcblocksize = calcsize(funcblocksize, n->nhere.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008361 break;
8362 case NNOT:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008363 funcblocksize = calcsize(funcblocksize, n->nnot.com);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008364 break;
8365 };
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008366 return funcblocksize;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008367}
8368
8369static char *
8370nodeckstrdup(char *s)
8371{
Denys Vlasenko561639a2016-10-07 04:28:33 +02008372 funcstring_end -= SHELL_ALIGN(strlen(s) + 1);
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008373 return strcpy(funcstring_end, s);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008374}
8375
8376static union node *copynode(union node *);
8377
8378static struct nodelist *
8379copynodelist(struct nodelist *lp)
8380{
8381 struct nodelist *start;
8382 struct nodelist **lpp;
8383
8384 lpp = &start;
8385 while (lp) {
8386 *lpp = funcblock;
8387 funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist));
8388 (*lpp)->n = copynode(lp->n);
8389 lp = lp->next;
8390 lpp = &(*lpp)->next;
8391 }
8392 *lpp = NULL;
8393 return start;
8394}
8395
8396static union node *
8397copynode(union node *n)
8398{
8399 union node *new;
8400
8401 if (n == NULL)
8402 return NULL;
8403 new = funcblock;
8404 funcblock = (char *) funcblock + nodesize[n->type];
8405
8406 switch (n->type) {
8407 case NCMD:
8408 new->ncmd.redirect = copynode(n->ncmd.redirect);
8409 new->ncmd.args = copynode(n->ncmd.args);
8410 new->ncmd.assign = copynode(n->ncmd.assign);
8411 break;
8412 case NPIPE:
8413 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00008414 new->npipe.pipe_backgnd = n->npipe.pipe_backgnd;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008415 break;
8416 case NREDIR:
8417 case NBACKGND:
8418 case NSUBSHELL:
8419 new->nredir.redirect = copynode(n->nredir.redirect);
8420 new->nredir.n = copynode(n->nredir.n);
8421 break;
8422 case NAND:
8423 case NOR:
8424 case NSEMI:
8425 case NWHILE:
8426 case NUNTIL:
8427 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8428 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8429 break;
8430 case NIF:
8431 new->nif.elsepart = copynode(n->nif.elsepart);
8432 new->nif.ifpart = copynode(n->nif.ifpart);
8433 new->nif.test = copynode(n->nif.test);
8434 break;
8435 case NFOR:
8436 new->nfor.var = nodeckstrdup(n->nfor.var);
8437 new->nfor.body = copynode(n->nfor.body);
8438 new->nfor.args = copynode(n->nfor.args);
8439 break;
8440 case NCASE:
8441 new->ncase.cases = copynode(n->ncase.cases);
8442 new->ncase.expr = copynode(n->ncase.expr);
8443 break;
8444 case NCLIST:
8445 new->nclist.body = copynode(n->nclist.body);
8446 new->nclist.pattern = copynode(n->nclist.pattern);
8447 new->nclist.next = copynode(n->nclist.next);
8448 break;
8449 case NDEFUN:
8450 case NARG:
8451 new->narg.backquote = copynodelist(n->narg.backquote);
8452 new->narg.text = nodeckstrdup(n->narg.text);
8453 new->narg.next = copynode(n->narg.next);
8454 break;
8455 case NTO:
Denis Vlasenko559691a2008-10-05 18:39:31 +00008456#if ENABLE_ASH_BASH_COMPAT
8457 case NTO2:
8458#endif
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008459 case NCLOBBER:
8460 case NFROM:
8461 case NFROMTO:
8462 case NAPPEND:
8463 new->nfile.fname = copynode(n->nfile.fname);
8464 new->nfile.fd = n->nfile.fd;
8465 new->nfile.next = copynode(n->nfile.next);
8466 break;
8467 case NTOFD:
8468 case NFROMFD:
8469 new->ndup.vname = copynode(n->ndup.vname);
8470 new->ndup.dupfd = n->ndup.dupfd;
8471 new->ndup.fd = n->ndup.fd;
8472 new->ndup.next = copynode(n->ndup.next);
8473 break;
8474 case NHERE:
8475 case NXHERE:
8476 new->nhere.doc = copynode(n->nhere.doc);
8477 new->nhere.fd = n->nhere.fd;
8478 new->nhere.next = copynode(n->nhere.next);
8479 break;
8480 case NNOT:
8481 new->nnot.com = copynode(n->nnot.com);
8482 break;
8483 };
8484 new->type = n->type;
8485 return new;
8486}
8487
8488/*
8489 * Make a copy of a parse tree.
8490 */
8491static struct funcnode *
8492copyfunc(union node *n)
8493{
8494 struct funcnode *f;
8495 size_t blocksize;
8496
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008497 /*funcstringsize = 0;*/
8498 blocksize = offsetof(struct funcnode, n) + calcsize(0, n);
8499 f = ckzalloc(blocksize /* + funcstringsize */);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008500 funcblock = (char *) f + offsetof(struct funcnode, n);
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008501 funcstring_end = (char *) f + blocksize;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008502 copynode(n);
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008503 /* f->count = 0; - ckzalloc did it */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008504 return f;
8505}
8506
8507/*
8508 * Define a shell function.
8509 */
8510static void
Denys Vlasenko7aec8682016-10-25 20:26:02 +02008511defun(union node *func)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008512{
8513 struct cmdentry entry;
8514
8515 INT_OFF;
8516 entry.cmdtype = CMDFUNCTION;
8517 entry.u.func = copyfunc(func);
Denys Vlasenko7aec8682016-10-25 20:26:02 +02008518 addcmdentry(func->narg.text, &entry);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008519 INT_ON;
8520}
8521
Denis Vlasenko4b875702009-03-19 13:30:04 +00008522/* Reasons for skipping commands (see comment on breakcmd routine) */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008523#define SKIPBREAK (1 << 0)
8524#define SKIPCONT (1 << 1)
8525#define SKIPFUNC (1 << 2)
Denis Vlasenko4b875702009-03-19 13:30:04 +00008526static smallint evalskip; /* set to SKIPxxx if we are skipping commands */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008527static int skipcount; /* number of levels to skip */
8528static int funcnest; /* depth of function calls */
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +00008529static int loopnest; /* current loop nesting level */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008530
Denis Vlasenko4b875702009-03-19 13:30:04 +00008531/* Forward decl way out to parsing code - dotrap needs it */
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02008532static int evalstring(char *s, int flags);
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008533
Denis Vlasenko4b875702009-03-19 13:30:04 +00008534/* Called to execute a trap.
8535 * Single callsite - at the end of evaltree().
Denys Vlasenkob563f622010-09-25 17:15:13 +02008536 * If we return non-zero, evaltree raises EXEXIT exception.
Denis Vlasenko4b875702009-03-19 13:30:04 +00008537 *
8538 * Perhaps we should avoid entering new trap handlers
8539 * while we are executing a trap handler. [is it a TODO?]
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008540 */
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008541static void
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008542dotrap(void)
8543{
Denis Vlasenko4b875702009-03-19 13:30:04 +00008544 uint8_t *g;
8545 int sig;
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008546 uint8_t last_status;
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008547
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008548 if (!pending_sig)
8549 return;
8550
8551 last_status = exitstatus;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02008552 pending_sig = 0;
Denys Vlasenkode892052016-10-02 01:49:13 +02008553 barrier();
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008554
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008555 TRACE(("dotrap entered\n"));
Denis Vlasenko4b875702009-03-19 13:30:04 +00008556 for (sig = 1, g = gotsig; sig < NSIG; sig++, g++) {
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008557 char *p;
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008558
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008559 if (!*g)
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008560 continue;
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008561
8562 if (evalskip) {
8563 pending_sig = sig;
8564 break;
8565 }
8566
8567 p = trap[sig];
Denis Vlasenko4b875702009-03-19 13:30:04 +00008568 /* non-trapped SIGINT is handled separately by raise_interrupt,
8569 * don't upset it by resetting gotsig[SIGINT-1] */
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008570 if (sig == SIGINT && !p)
Denis Vlasenko4b875702009-03-19 13:30:04 +00008571 continue;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008572
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008573 TRACE(("sig %d is active, will run handler '%s'\n", sig, p));
Denis Vlasenko4b875702009-03-19 13:30:04 +00008574 *g = 0;
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008575 if (!p)
Denis Vlasenko4b875702009-03-19 13:30:04 +00008576 continue;
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008577 evalstring(p, 0);
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008578 }
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008579 exitstatus = last_status;
8580 TRACE(("dotrap returns\n"));
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008581}
8582
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00008583/* forward declarations - evaluation is fairly recursive business... */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008584static int evalloop(union node *, int);
8585static int evalfor(union node *, int);
8586static int evalcase(union node *, int);
8587static int evalsubshell(union node *, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008588static void expredir(union node *);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008589static int evalpipe(union node *, int);
8590static int evalcommand(union node *, int);
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02008591static int evalbltin(const struct builtincmd *, int, char **, int);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008592static void prehash(union node *);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008593
Eric Andersen62483552001-07-10 06:09:16 +00008594/*
Eric Andersenc470f442003-07-28 09:56:35 +00008595 * Evaluate a parse tree. The value is left in the global variable
8596 * exitstatus.
Eric Andersen62483552001-07-10 06:09:16 +00008597 */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008598static int
Eric Andersenc470f442003-07-28 09:56:35 +00008599evaltree(union node *n, int flags)
Eric Andersen62483552001-07-10 06:09:16 +00008600{
Eric Andersenc470f442003-07-28 09:56:35 +00008601 int checkexit = 0;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008602 int (*evalfn)(union node *, int);
8603 int status = 0;
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008604
Eric Andersenc470f442003-07-28 09:56:35 +00008605 if (n == NULL) {
8606 TRACE(("evaltree(NULL) called\n"));
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02008607 goto out;
Eric Andersen62483552001-07-10 06:09:16 +00008608 }
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008609 TRACE(("evaltree(%p: %d, %d) called\n", n, n->type, flags));
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008610
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008611 dotrap();
8612
Eric Andersenc470f442003-07-28 09:56:35 +00008613 switch (n->type) {
8614 default:
Denis Vlasenkoa7189f02006-11-17 20:29:00 +00008615#if DEBUG
Eric Andersenc470f442003-07-28 09:56:35 +00008616 out1fmt("Node type = %d\n", n->type);
Denys Vlasenko8131eea2009-11-02 14:19:51 +01008617 fflush_all();
Eric Andersenc470f442003-07-28 09:56:35 +00008618 break;
8619#endif
8620 case NNOT:
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008621 status = !evaltree(n->nnot.com, EV_TESTED);
Eric Andersenc470f442003-07-28 09:56:35 +00008622 goto setstatus;
8623 case NREDIR:
8624 expredir(n->nredir.redirect);
8625 status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
8626 if (!status) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008627 status = evaltree(n->nredir.n, flags & EV_TESTED);
Eric Andersenc470f442003-07-28 09:56:35 +00008628 }
Denys Vlasenkoeaf94362016-10-25 21:46:03 +02008629 if (n->nredir.redirect)
8630 popredir(/*drop:*/ 0, /*restore:*/ 0 /* not sure */);
Eric Andersenc470f442003-07-28 09:56:35 +00008631 goto setstatus;
8632 case NCMD:
8633 evalfn = evalcommand;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008634 checkexit:
Eric Andersenc470f442003-07-28 09:56:35 +00008635 if (eflag && !(flags & EV_TESTED))
8636 checkexit = ~0;
8637 goto calleval;
8638 case NFOR:
8639 evalfn = evalfor;
8640 goto calleval;
8641 case NWHILE:
8642 case NUNTIL:
8643 evalfn = evalloop;
8644 goto calleval;
8645 case NSUBSHELL:
8646 case NBACKGND:
8647 evalfn = evalsubshell;
Denys Vlasenkocf98b0c2016-10-25 18:19:39 +02008648 goto checkexit;
Eric Andersenc470f442003-07-28 09:56:35 +00008649 case NPIPE:
8650 evalfn = evalpipe;
8651 goto checkexit;
8652 case NCASE:
8653 evalfn = evalcase;
8654 goto calleval;
8655 case NAND:
8656 case NOR:
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008657 case NSEMI: {
8658
Eric Andersenc470f442003-07-28 09:56:35 +00008659#if NAND + 1 != NOR
8660#error NAND + 1 != NOR
8661#endif
8662#if NOR + 1 != NSEMI
8663#error NOR + 1 != NSEMI
8664#endif
Denis Vlasenko87d5fd92008-07-26 13:48:35 +00008665 unsigned is_or = n->type - NAND;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008666 status = evaltree(
Eric Andersenc470f442003-07-28 09:56:35 +00008667 n->nbinary.ch1,
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008668 (flags | ((is_or >> 1) - 1)) & EV_TESTED
Eric Andersenc470f442003-07-28 09:56:35 +00008669 );
Denys Vlasenkobc1a0082016-10-02 15:31:33 +02008670 if ((!status) == is_or || evalskip)
Eric Andersenc470f442003-07-28 09:56:35 +00008671 break;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008672 n = n->nbinary.ch2;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008673 evaln:
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008674 evalfn = evaltree;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008675 calleval:
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008676 status = evalfn(n, flags);
8677 goto setstatus;
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008678 }
Eric Andersenc470f442003-07-28 09:56:35 +00008679 case NIF:
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008680 status = evaltree(n->nif.test, EV_TESTED);
Eric Andersenc470f442003-07-28 09:56:35 +00008681 if (evalskip)
8682 break;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008683 if (!status) {
Eric Andersenc470f442003-07-28 09:56:35 +00008684 n = n->nif.ifpart;
8685 goto evaln;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008686 }
8687 if (n->nif.elsepart) {
Eric Andersenc470f442003-07-28 09:56:35 +00008688 n = n->nif.elsepart;
8689 goto evaln;
8690 }
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008691 status = 0;
8692 goto setstatus;
Eric Andersenc470f442003-07-28 09:56:35 +00008693 case NDEFUN:
Denys Vlasenko7aec8682016-10-25 20:26:02 +02008694 defun(n);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008695 /* Not necessary. To test it:
8696 * "false; f() { qwerty; }; echo $?" should print 0.
8697 */
8698 /* status = 0; */
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008699 setstatus:
Eric Andersenc470f442003-07-28 09:56:35 +00008700 exitstatus = status;
8701 break;
8702 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008703 out:
Denys Vlasenkob563f622010-09-25 17:15:13 +02008704 /* Order of checks below is important:
8705 * signal handlers trigger before exit caused by "set -e".
8706 */
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008707 dotrap();
8708
8709 if (checkexit & status)
Denis Vlasenkob012b102007-02-19 22:43:01 +00008710 raise_exception(EXEXIT);
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008711 if (flags & EV_EXIT)
8712 raise_exception(EXEXIT);
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008713
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008714 TRACE(("leaving evaltree (no interrupts)\n"));
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008715 return exitstatus;
Eric Andersen62483552001-07-10 06:09:16 +00008716}
8717
Eric Andersenc470f442003-07-28 09:56:35 +00008718#if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3)
8719static
8720#endif
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008721int evaltreenr(union node *, int) __attribute__ ((alias("evaltree"),__noreturn__));
Eric Andersenc470f442003-07-28 09:56:35 +00008722
Denys Vlasenko37dc08b2016-10-02 04:38:07 +02008723static int
8724skiploop(void)
Denys Vlasenko35ec8182016-10-01 19:56:52 +02008725{
8726 int skip = evalskip;
8727
8728 switch (skip) {
8729 case 0:
8730 break;
8731 case SKIPBREAK:
8732 case SKIPCONT:
8733 if (--skipcount <= 0) {
8734 evalskip = 0;
8735 break;
8736 }
8737 skip = SKIPBREAK;
8738 break;
8739 }
8740 return skip;
8741}
8742
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008743static int
Eric Andersenc470f442003-07-28 09:56:35 +00008744evalloop(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00008745{
Denys Vlasenko35ec8182016-10-01 19:56:52 +02008746 int skip;
Eric Andersencb57d552001-06-28 07:25:16 +00008747 int status;
8748
8749 loopnest++;
8750 status = 0;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008751 flags &= EV_TESTED;
Denys Vlasenko35ec8182016-10-01 19:56:52 +02008752 do {
Eric Andersenc470f442003-07-28 09:56:35 +00008753 int i;
8754
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008755 i = evaltree(n->nbinary.ch1, EV_TESTED);
Denys Vlasenko35ec8182016-10-01 19:56:52 +02008756 skip = skiploop();
8757 if (skip == SKIPFUNC)
8758 status = i;
8759 if (skip)
8760 continue;
Eric Andersenc470f442003-07-28 09:56:35 +00008761 if (n->type != NWHILE)
8762 i = !i;
8763 if (i != 0)
8764 break;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008765 status = evaltree(n->nbinary.ch2, flags);
Denys Vlasenko35ec8182016-10-01 19:56:52 +02008766 skip = skiploop();
8767 } while (!(skip & ~SKIPCONT));
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008768 loopnest--;
8769
8770 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00008771}
8772
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008773static int
Eric Andersenc470f442003-07-28 09:56:35 +00008774evalfor(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00008775{
8776 struct arglist arglist;
8777 union node *argp;
8778 struct strlist *sp;
8779 struct stackmark smark;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008780 int status = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00008781
8782 setstackmark(&smark);
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00008783 arglist.list = NULL;
Eric Andersencb57d552001-06-28 07:25:16 +00008784 arglist.lastp = &arglist.list;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008785 for (argp = n->nfor.args; argp; argp = argp->narg.next) {
Ron Yorston549deab2015-05-18 09:57:51 +02008786 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
Eric Andersencb57d552001-06-28 07:25:16 +00008787 }
8788 *arglist.lastp = NULL;
8789
Eric Andersencb57d552001-06-28 07:25:16 +00008790 loopnest++;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008791 flags &= EV_TESTED;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008792 for (sp = arglist.list; sp; sp = sp->next) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02008793 setvar0(n->nfor.var, sp->text);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008794 status = evaltree(n->nfor.body, flags);
Denys Vlasenko35ec8182016-10-01 19:56:52 +02008795 if (skiploop() & ~SKIPCONT)
Eric Andersencb57d552001-06-28 07:25:16 +00008796 break;
Eric Andersencb57d552001-06-28 07:25:16 +00008797 }
8798 loopnest--;
Eric Andersencb57d552001-06-28 07:25:16 +00008799 popstackmark(&smark);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008800
8801 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00008802}
8803
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008804static int
Eric Andersenc470f442003-07-28 09:56:35 +00008805evalcase(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00008806{
8807 union node *cp;
8808 union node *patp;
8809 struct arglist arglist;
8810 struct stackmark smark;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008811 int status = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00008812
8813 setstackmark(&smark);
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00008814 arglist.list = NULL;
Eric Andersencb57d552001-06-28 07:25:16 +00008815 arglist.lastp = &arglist.list;
Eric Andersencb57d552001-06-28 07:25:16 +00008816 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008817 for (cp = n->ncase.cases; cp && evalskip == 0; cp = cp->nclist.next) {
8818 for (patp = cp->nclist.pattern; patp; patp = patp->narg.next) {
Eric Andersencb57d552001-06-28 07:25:16 +00008819 if (casematch(patp, arglist.list->text)) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008820 /* Ensure body is non-empty as otherwise
8821 * EV_EXIT may prevent us from setting the
8822 * exit status.
8823 */
8824 if (evalskip == 0 && cp->nclist.body) {
8825 status = evaltree(cp->nclist.body, flags);
Eric Andersencb57d552001-06-28 07:25:16 +00008826 }
8827 goto out;
8828 }
8829 }
8830 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008831 out:
Eric Andersencb57d552001-06-28 07:25:16 +00008832 popstackmark(&smark);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008833
8834 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00008835}
8836
Eric Andersenc470f442003-07-28 09:56:35 +00008837/*
8838 * Kick off a subshell to evaluate a tree.
8839 */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008840static int
Eric Andersenc470f442003-07-28 09:56:35 +00008841evalsubshell(union node *n, int flags)
8842{
8843 struct job *jp;
8844 int backgnd = (n->type == NBACKGND);
8845 int status;
8846
8847 expredir(n->nredir.redirect);
Denys Vlasenko238bf182010-05-18 15:49:07 +02008848 if (!backgnd && (flags & EV_EXIT) && !may_have_traps)
Eric Andersenc470f442003-07-28 09:56:35 +00008849 goto nofork;
Denis Vlasenkob012b102007-02-19 22:43:01 +00008850 INT_OFF;
Denis Vlasenko68404f12008-03-17 09:00:54 +00008851 jp = makejob(/*n,*/ 1);
Eric Andersenc470f442003-07-28 09:56:35 +00008852 if (forkshell(jp, n, backgnd) == 0) {
Denys Vlasenko238bf182010-05-18 15:49:07 +02008853 /* child */
Denis Vlasenkob012b102007-02-19 22:43:01 +00008854 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +00008855 flags |= EV_EXIT;
8856 if (backgnd)
Denys Vlasenko238bf182010-05-18 15:49:07 +02008857 flags &= ~EV_TESTED;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00008858 nofork:
Eric Andersenc470f442003-07-28 09:56:35 +00008859 redirect(n->nredir.redirect, 0);
8860 evaltreenr(n->nredir.n, flags);
8861 /* never returns */
8862 }
Denys Vlasenko70392332016-10-27 02:31:55 +02008863 /* parent */
Eric Andersenc470f442003-07-28 09:56:35 +00008864 status = 0;
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00008865 if (!backgnd)
Eric Andersenc470f442003-07-28 09:56:35 +00008866 status = waitforjob(jp);
Denis Vlasenkob012b102007-02-19 22:43:01 +00008867 INT_ON;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008868 return status;
Eric Andersenc470f442003-07-28 09:56:35 +00008869}
8870
Eric Andersenc470f442003-07-28 09:56:35 +00008871/*
8872 * Compute the names of the files in a redirection list.
8873 */
Denis Vlasenko99eb8502007-02-23 21:09:49 +00008874static void fixredir(union node *, const char *, int);
Eric Andersenc470f442003-07-28 09:56:35 +00008875static void
8876expredir(union node *n)
8877{
8878 union node *redir;
8879
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008880 for (redir = n; redir; redir = redir->nfile.next) {
Eric Andersenc470f442003-07-28 09:56:35 +00008881 struct arglist fn;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008882
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00008883 fn.list = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00008884 fn.lastp = &fn.list;
8885 switch (redir->type) {
8886 case NFROMTO:
8887 case NFROM:
8888 case NTO:
Denis Vlasenko559691a2008-10-05 18:39:31 +00008889#if ENABLE_ASH_BASH_COMPAT
8890 case NTO2:
8891#endif
Eric Andersenc470f442003-07-28 09:56:35 +00008892 case NCLOBBER:
8893 case NAPPEND:
8894 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02008895 TRACE(("expredir expanded to '%s'\n", fn.list->text));
Denis Vlasenko559691a2008-10-05 18:39:31 +00008896#if ENABLE_ASH_BASH_COMPAT
8897 store_expfname:
8898#endif
Denys Vlasenko7c4b13e2013-01-17 13:02:27 +01008899#if 0
8900// By the design of stack allocator, the loop of this kind:
8901// while true; do while true; do break; done </dev/null; done
8902// will look like a memory leak: ash plans to free expfname's
8903// of "/dev/null" as soon as it finishes running the loop
8904// (in this case, never).
8905// This "fix" is wrong:
Jon Tollefson4ba6c5d2012-11-13 19:26:53 +01008906 if (redir->nfile.expfname)
8907 stunalloc(redir->nfile.expfname);
Denys Vlasenko7c4b13e2013-01-17 13:02:27 +01008908// It results in corrupted state of stacked allocations.
8909#endif
Eric Andersenc470f442003-07-28 09:56:35 +00008910 redir->nfile.expfname = fn.list->text;
8911 break;
8912 case NFROMFD:
Denis Vlasenko559691a2008-10-05 18:39:31 +00008913 case NTOFD: /* >& */
Eric Andersenc470f442003-07-28 09:56:35 +00008914 if (redir->ndup.vname) {
8915 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008916 if (fn.list == NULL)
Denis Vlasenkob012b102007-02-19 22:43:01 +00008917 ash_msg_and_raise_error("redir error");
Denis Vlasenko559691a2008-10-05 18:39:31 +00008918#if ENABLE_ASH_BASH_COMPAT
8919//FIXME: we used expandarg with different args!
8920 if (!isdigit_str9(fn.list->text)) {
8921 /* >&file, not >&fd */
8922 if (redir->nfile.fd != 1) /* 123>&file - BAD */
8923 ash_msg_and_raise_error("redir error");
8924 redir->type = NTO2;
8925 goto store_expfname;
8926 }
8927#endif
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008928 fixredir(redir, fn.list->text, 1);
Eric Andersenc470f442003-07-28 09:56:35 +00008929 }
8930 break;
8931 }
8932 }
8933}
8934
Eric Andersencb57d552001-06-28 07:25:16 +00008935/*
Eric Andersencb57d552001-06-28 07:25:16 +00008936 * Evaluate a pipeline. All the processes in the pipeline are children
8937 * of the process creating the pipeline. (This differs from some versions
8938 * of the shell, which make the last process in a pipeline the parent
8939 * of all the rest.)
8940 */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008941static int
Eric Andersenc470f442003-07-28 09:56:35 +00008942evalpipe(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00008943{
8944 struct job *jp;
8945 struct nodelist *lp;
8946 int pipelen;
8947 int prevfd;
8948 int pip[2];
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008949 int status = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00008950
Eric Andersenc470f442003-07-28 09:56:35 +00008951 TRACE(("evalpipe(0x%lx) called\n", (long)n));
Eric Andersencb57d552001-06-28 07:25:16 +00008952 pipelen = 0;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008953 for (lp = n->npipe.cmdlist; lp; lp = lp->next)
Eric Andersencb57d552001-06-28 07:25:16 +00008954 pipelen++;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008955 flags |= EV_EXIT;
Denis Vlasenkob012b102007-02-19 22:43:01 +00008956 INT_OFF;
Denis Vlasenko68404f12008-03-17 09:00:54 +00008957 jp = makejob(/*n,*/ pipelen);
Eric Andersencb57d552001-06-28 07:25:16 +00008958 prevfd = -1;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008959 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008960 prehash(lp->n);
Eric Andersencb57d552001-06-28 07:25:16 +00008961 pip[1] = -1;
8962 if (lp->next) {
8963 if (pipe(pip) < 0) {
8964 close(prevfd);
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00008965 ash_msg_and_raise_error("pipe call failed");
Eric Andersencb57d552001-06-28 07:25:16 +00008966 }
8967 }
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00008968 if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) {
Denys Vlasenko70392332016-10-27 02:31:55 +02008969 /* child */
Denis Vlasenkob012b102007-02-19 22:43:01 +00008970 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +00008971 if (pip[1] >= 0) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008972 close(pip[0]);
Eric Andersencb57d552001-06-28 07:25:16 +00008973 }
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008974 if (prevfd > 0) {
8975 dup2(prevfd, 0);
8976 close(prevfd);
8977 }
8978 if (pip[1] > 1) {
8979 dup2(pip[1], 1);
8980 close(pip[1]);
8981 }
Eric Andersenc470f442003-07-28 09:56:35 +00008982 evaltreenr(lp->n, flags);
8983 /* never returns */
Eric Andersencb57d552001-06-28 07:25:16 +00008984 }
Denys Vlasenko70392332016-10-27 02:31:55 +02008985 /* parent */
Eric Andersencb57d552001-06-28 07:25:16 +00008986 if (prevfd >= 0)
8987 close(prevfd);
8988 prevfd = pip[0];
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +00008989 /* Don't want to trigger debugging */
8990 if (pip[1] != -1)
8991 close(pip[1]);
Eric Andersencb57d552001-06-28 07:25:16 +00008992 }
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00008993 if (n->npipe.pipe_backgnd == 0) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008994 status = waitforjob(jp);
8995 TRACE(("evalpipe: job done exit status %d\n", status));
Eric Andersencb57d552001-06-28 07:25:16 +00008996 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00008997 INT_ON;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008998
8999 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00009000}
9001
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009002/*
9003 * Controls whether the shell is interactive or not.
9004 */
9005static void
9006setinteractive(int on)
9007{
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009008 static smallint is_interactive;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009009
9010 if (++on == is_interactive)
9011 return;
9012 is_interactive = on;
9013 setsignal(SIGINT);
9014 setsignal(SIGQUIT);
9015 setsignal(SIGTERM);
9016#if !ENABLE_FEATURE_SH_EXTRA_QUIET
9017 if (is_interactive > 1) {
9018 /* Looks like they want an interactive shell */
Denis Vlasenkoca525b42007-06-13 12:27:17 +00009019 static smallint did_banner;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009020
Denis Vlasenkoca525b42007-06-13 12:27:17 +00009021 if (!did_banner) {
Denys Vlasenkoc34c0332009-09-29 12:25:30 +02009022 /* note: ash and hush share this string */
9023 out1fmt("\n\n%s %s\n"
Denys Vlasenko2ec34962014-09-08 16:52:39 +02009024 IF_ASH_HELP("Enter 'help' for a list of built-in commands.\n")
9025 "\n",
Denys Vlasenkoc34c0332009-09-29 12:25:30 +02009026 bb_banner,
9027 "built-in shell (ash)"
9028 );
Denis Vlasenkoca525b42007-06-13 12:27:17 +00009029 did_banner = 1;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009030 }
9031 }
9032#endif
9033}
9034
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009035static void
9036optschanged(void)
9037{
9038#if DEBUG
9039 opentrace();
9040#endif
9041 setinteractive(iflag);
9042 setjobctl(mflag);
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009043#if ENABLE_FEATURE_EDITING_VI
9044 if (viflag)
9045 line_input_state->flags |= VI_MODE;
9046 else
9047 line_input_state->flags &= ~VI_MODE;
9048#else
9049 viflag = 0; /* forcibly keep the option off */
9050#endif
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009051}
9052
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009053static struct localvar *localvars;
9054
9055/*
9056 * Called after a function returns.
9057 * Interrupts must be off.
9058 */
9059static void
9060poplocalvars(void)
9061{
9062 struct localvar *lvp;
9063 struct var *vp;
9064
9065 while ((lvp = localvars) != NULL) {
9066 localvars = lvp->next;
9067 vp = lvp->vp;
Denys Vlasenkob563f622010-09-25 17:15:13 +02009068 TRACE(("poplocalvar %s\n", vp ? vp->var_text : "-"));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009069 if (vp == NULL) { /* $- saved */
9070 memcpy(optlist, lvp->text, sizeof(optlist));
9071 free((char*)lvp->text);
9072 optschanged();
9073 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009074 unsetvar(vp->var_text);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009075 } else {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009076 if (vp->var_func)
9077 vp->var_func(var_end(lvp->text));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009078 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009079 free((char*)vp->var_text);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009080 vp->flags = lvp->flags;
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009081 vp->var_text = lvp->text;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009082 }
9083 free(lvp);
9084 }
9085}
9086
9087static int
9088evalfun(struct funcnode *func, int argc, char **argv, int flags)
9089{
9090 volatile struct shparam saveparam;
9091 struct localvar *volatile savelocalvars;
9092 struct jmploc *volatile savehandler;
9093 struct jmploc jmploc;
9094 int e;
9095
9096 saveparam = shellparam;
9097 savelocalvars = localvars;
Denys Vlasenkoa2d121c2016-09-30 11:30:11 +02009098 savehandler = exception_handler;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009099 e = setjmp(jmploc.loc);
9100 if (e) {
9101 goto funcdone;
9102 }
9103 INT_OFF;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009104 exception_handler = &jmploc;
9105 localvars = NULL;
Denis Vlasenko01631112007-12-16 17:20:38 +00009106 shellparam.malloced = 0;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009107 func->count++;
9108 funcnest++;
9109 INT_ON;
9110 shellparam.nparam = argc - 1;
9111 shellparam.p = argv + 1;
9112#if ENABLE_ASH_GETOPTS
9113 shellparam.optind = 1;
9114 shellparam.optoff = -1;
9115#endif
Denys Vlasenko7aec8682016-10-25 20:26:02 +02009116 evaltree(func->n.narg.next, flags & EV_TESTED);
Denis Vlasenko01631112007-12-16 17:20:38 +00009117 funcdone:
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009118 INT_OFF;
9119 funcnest--;
9120 freefunc(func);
9121 poplocalvars();
9122 localvars = savelocalvars;
9123 freeparam(&shellparam);
9124 shellparam = saveparam;
9125 exception_handler = savehandler;
9126 INT_ON;
9127 evalskip &= ~SKIPFUNC;
9128 return e;
9129}
9130
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009131/*
9132 * Make a variable a local variable. When a variable is made local, it's
9133 * value and flags are saved in a localvar structure. The saved values
9134 * will be restored when the shell function returns. We handle the name
Denys Vlasenkoe0a4e102015-05-13 02:20:14 +02009135 * "-" as a special case: it makes changes to "set +-options" local
9136 * (options will be restored on return from the function).
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009137 */
9138static void
9139mklocal(char *name)
9140{
9141 struct localvar *lvp;
9142 struct var **vpp;
9143 struct var *vp;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009144 char *eq = strchr(name, '=');
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009145
9146 INT_OFF;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009147 /* Cater for duplicate "local". Examples:
9148 * x=0; f() { local x=1; echo $x; local x; echo $x; }; f; echo $x
9149 * x=0; f() { local x=1; echo $x; local x=2; echo $x; }; f; echo $x
9150 */
9151 lvp = localvars;
9152 while (lvp) {
Eugene Rudoy1285aa62015-04-26 23:32:00 +02009153 if (lvp->vp && varcmp(lvp->vp->var_text, name) == 0) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009154 if (eq)
9155 setvareq(name, 0);
9156 /* else:
9157 * it's a duplicate "local VAR" declaration, do nothing
9158 */
Denys Vlasenko06b11492016-11-04 16:43:18 +01009159 goto ret;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009160 }
9161 lvp = lvp->next;
9162 }
9163
9164 lvp = ckzalloc(sizeof(*lvp));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009165 if (LONE_DASH(name)) {
9166 char *p;
9167 p = ckmalloc(sizeof(optlist));
9168 lvp->text = memcpy(p, optlist, sizeof(optlist));
9169 vp = NULL;
9170 } else {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009171 vpp = hashvar(name);
9172 vp = *findvar(vpp, name);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009173 if (vp == NULL) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009174 /* variable did not exist yet */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009175 if (eq)
9176 setvareq(name, VSTRFIXED);
9177 else
9178 setvar(name, NULL, VSTRFIXED);
9179 vp = *vpp; /* the new variable */
9180 lvp->flags = VUNSET;
9181 } else {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009182 lvp->text = vp->var_text;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009183 lvp->flags = vp->flags;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009184 /* make sure neither "struct var" nor string gets freed
9185 * during (un)setting:
9186 */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009187 vp->flags |= VSTRFIXED|VTEXTFIXED;
9188 if (eq)
9189 setvareq(name, 0);
Denys Vlasenko109ee5d2014-03-16 18:41:11 +01009190 else
9191 /* "local VAR" unsets VAR: */
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009192 setvar0(name, NULL);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009193 }
9194 }
9195 lvp->vp = vp;
9196 lvp->next = localvars;
9197 localvars = lvp;
Denys Vlasenko06b11492016-11-04 16:43:18 +01009198 ret:
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009199 INT_ON;
9200}
9201
9202/*
9203 * The "local" command.
9204 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009205static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009206localcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009207{
9208 char *name;
9209
Ron Yorstonef2386b2015-10-29 16:19:14 +00009210 if (!funcnest)
9211 ash_msg_and_raise_error("not in a function");
9212
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009213 argv = argptr;
9214 while ((name = *argv++) != NULL) {
9215 mklocal(name);
9216 }
9217 return 0;
9218}
9219
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009220static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009221falsecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009222{
9223 return 1;
9224}
9225
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009226static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009227truecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009228{
9229 return 0;
9230}
9231
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009232static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009233execcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009234{
Denis Vlasenko68404f12008-03-17 09:00:54 +00009235 if (argv[1]) {
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009236 iflag = 0; /* exit on error */
9237 mflag = 0;
9238 optschanged();
Denys Vlasenkoe5814a52016-07-16 18:33:55 +02009239 /* We should set up signals for "exec CMD"
9240 * the same way as for "CMD" without "exec".
9241 * But optschanged->setinteractive->setsignal
9242 * still thought we are a root shell. Therefore, for example,
9243 * SIGQUIT is still set to IGN. Fix it:
9244 */
9245 shlvl++;
9246 setsignal(SIGQUIT);
9247 /*setsignal(SIGTERM); - unnecessary because of iflag=0 */
9248 /*setsignal(SIGTSTP); - unnecessary because of mflag=0 */
9249 /*setsignal(SIGTTOU); - unnecessary because of mflag=0 */
9250
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009251 shellexec(argv + 1, pathval(), 0);
Denys Vlasenkoe5814a52016-07-16 18:33:55 +02009252 /* NOTREACHED */
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009253 }
9254 return 0;
9255}
9256
9257/*
9258 * The return command.
9259 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009260static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009261returncmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009262{
9263 /*
9264 * If called outside a function, do what ksh does;
9265 * skip the rest of the file.
9266 */
Denys Vlasenko6a0710e2016-09-30 14:18:34 +02009267 evalskip = SKIPFUNC;
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009268 return argv[1] ? number(argv[1]) : exitstatus;
9269}
9270
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009271/* Forward declarations for builtintab[] */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009272static int breakcmd(int, char **) FAST_FUNC;
9273static int dotcmd(int, char **) FAST_FUNC;
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009274static int evalcmd(int, char **, int) FAST_FUNC;
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009275static int exitcmd(int, char **) FAST_FUNC;
9276static int exportcmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009277#if ENABLE_ASH_GETOPTS
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009278static int getoptscmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009279#endif
Denys Vlasenko2ec34962014-09-08 16:52:39 +02009280#if ENABLE_ASH_HELP
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009281static int helpcmd(int, char **) FAST_FUNC;
Denis Vlasenko52764022007-02-24 13:42:56 +00009282#endif
Flemming Madsend96ffda2013-04-07 18:47:24 +02009283#if MAX_HISTORY
9284static int historycmd(int, char **) FAST_FUNC;
9285#endif
Denys Vlasenko0b883582016-12-23 16:49:07 +01009286#if ENABLE_FEATURE_SH_MATH
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009287static int letcmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009288#endif
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009289static int readcmd(int, char **) FAST_FUNC;
9290static int setcmd(int, char **) FAST_FUNC;
9291static int shiftcmd(int, char **) FAST_FUNC;
9292static int timescmd(int, char **) FAST_FUNC;
9293static int trapcmd(int, char **) FAST_FUNC;
9294static int umaskcmd(int, char **) FAST_FUNC;
9295static int unsetcmd(int, char **) FAST_FUNC;
9296static int ulimitcmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009297
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009298#define BUILTIN_NOSPEC "0"
9299#define BUILTIN_SPECIAL "1"
9300#define BUILTIN_REGULAR "2"
9301#define BUILTIN_SPEC_REG "3"
9302#define BUILTIN_ASSIGN "4"
9303#define BUILTIN_SPEC_ASSG "5"
9304#define BUILTIN_REG_ASSG "6"
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009305#define BUILTIN_SPEC_REG_ASSG "7"
9306
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009307/* Stubs for calling non-FAST_FUNC's */
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009308#if ENABLE_ASH_BUILTIN_ECHO
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009309static int FAST_FUNC echocmd(int argc, char **argv) { return echo_main(argc, argv); }
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009310#endif
9311#if ENABLE_ASH_BUILTIN_PRINTF
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009312static int FAST_FUNC printfcmd(int argc, char **argv) { return printf_main(argc, argv); }
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009313#endif
9314#if ENABLE_ASH_BUILTIN_TEST
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009315static int FAST_FUNC testcmd(int argc, char **argv) { return test_main(argc, argv); }
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009316#endif
Denis Vlasenko468aea22008-04-01 14:47:57 +00009317
Denis Vlasenkof7d56652008-03-25 05:51:41 +00009318/* Keep these in proper order since it is searched via bsearch() */
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009319static const struct builtincmd builtintab[] = {
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009320 { BUILTIN_SPEC_REG "." , dotcmd },
9321 { BUILTIN_SPEC_REG ":" , truecmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009322#if ENABLE_ASH_BUILTIN_TEST
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009323 { BUILTIN_REGULAR "[" , testcmd },
Denys Vlasenko15fb91c2016-11-23 18:31:48 +01009324# if ENABLE_ASH_BASH_COMPAT
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009325 { BUILTIN_REGULAR "[[" , testcmd },
Denys Vlasenko15fb91c2016-11-23 18:31:48 +01009326# endif
Denis Vlasenko80591b02008-03-25 07:49:43 +00009327#endif
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009328#if ENABLE_ASH_ALIAS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009329 { BUILTIN_REG_ASSG "alias" , aliascmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009330#endif
9331#if JOBS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009332 { BUILTIN_REGULAR "bg" , fg_bgcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009333#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009334 { BUILTIN_SPEC_REG "break" , breakcmd },
9335 { BUILTIN_REGULAR "cd" , cdcmd },
9336 { BUILTIN_NOSPEC "chdir" , cdcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009337#if ENABLE_ASH_CMDCMD
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009338 { BUILTIN_REGULAR "command" , commandcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009339#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009340 { BUILTIN_SPEC_REG "continue", breakcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009341#if ENABLE_ASH_BUILTIN_ECHO
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009342 { BUILTIN_REGULAR "echo" , echocmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009343#endif
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009344 { BUILTIN_SPEC_REG "eval" , NULL }, /*evalcmd() has a differing prototype*/
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009345 { BUILTIN_SPEC_REG "exec" , execcmd },
9346 { BUILTIN_SPEC_REG "exit" , exitcmd },
9347 { BUILTIN_SPEC_REG_ASSG "export" , exportcmd },
9348 { BUILTIN_REGULAR "false" , falsecmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009349#if JOBS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009350 { BUILTIN_REGULAR "fg" , fg_bgcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009351#endif
9352#if ENABLE_ASH_GETOPTS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009353 { BUILTIN_REGULAR "getopts" , getoptscmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009354#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009355 { BUILTIN_NOSPEC "hash" , hashcmd },
Denys Vlasenko2ec34962014-09-08 16:52:39 +02009356#if ENABLE_ASH_HELP
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009357 { BUILTIN_NOSPEC "help" , helpcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009358#endif
Flemming Madsend96ffda2013-04-07 18:47:24 +02009359#if MAX_HISTORY
9360 { BUILTIN_NOSPEC "history" , historycmd },
9361#endif
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009362#if JOBS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009363 { BUILTIN_REGULAR "jobs" , jobscmd },
9364 { BUILTIN_REGULAR "kill" , killcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009365#endif
Denys Vlasenko0b883582016-12-23 16:49:07 +01009366#if ENABLE_FEATURE_SH_MATH
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009367 { BUILTIN_NOSPEC "let" , letcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009368#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009369 { BUILTIN_ASSIGN "local" , localcmd },
Denis Vlasenkocd2663f2008-06-01 22:36:39 +00009370#if ENABLE_ASH_BUILTIN_PRINTF
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009371 { BUILTIN_REGULAR "printf" , printfcmd },
Denis Vlasenkocd2663f2008-06-01 22:36:39 +00009372#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009373 { BUILTIN_NOSPEC "pwd" , pwdcmd },
9374 { BUILTIN_REGULAR "read" , readcmd },
9375 { BUILTIN_SPEC_REG_ASSG "readonly", exportcmd },
9376 { BUILTIN_SPEC_REG "return" , returncmd },
9377 { BUILTIN_SPEC_REG "set" , setcmd },
9378 { BUILTIN_SPEC_REG "shift" , shiftcmd },
Denys Vlasenko82731b42010-05-17 17:49:52 +02009379#if ENABLE_ASH_BASH_COMPAT
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009380 { BUILTIN_SPEC_REG "source" , dotcmd },
Denys Vlasenko82731b42010-05-17 17:49:52 +02009381#endif
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009382#if ENABLE_ASH_BUILTIN_TEST
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009383 { BUILTIN_REGULAR "test" , testcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009384#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009385 { BUILTIN_SPEC_REG "times" , timescmd },
9386 { BUILTIN_SPEC_REG "trap" , trapcmd },
9387 { BUILTIN_REGULAR "true" , truecmd },
9388 { BUILTIN_NOSPEC "type" , typecmd },
9389 { BUILTIN_NOSPEC "ulimit" , ulimitcmd },
9390 { BUILTIN_REGULAR "umask" , umaskcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009391#if ENABLE_ASH_ALIAS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009392 { BUILTIN_REGULAR "unalias" , unaliascmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009393#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009394 { BUILTIN_SPEC_REG "unset" , unsetcmd },
9395 { BUILTIN_REGULAR "wait" , waitcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009396};
9397
Denis Vlasenko80591b02008-03-25 07:49:43 +00009398/* Should match the above table! */
9399#define COMMANDCMD (builtintab + \
Denys Vlasenko928e2a72016-09-29 00:30:31 +02009400 /* . : */ 2 + \
9401 /* [ */ 1 * ENABLE_ASH_BUILTIN_TEST + \
9402 /* [[ */ 1 * ENABLE_ASH_BUILTIN_TEST * ENABLE_ASH_BASH_COMPAT + \
9403 /* alias */ 1 * ENABLE_ASH_ALIAS + \
9404 /* bg */ 1 * ENABLE_ASH_JOB_CONTROL + \
9405 /* break cd cddir */ 3)
9406#define EVALCMD (COMMANDCMD + \
9407 /* command */ 1 * ENABLE_ASH_CMDCMD + \
9408 /* continue */ 1 + \
9409 /* echo */ 1 * ENABLE_ASH_BUILTIN_ECHO + \
9410 0)
9411#define EXECCMD (EVALCMD + \
9412 /* eval */ 1)
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009413
9414/*
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009415 * Search the table of builtin commands.
9416 */
Denys Vlasenko888527c2016-10-02 16:54:17 +02009417static int
9418pstrcmp1(const void *a, const void *b)
9419{
9420 return strcmp((char*)a, *(char**)b + 1);
9421}
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009422static struct builtincmd *
9423find_builtin(const char *name)
9424{
9425 struct builtincmd *bp;
9426
9427 bp = bsearch(
Denis Vlasenko80b8b392007-06-25 10:55:35 +00009428 name, builtintab, ARRAY_SIZE(builtintab), sizeof(builtintab[0]),
Denys Vlasenko888527c2016-10-02 16:54:17 +02009429 pstrcmp1
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009430 );
9431 return bp;
9432}
9433
9434/*
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009435 * Execute a simple command.
9436 */
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009437static int
9438isassignment(const char *p)
Paul Foxc3850c82005-07-20 18:23:39 +00009439{
9440 const char *q = endofname(p);
9441 if (p == q)
9442 return 0;
9443 return *q == '=';
9444}
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009445static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009446bltincmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009447{
9448 /* Preserve exitstatus of a previous possible redirection
9449 * as POSIX mandates */
9450 return back_exitstatus;
9451}
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009452static int
Eric Andersenc470f442003-07-28 09:56:35 +00009453evalcommand(union node *cmd, int flags)
9454{
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00009455 static const struct builtincmd null_bltin = {
9456 "\0\0", bltincmd /* why three NULs? */
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009457 };
Eric Andersenc470f442003-07-28 09:56:35 +00009458 struct stackmark smark;
9459 union node *argp;
9460 struct arglist arglist;
9461 struct arglist varlist;
9462 char **argv;
9463 int argc;
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009464 const struct strlist *sp;
Eric Andersenc470f442003-07-28 09:56:35 +00009465 struct cmdentry cmdentry;
9466 struct job *jp;
9467 char *lastarg;
9468 const char *path;
9469 int spclbltin;
Eric Andersenc470f442003-07-28 09:56:35 +00009470 int status;
9471 char **nargv;
Paul Foxc3850c82005-07-20 18:23:39 +00009472 struct builtincmd *bcmd;
Denis Vlasenko34c73c42008-08-16 11:48:02 +00009473 smallint cmd_is_exec;
9474 smallint pseudovarflag = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00009475
9476 /* First expand the arguments. */
9477 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
9478 setstackmark(&smark);
9479 back_exitstatus = 0;
9480
9481 cmdentry.cmdtype = CMDBUILTIN;
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00009482 cmdentry.u.cmd = &null_bltin;
Eric Andersenc470f442003-07-28 09:56:35 +00009483 varlist.lastp = &varlist.list;
9484 *varlist.lastp = NULL;
9485 arglist.lastp = &arglist.list;
9486 *arglist.lastp = NULL;
9487
9488 argc = 0;
Denis Vlasenkob012b102007-02-19 22:43:01 +00009489 if (cmd->ncmd.args) {
Paul Foxc3850c82005-07-20 18:23:39 +00009490 bcmd = find_builtin(cmd->ncmd.args->narg.text);
9491 pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd);
9492 }
9493
Eric Andersenc470f442003-07-28 09:56:35 +00009494 for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) {
9495 struct strlist **spp;
9496
9497 spp = arglist.lastp;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00009498 if (pseudovarflag && isassignment(argp->narg.text))
Paul Foxc3850c82005-07-20 18:23:39 +00009499 expandarg(argp, &arglist, EXP_VARTILDE);
9500 else
9501 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
9502
Eric Andersenc470f442003-07-28 09:56:35 +00009503 for (sp = *spp; sp; sp = sp->next)
9504 argc++;
9505 }
9506
Denys Vlasenko65a8b852016-10-26 22:29:11 +02009507 /* Reserve one extra spot at the front for shellexec. */
9508 nargv = stalloc(sizeof(char *) * (argc + 2));
9509 argv = ++nargv;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009510 for (sp = arglist.list; sp; sp = sp->next) {
Eric Andersenc470f442003-07-28 09:56:35 +00009511 TRACE(("evalcommand arg: %s\n", sp->text));
9512 *nargv++ = sp->text;
9513 }
9514 *nargv = NULL;
9515
9516 lastarg = NULL;
9517 if (iflag && funcnest == 0 && argc > 0)
9518 lastarg = nargv[-1];
9519
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009520 preverrout_fd = 2;
Eric Andersenc470f442003-07-28 09:56:35 +00009521 expredir(cmd->ncmd.redirect);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009522 status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH | REDIR_SAVEFD2);
Eric Andersenc470f442003-07-28 09:56:35 +00009523
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009524 path = vpath.var_text;
Eric Andersenc470f442003-07-28 09:56:35 +00009525 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
9526 struct strlist **spp;
9527 char *p;
9528
9529 spp = varlist.lastp;
9530 expandarg(argp, &varlist, EXP_VARTILDE);
9531
9532 /*
9533 * Modify the command lookup path, if a PATH= assignment
9534 * is present
9535 */
9536 p = (*spp)->text;
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009537 if (varcmp(p, path) == 0)
Eric Andersenc470f442003-07-28 09:56:35 +00009538 path = p;
9539 }
9540
9541 /* Print the command if xflag is set. */
9542 if (xflag) {
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009543 int n;
Denys Vlasenkofd33e172010-06-26 22:55:44 +02009544 const char *p = " %s" + 1;
Eric Andersenc470f442003-07-28 09:56:35 +00009545
Denis Vlasenko0de37e12007-10-17 11:08:53 +00009546 fdprintf(preverrout_fd, p, expandstr(ps4val()));
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009547 sp = varlist.list;
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +00009548 for (n = 0; n < 2; n++) {
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009549 while (sp) {
Denis Vlasenko0de37e12007-10-17 11:08:53 +00009550 fdprintf(preverrout_fd, p, sp->text);
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009551 sp = sp->next;
Denys Vlasenkofd33e172010-06-26 22:55:44 +02009552 p = " %s";
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009553 }
9554 sp = arglist.list;
9555 }
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00009556 safe_write(preverrout_fd, "\n", 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009557 }
9558
9559 cmd_is_exec = 0;
9560 spclbltin = -1;
9561
9562 /* Now locate the command. */
9563 if (argc) {
Eric Andersenc470f442003-07-28 09:56:35 +00009564 int cmd_flag = DO_ERR;
Denys Vlasenko0b4980c2012-09-25 12:49:29 +02009565#if ENABLE_ASH_CMDCMD
9566 const char *oldpath = path + 5;
9567#endif
Eric Andersenc470f442003-07-28 09:56:35 +00009568 path += 5;
Eric Andersenc470f442003-07-28 09:56:35 +00009569 for (;;) {
9570 find_command(argv[0], &cmdentry, cmd_flag, path);
9571 if (cmdentry.cmdtype == CMDUNKNOWN) {
Denys Vlasenko8131eea2009-11-02 14:19:51 +01009572 flush_stdout_stderr();
Denis Vlasenko6514c5e2008-07-24 13:41:37 +00009573 status = 127;
Eric Andersenc470f442003-07-28 09:56:35 +00009574 goto bail;
9575 }
9576
9577 /* implement bltin and command here */
9578 if (cmdentry.cmdtype != CMDBUILTIN)
9579 break;
9580 if (spclbltin < 0)
9581 spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd);
9582 if (cmdentry.u.cmd == EXECCMD)
Denis Vlasenko34c73c42008-08-16 11:48:02 +00009583 cmd_is_exec = 1;
Denis Vlasenko131ae172007-02-18 13:00:19 +00009584#if ENABLE_ASH_CMDCMD
Eric Andersenc470f442003-07-28 09:56:35 +00009585 if (cmdentry.u.cmd == COMMANDCMD) {
Eric Andersenc470f442003-07-28 09:56:35 +00009586 path = oldpath;
9587 nargv = parse_command_args(argv, &path);
9588 if (!nargv)
9589 break;
Denys Vlasenkocac4d002016-10-01 03:02:25 +02009590 /* It's "command [-p] PROG ARGS" (that is, no -Vv).
9591 * nargv => "PROG". path is updated if -p.
9592 */
Eric Andersenc470f442003-07-28 09:56:35 +00009593 argc -= nargv - argv;
9594 argv = nargv;
9595 cmd_flag |= DO_NOFUNC;
9596 } else
9597#endif
9598 break;
9599 }
9600 }
9601
9602 if (status) {
Ron Yorstonea7d2f62017-01-03 11:18:23 +01009603 bail:
9604 exitstatus = status;
9605
Eric Andersenc470f442003-07-28 09:56:35 +00009606 /* We have a redirection error. */
9607 if (spclbltin > 0)
Denis Vlasenkob012b102007-02-19 22:43:01 +00009608 raise_exception(EXERROR);
Ron Yorstonea7d2f62017-01-03 11:18:23 +01009609
Eric Andersenc470f442003-07-28 09:56:35 +00009610 goto out;
9611 }
9612
9613 /* Execute the command. */
9614 switch (cmdentry.cmdtype) {
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009615 default: {
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +00009616
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009617#if ENABLE_FEATURE_SH_NOFORK
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009618/* (1) BUG: if variables are set, we need to fork, or save/restore them
9619 * around run_nofork_applet() call.
9620 * (2) Should this check also be done in forkshell()?
9621 * (perhaps it should, so that "VAR=VAL nofork" at least avoids exec...)
9622 */
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00009623 /* find_command() encodes applet_no as (-2 - applet_no) */
9624 int applet_no = (- cmdentry.u.index - 2);
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009625 if (applet_no >= 0 && APPLET_IS_NOFORK(applet_no)) {
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009626 listsetvar(varlist.list, VEXPORT|VSTACK);
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00009627 /* run <applet>_main() */
Ron Yorston5ccb0e92016-10-20 12:24:02 +01009628 status = run_nofork_applet(applet_no, argv);
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009629 break;
9630 }
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009631#endif
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009632 /* Can we avoid forking off? For example, very last command
9633 * in a script or a subshell does not need forking,
9634 * we can just exec it.
9635 */
Denys Vlasenko238bf182010-05-18 15:49:07 +02009636 if (!(flags & EV_EXIT) || may_have_traps) {
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009637 /* No, forking off a child is necessary */
Denis Vlasenkob012b102007-02-19 22:43:01 +00009638 INT_OFF;
Denis Vlasenko68404f12008-03-17 09:00:54 +00009639 jp = makejob(/*cmd,*/ 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009640 if (forkshell(jp, cmd, FORK_FG) != 0) {
Denys Vlasenko238bf182010-05-18 15:49:07 +02009641 /* parent */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009642 status = waitforjob(jp);
Denis Vlasenkob012b102007-02-19 22:43:01 +00009643 INT_ON;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009644 TRACE(("forked child exited with %d\n", status));
Eric Andersenc470f442003-07-28 09:56:35 +00009645 break;
9646 }
Denys Vlasenko238bf182010-05-18 15:49:07 +02009647 /* child */
Denis Vlasenkob012b102007-02-19 22:43:01 +00009648 FORCE_INT_ON;
Denys Vlasenkoc7f95d22010-05-18 15:52:23 +02009649 /* fall through to exec'ing external program */
Eric Andersenc470f442003-07-28 09:56:35 +00009650 }
9651 listsetvar(varlist.list, VEXPORT|VSTACK);
9652 shellexec(argv, path, cmdentry.u.index);
9653 /* NOTREACHED */
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009654 } /* default */
Eric Andersenc470f442003-07-28 09:56:35 +00009655 case CMDBUILTIN:
9656 cmdenviron = varlist.list;
9657 if (cmdenviron) {
9658 struct strlist *list = cmdenviron;
9659 int i = VNOSET;
9660 if (spclbltin > 0 || argc == 0) {
9661 i = 0;
9662 if (cmd_is_exec && argc > 1)
9663 i = VEXPORT;
9664 }
9665 listsetvar(list, i);
9666 }
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +00009667 /* Tight loop with builtins only:
9668 * "while kill -0 $child; do true; done"
9669 * will never exit even if $child died, unless we do this
9670 * to reap the zombie and make kill detect that it's gone: */
9671 dowait(DOWAIT_NONBLOCK, NULL);
9672
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009673 if (evalbltin(cmdentry.u.cmd, argc, argv, flags)) {
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02009674 if (exception_type == EXERROR && spclbltin <= 0) {
9675 FORCE_INT_ON;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +02009676 goto readstatus;
Eric Andersenc470f442003-07-28 09:56:35 +00009677 }
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02009678 raise:
9679 longjmp(exception_handler->loc, 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009680 }
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009681 goto readstatus;
Eric Andersenc470f442003-07-28 09:56:35 +00009682
9683 case CMDFUNCTION:
9684 listsetvar(varlist.list, 0);
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +00009685 /* See above for the rationale */
9686 dowait(DOWAIT_NONBLOCK, NULL);
Eric Andersenc470f442003-07-28 09:56:35 +00009687 if (evalfun(cmdentry.u.func, argc, argv, flags))
9688 goto raise;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009689 readstatus:
9690 status = exitstatus;
Eric Andersenc470f442003-07-28 09:56:35 +00009691 break;
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009692 } /* switch */
Eric Andersenc470f442003-07-28 09:56:35 +00009693
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009694 out:
Denys Vlasenkoeaf94362016-10-25 21:46:03 +02009695 if (cmd->ncmd.redirect)
9696 popredir(/*drop:*/ cmd_is_exec, /*restore:*/ cmd_is_exec);
Denis Vlasenko6514c5e2008-07-24 13:41:37 +00009697 if (lastarg) {
Eric Andersenc470f442003-07-28 09:56:35 +00009698 /* dsl: I think this is intended to be used to support
9699 * '_' in 'vi' command mode during line editing...
9700 * However I implemented that within libedit itself.
9701 */
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009702 setvar0("_", lastarg);
Denis Vlasenko6514c5e2008-07-24 13:41:37 +00009703 }
Eric Andersenc470f442003-07-28 09:56:35 +00009704 popstackmark(&smark);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009705
9706 return status;
Eric Andersenc470f442003-07-28 09:56:35 +00009707}
9708
9709static int
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009710evalbltin(const struct builtincmd *cmd, int argc, char **argv, int flags)
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009711{
Eric Andersenc470f442003-07-28 09:56:35 +00009712 char *volatile savecmdname;
9713 struct jmploc *volatile savehandler;
9714 struct jmploc jmploc;
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009715 int status;
Eric Andersenc470f442003-07-28 09:56:35 +00009716 int i;
9717
9718 savecmdname = commandname;
Denys Vlasenkoa2d121c2016-09-30 11:30:11 +02009719 savehandler = exception_handler;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009720 i = setjmp(jmploc.loc);
9721 if (i)
Eric Andersenc470f442003-07-28 09:56:35 +00009722 goto cmddone;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009723 exception_handler = &jmploc;
Eric Andersenc470f442003-07-28 09:56:35 +00009724 commandname = argv[0];
9725 argptr = argv + 1;
9726 optptr = NULL; /* initialize nextopt */
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009727 if (cmd == EVALCMD)
9728 status = evalcmd(argc, argv, flags);
9729 else
9730 status = (*cmd->builtin)(argc, argv);
Denis Vlasenkob012b102007-02-19 22:43:01 +00009731 flush_stdout_stderr();
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009732 status |= ferror(stdout);
9733 exitstatus = status;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009734 cmddone:
Rob Landleyf296f0b2006-07-06 01:09:21 +00009735 clearerr(stdout);
Eric Andersenc470f442003-07-28 09:56:35 +00009736 commandname = savecmdname;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009737 exception_handler = savehandler;
Eric Andersenc470f442003-07-28 09:56:35 +00009738
9739 return i;
9740}
9741
Denis Vlasenkoaa744452007-02-23 01:04:22 +00009742static int
9743goodname(const char *p)
Glenn L McGrath16e45d72004-02-04 08:24:39 +00009744{
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02009745 return endofname(p)[0] == '\0';
Glenn L McGrath16e45d72004-02-04 08:24:39 +00009746}
9747
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009748
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009749/*
9750 * Search for a command. This is called before we fork so that the
9751 * location of the command will be available in the parent as well as
Glenn L McGrath16e45d72004-02-04 08:24:39 +00009752 * the child. The check for "goodname" is an overly conservative
9753 * check that the name will not be subject to expansion.
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009754 */
Eric Andersenc470f442003-07-28 09:56:35 +00009755static void
9756prehash(union node *n)
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009757{
9758 struct cmdentry entry;
9759
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +00009760 if (n->type == NCMD && n->ncmd.args && goodname(n->ncmd.args->narg.text))
9761 find_command(n->ncmd.args->narg.text, &entry, 0, pathval());
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009762}
9763
Eric Andersencb57d552001-06-28 07:25:16 +00009764
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009765/* ============ Builtin commands
9766 *
9767 * Builtin commands whose functions are closely tied to evaluation
9768 * are implemented here.
Eric Andersencb57d552001-06-28 07:25:16 +00009769 */
9770
9771/*
Eric Andersencb57d552001-06-28 07:25:16 +00009772 * Handle break and continue commands. Break, continue, and return are
9773 * all handled by setting the evalskip flag. The evaluation routines
9774 * above all check this flag, and if it is set they start skipping
9775 * commands rather than executing them. The variable skipcount is
9776 * the number of loops to break/continue, or the number of function
9777 * levels to return. (The latter is always 1.) It should probably
9778 * be an error to break out of more loops than exist, but it isn't
9779 * in the standard shell so we don't make it one here.
9780 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009781static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009782breakcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00009783{
Denis Vlasenko68404f12008-03-17 09:00:54 +00009784 int n = argv[1] ? number(argv[1]) : 1;
Eric Andersencb57d552001-06-28 07:25:16 +00009785
Aaron Lehmann2aef3a62001-12-31 06:03:12 +00009786 if (n <= 0)
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02009787 ash_msg_and_raise_error(msg_illnum, argv[1]);
Eric Andersencb57d552001-06-28 07:25:16 +00009788 if (n > loopnest)
9789 n = loopnest;
9790 if (n > 0) {
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009791 evalskip = (**argv == 'c') ? SKIPCONT : SKIPBREAK;
Eric Andersencb57d552001-06-28 07:25:16 +00009792 skipcount = n;
9793 }
9794 return 0;
9795}
9796
Eric Andersenc470f442003-07-28 09:56:35 +00009797
Denys Vlasenko70392332016-10-27 02:31:55 +02009798/*
Eric Andersen90898442003-08-06 11:20:52 +00009799 * This implements the input routines used by the parser.
Eric Andersencb57d552001-06-28 07:25:16 +00009800 */
Denis Vlasenko99eb8502007-02-23 21:09:49 +00009801
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009802enum {
9803 INPUT_PUSH_FILE = 1,
9804 INPUT_NOFILE_OK = 2,
9805};
Eric Andersencb57d552001-06-28 07:25:16 +00009806
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009807static smallint checkkwd;
Denis Vlasenko99eb8502007-02-23 21:09:49 +00009808/* values of checkkwd variable */
9809#define CHKALIAS 0x1
9810#define CHKKWD 0x2
9811#define CHKNL 0x4
9812
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009813/*
9814 * Push a string back onto the input at this current parsefile level.
9815 * We handle aliases this way.
9816 */
9817#if !ENABLE_ASH_ALIAS
9818#define pushstring(s, ap) pushstring(s)
9819#endif
9820static void
9821pushstring(char *s, struct alias *ap)
9822{
9823 struct strpush *sp;
9824 int len;
9825
9826 len = strlen(s);
9827 INT_OFF;
9828 if (g_parsefile->strpush) {
9829 sp = ckzalloc(sizeof(*sp));
9830 sp->prev = g_parsefile->strpush;
9831 } else {
9832 sp = &(g_parsefile->basestrpush);
9833 }
9834 g_parsefile->strpush = sp;
9835 sp->prev_string = g_parsefile->next_to_pgetc;
9836 sp->prev_left_in_line = g_parsefile->left_in_line;
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02009837 sp->unget = g_parsefile->unget;
9838 memcpy(sp->lastc, g_parsefile->lastc, sizeof(sp->lastc));
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009839#if ENABLE_ASH_ALIAS
9840 sp->ap = ap;
9841 if (ap) {
9842 ap->flag |= ALIASINUSE;
9843 sp->string = s;
9844 }
9845#endif
9846 g_parsefile->next_to_pgetc = s;
9847 g_parsefile->left_in_line = len;
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02009848 g_parsefile->unget = 0;
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009849 INT_ON;
9850}
9851
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009852static void
9853popstring(void)
Eric Andersenc470f442003-07-28 09:56:35 +00009854{
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009855 struct strpush *sp = g_parsefile->strpush;
Eric Andersenc470f442003-07-28 09:56:35 +00009856
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009857 INT_OFF;
Denis Vlasenko131ae172007-02-18 13:00:19 +00009858#if ENABLE_ASH_ALIAS
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009859 if (sp->ap) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009860 if (g_parsefile->next_to_pgetc[-1] == ' '
9861 || g_parsefile->next_to_pgetc[-1] == '\t'
9862 ) {
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009863 checkkwd |= CHKALIAS;
Glenn L McGrath28939ad2004-07-21 10:20:19 +00009864 }
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009865 if (sp->string != sp->ap->val) {
9866 free(sp->string);
9867 }
9868 sp->ap->flag &= ~ALIASINUSE;
9869 if (sp->ap->flag & ALIASDEAD) {
9870 unalias(sp->ap->name);
9871 }
Glenn L McGrath28939ad2004-07-21 10:20:19 +00009872 }
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00009873#endif
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009874 g_parsefile->next_to_pgetc = sp->prev_string;
9875 g_parsefile->left_in_line = sp->prev_left_in_line;
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02009876 g_parsefile->unget = sp->unget;
9877 memcpy(g_parsefile->lastc, sp->lastc, sizeof(sp->lastc));
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009878 g_parsefile->strpush = sp->prev;
9879 if (sp != &(g_parsefile->basestrpush))
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009880 free(sp);
9881 INT_ON;
9882}
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00009883
Denis Vlasenkoaa744452007-02-23 01:04:22 +00009884static int
9885preadfd(void)
Eric Andersencb57d552001-06-28 07:25:16 +00009886{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009887 int nr;
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00009888 char *buf = g_parsefile->buf;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009889
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009890 g_parsefile->next_to_pgetc = buf;
Denis Vlasenko38f63192007-01-22 09:03:07 +00009891#if ENABLE_FEATURE_EDITING
Denis Vlasenko85c24712008-03-17 09:04:04 +00009892 retry:
Denys Vlasenko79b3d422010-06-03 04:29:08 +02009893 if (!iflag || g_parsefile->pf_fd != STDIN_FILENO)
Ron Yorston61d6ae22015-04-19 10:50:25 +01009894 nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009895 else {
Denys Vlasenko66c5b122011-02-08 05:07:02 +01009896 int timeout = -1;
9897# if ENABLE_ASH_IDLE_TIMEOUT
9898 if (iflag) {
9899 const char *tmout_var = lookupvar("TMOUT");
9900 if (tmout_var) {
9901 timeout = atoi(tmout_var) * 1000;
9902 if (timeout <= 0)
9903 timeout = -1;
9904 }
9905 }
9906# endif
Denys Vlasenko8c52f802011-02-04 17:36:21 +01009907# if ENABLE_FEATURE_TAB_COMPLETION
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00009908 line_input_state->path_lookup = pathval();
Denys Vlasenko8c52f802011-02-04 17:36:21 +01009909# endif
Denys Vlasenkoe9ab07c2014-08-13 18:00:08 +02009910 reinit_unicode_for_ash();
Denys Vlasenko66c5b122011-02-08 05:07:02 +01009911 nr = read_line_input(line_input_state, cmdedit_prompt, buf, IBUFSIZ, timeout);
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00009912 if (nr == 0) {
Denys Vlasenko4b89d512016-11-25 03:41:03 +01009913 /* ^C pressed, "convert" to SIGINT */
9914 write(STDOUT_FILENO, "^C", 2);
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00009915 if (trap[SIGINT]) {
Glenn L McGrath16e45d72004-02-04 08:24:39 +00009916 buf[0] = '\n';
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00009917 buf[1] = '\0';
Glenn L McGrath16e45d72004-02-04 08:24:39 +00009918 raise(SIGINT);
9919 return 1;
9920 }
Denys Vlasenko8660aeb2016-11-24 17:44:02 +01009921 exitstatus = 128 + SIGINT;
Denys Vlasenko4b89d512016-11-25 03:41:03 +01009922 bb_putchar('\n');
Eric Andersenc470f442003-07-28 09:56:35 +00009923 goto retry;
9924 }
Denys Vlasenko66c5b122011-02-08 05:07:02 +01009925 if (nr < 0) {
9926 if (errno == 0) {
9927 /* Ctrl+D pressed */
9928 nr = 0;
9929 }
9930# if ENABLE_ASH_IDLE_TIMEOUT
9931 else if (errno == EAGAIN && timeout > 0) {
Denys Vlasenkod60752f2015-10-07 22:42:45 +02009932 puts("\007timed out waiting for input: auto-logout");
Denys Vlasenko66c5b122011-02-08 05:07:02 +01009933 exitshell();
9934 }
9935# endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009936 }
Eric Andersencb57d552001-06-28 07:25:16 +00009937 }
9938#else
Ron Yorston61d6ae22015-04-19 10:50:25 +01009939 nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1);
Eric Andersencb57d552001-06-28 07:25:16 +00009940#endif
9941
Denys Vlasenko80c5b682011-05-08 21:21:10 +02009942#if 0 /* disabled: nonblock_immune_read() handles this problem */
Eric Andersencb57d552001-06-28 07:25:16 +00009943 if (nr < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00009944 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
Denis Vlasenkod37f2222007-08-19 13:42:08 +00009945 int flags = fcntl(0, F_GETFL);
Denis Vlasenko9cb220b2007-12-09 10:03:28 +00009946 if (flags >= 0 && (flags & O_NONBLOCK)) {
9947 flags &= ~O_NONBLOCK;
Eric Andersencb57d552001-06-28 07:25:16 +00009948 if (fcntl(0, F_SETFL, flags) >= 0) {
9949 out2str("sh: turning off NDELAY mode\n");
9950 goto retry;
9951 }
9952 }
9953 }
9954 }
Denis Vlasenkoe376d452008-02-20 22:23:24 +00009955#endif
Eric Andersencb57d552001-06-28 07:25:16 +00009956 return nr;
9957}
9958
9959/*
9960 * Refill the input buffer and return the next input character:
9961 *
9962 * 1) If a string was pushed back on the input, pop it;
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009963 * 2) If an EOF was pushed back (g_parsefile->left_in_line < -BIGNUM)
9964 * or we are reading from a string so we can't refill the buffer,
9965 * return EOF.
Denys Vlasenko883cea42009-07-11 15:31:59 +02009966 * 3) If there is more stuff in this buffer, use it else call read to fill it.
Eric Andersencb57d552001-06-28 07:25:16 +00009967 * 4) Process input up to the next newline, deleting nul characters.
9968 */
Denis Vlasenko727752d2008-11-28 03:41:47 +00009969//#define pgetc_debug(...) bb_error_msg(__VA_ARGS__)
9970#define pgetc_debug(...) ((void)0)
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02009971static int pgetc(void);
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009972static int
Eric Andersenc470f442003-07-28 09:56:35 +00009973preadbuffer(void)
Eric Andersencb57d552001-06-28 07:25:16 +00009974{
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009975 char *q;
Eric Andersencb57d552001-06-28 07:25:16 +00009976 int more;
Eric Andersencb57d552001-06-28 07:25:16 +00009977
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02009978 if (g_parsefile->strpush) {
Denis Vlasenko131ae172007-02-18 13:00:19 +00009979#if ENABLE_ASH_ALIAS
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009980 if (g_parsefile->left_in_line == -1
9981 && g_parsefile->strpush->ap
9982 && g_parsefile->next_to_pgetc[-1] != ' '
9983 && g_parsefile->next_to_pgetc[-1] != '\t'
Denis Vlasenko16898402008-11-25 01:34:52 +00009984 ) {
Denis Vlasenko727752d2008-11-28 03:41:47 +00009985 pgetc_debug("preadbuffer PEOA");
Eric Andersencb57d552001-06-28 07:25:16 +00009986 return PEOA;
9987 }
Eric Andersen2870d962001-07-02 17:27:21 +00009988#endif
Eric Andersencb57d552001-06-28 07:25:16 +00009989 popstring();
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02009990 return pgetc();
Eric Andersencb57d552001-06-28 07:25:16 +00009991 }
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009992 /* on both branches above g_parsefile->left_in_line < 0.
Denis Vlasenko727752d2008-11-28 03:41:47 +00009993 * "pgetc" needs refilling.
9994 */
9995
Denis Vlasenkoe27dafd2008-11-28 04:01:03 +00009996 /* -90 is our -BIGNUM. Below we use -99 to mark "EOF on read",
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009997 * pungetc() may increment it a few times.
Denis Vlasenkoe27dafd2008-11-28 04:01:03 +00009998 * Assuming it won't increment it to less than -90.
Denis Vlasenko727752d2008-11-28 03:41:47 +00009999 */
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010000 if (g_parsefile->left_in_line < -90 || g_parsefile->buf == NULL) {
Denis Vlasenko727752d2008-11-28 03:41:47 +000010001 pgetc_debug("preadbuffer PEOF1");
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010002 /* even in failure keep left_in_line and next_to_pgetc
10003 * in lock step, for correct multi-layer pungetc.
10004 * left_in_line was decremented before preadbuffer(),
10005 * must inc next_to_pgetc: */
10006 g_parsefile->next_to_pgetc++;
Eric Andersencb57d552001-06-28 07:25:16 +000010007 return PEOF;
Denis Vlasenko727752d2008-11-28 03:41:47 +000010008 }
Eric Andersencb57d552001-06-28 07:25:16 +000010009
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010010 more = g_parsefile->left_in_buffer;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010011 if (more <= 0) {
Denis Vlasenko727752d2008-11-28 03:41:47 +000010012 flush_stdout_stderr();
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010013 again:
10014 more = preadfd();
10015 if (more <= 0) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010016 /* don't try reading again */
10017 g_parsefile->left_in_line = -99;
Denis Vlasenko727752d2008-11-28 03:41:47 +000010018 pgetc_debug("preadbuffer PEOF2");
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010019 g_parsefile->next_to_pgetc++;
Eric Andersencb57d552001-06-28 07:25:16 +000010020 return PEOF;
10021 }
10022 }
10023
Denis Vlasenko727752d2008-11-28 03:41:47 +000010024 /* Find out where's the end of line.
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010025 * Set g_parsefile->left_in_line
10026 * and g_parsefile->left_in_buffer acordingly.
Denis Vlasenko727752d2008-11-28 03:41:47 +000010027 * NUL chars are deleted.
10028 */
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010029 q = g_parsefile->next_to_pgetc;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010030 for (;;) {
Denis Vlasenko727752d2008-11-28 03:41:47 +000010031 char c;
Eric Andersencb57d552001-06-28 07:25:16 +000010032
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010033 more--;
Eric Andersenc470f442003-07-28 09:56:35 +000010034
Denis Vlasenko727752d2008-11-28 03:41:47 +000010035 c = *q;
10036 if (c == '\0') {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010037 memmove(q, q + 1, more);
Denis Vlasenko727752d2008-11-28 03:41:47 +000010038 } else {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010039 q++;
10040 if (c == '\n') {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010041 g_parsefile->left_in_line = q - g_parsefile->next_to_pgetc - 1;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010042 break;
10043 }
Eric Andersencb57d552001-06-28 07:25:16 +000010044 }
10045
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010046 if (more <= 0) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010047 g_parsefile->left_in_line = q - g_parsefile->next_to_pgetc - 1;
10048 if (g_parsefile->left_in_line < 0)
Eric Andersencb57d552001-06-28 07:25:16 +000010049 goto again;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010050 break;
Eric Andersencb57d552001-06-28 07:25:16 +000010051 }
10052 }
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010053 g_parsefile->left_in_buffer = more;
Eric Andersencb57d552001-06-28 07:25:16 +000010054
Eric Andersencb57d552001-06-28 07:25:16 +000010055 if (vflag) {
Denis Vlasenko727752d2008-11-28 03:41:47 +000010056 char save = *q;
10057 *q = '\0';
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010058 out2str(g_parsefile->next_to_pgetc);
Denis Vlasenko727752d2008-11-28 03:41:47 +000010059 *q = save;
Eric Andersencb57d552001-06-28 07:25:16 +000010060 }
10061
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010062 pgetc_debug("preadbuffer at %d:%p'%s'",
10063 g_parsefile->left_in_line,
10064 g_parsefile->next_to_pgetc,
10065 g_parsefile->next_to_pgetc);
Denys Vlasenkocd716832009-11-28 22:14:02 +010010066 return (unsigned char)*g_parsefile->next_to_pgetc++;
Eric Andersencb57d552001-06-28 07:25:16 +000010067}
10068
Denys Vlasenkoce332a22016-10-02 23:47:34 +020010069static void
10070nlprompt(void)
10071{
10072 g_parsefile->linno++;
10073 setprompt_if(doprompt, 2);
10074}
10075static void
10076nlnoprompt(void)
10077{
10078 g_parsefile->linno++;
10079 needprompt = doprompt;
10080}
10081
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010082static int
10083pgetc(void)
10084{
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010085 int c;
10086
10087 pgetc_debug("pgetc at %d:%p'%s'",
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010088 g_parsefile->left_in_line,
10089 g_parsefile->next_to_pgetc,
10090 g_parsefile->next_to_pgetc);
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010091 if (g_parsefile->unget)
10092 return g_parsefile->lastc[--g_parsefile->unget];
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010093
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010094 if (--g_parsefile->left_in_line >= 0)
Denys Vlasenko2fe66b12016-12-12 17:39:12 +010010095 c = (unsigned char)*g_parsefile->next_to_pgetc++;
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010096 else
10097 c = preadbuffer();
10098
10099 g_parsefile->lastc[1] = g_parsefile->lastc[0];
10100 g_parsefile->lastc[0] = c;
10101
10102 return c;
10103}
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010104
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010105#if ENABLE_ASH_ALIAS
10106static int
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010010107pgetc_without_PEOA(void)
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010108{
10109 int c;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010110 do {
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010111 pgetc_debug("pgetc at %d:%p'%s'",
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010112 g_parsefile->left_in_line,
10113 g_parsefile->next_to_pgetc,
10114 g_parsefile->next_to_pgetc);
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010115 c = pgetc();
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010116 } while (c == PEOA);
10117 return c;
10118}
10119#else
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010010120# define pgetc_without_PEOA() pgetc()
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010121#endif
10122
10123/*
10124 * Read a line from the script.
10125 */
10126static char *
10127pfgets(char *line, int len)
10128{
10129 char *p = line;
10130 int nleft = len;
10131 int c;
10132
10133 while (--nleft > 0) {
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010010134 c = pgetc_without_PEOA();
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010135 if (c == PEOF) {
10136 if (p == line)
10137 return NULL;
10138 break;
10139 }
10140 *p++ = c;
10141 if (c == '\n')
10142 break;
10143 }
10144 *p = '\0';
10145 return line;
10146}
10147
Eric Andersenc470f442003-07-28 09:56:35 +000010148/*
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010149 * Undo a call to pgetc. Only two characters may be pushed back.
Eric Andersenc470f442003-07-28 09:56:35 +000010150 * PEOF may be pushed back.
10151 */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010152static void
Eric Andersenc470f442003-07-28 09:56:35 +000010153pungetc(void)
10154{
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010155 g_parsefile->unget++;
Eric Andersencb57d552001-06-28 07:25:16 +000010156}
10157
Denys Vlasenko73c3e072016-09-29 17:17:04 +020010158/* This one eats backslash+newline */
10159static int
10160pgetc_eatbnl(void)
10161{
10162 int c;
10163
10164 while ((c = pgetc()) == '\\') {
10165 if (pgetc() != '\n') {
10166 pungetc();
10167 break;
10168 }
10169
Denys Vlasenkoce332a22016-10-02 23:47:34 +020010170 nlprompt();
Denys Vlasenko73c3e072016-09-29 17:17:04 +020010171 }
10172
10173 return c;
10174}
10175
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010176/*
10177 * To handle the "." command, a stack of input files is used. Pushfile
10178 * adds a new entry to the stack and popfile restores the previous level.
10179 */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010180static void
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010181pushfile(void)
Eric Andersenc470f442003-07-28 09:56:35 +000010182{
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010183 struct parsefile *pf;
10184
Denis Vlasenko597906c2008-02-20 16:38:54 +000010185 pf = ckzalloc(sizeof(*pf));
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010186 pf->prev = g_parsefile;
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010187 pf->pf_fd = -1;
Denis Vlasenko597906c2008-02-20 16:38:54 +000010188 /*pf->strpush = NULL; - ckzalloc did it */
10189 /*pf->basestrpush.prev = NULL;*/
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010190 /*pf->unget = 0;*/
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010191 g_parsefile = pf;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010192}
10193
10194static void
10195popfile(void)
10196{
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010197 struct parsefile *pf = g_parsefile;
Eric Andersenc470f442003-07-28 09:56:35 +000010198
Denys Vlasenko493b9ca2016-10-30 18:27:14 +010010199 if (pf == &basepf)
10200 return;
10201
Denis Vlasenkob012b102007-02-19 22:43:01 +000010202 INT_OFF;
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010203 if (pf->pf_fd >= 0)
10204 close(pf->pf_fd);
Denis Vlasenko60818682007-09-28 22:07:23 +000010205 free(pf->buf);
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010206 while (pf->strpush)
10207 popstring();
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010208 g_parsefile = pf->prev;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010209 free(pf);
Denis Vlasenkob012b102007-02-19 22:43:01 +000010210 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +000010211}
10212
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010213/*
10214 * Return to top level.
10215 */
10216static void
10217popallfiles(void)
10218{
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010219 while (g_parsefile != &basepf)
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010220 popfile();
10221}
10222
10223/*
10224 * Close the file(s) that the shell is reading commands from. Called
10225 * after a fork is done.
10226 */
10227static void
10228closescript(void)
10229{
10230 popallfiles();
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010231 if (g_parsefile->pf_fd > 0) {
10232 close(g_parsefile->pf_fd);
10233 g_parsefile->pf_fd = 0;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010234 }
10235}
10236
10237/*
10238 * Like setinputfile, but takes an open file descriptor. Call this with
10239 * interrupts off.
10240 */
10241static void
10242setinputfd(int fd, int push)
10243{
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010244 if (push) {
10245 pushfile();
Denis Vlasenko727752d2008-11-28 03:41:47 +000010246 g_parsefile->buf = NULL;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010247 }
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010248 g_parsefile->pf_fd = fd;
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010249 if (g_parsefile->buf == NULL)
10250 g_parsefile->buf = ckmalloc(IBUFSIZ);
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010251 g_parsefile->left_in_buffer = 0;
10252 g_parsefile->left_in_line = 0;
10253 g_parsefile->linno = 1;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010254}
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010255
Eric Andersenc470f442003-07-28 09:56:35 +000010256/*
10257 * Set the input to take input from a file. If push is set, push the
10258 * old input onto the stack first.
10259 */
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010260static int
10261setinputfile(const char *fname, int flags)
Eric Andersenc470f442003-07-28 09:56:35 +000010262{
10263 int fd;
Eric Andersenc470f442003-07-28 09:56:35 +000010264
Denis Vlasenkob012b102007-02-19 22:43:01 +000010265 INT_OFF;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010266 fd = open(fname, O_RDONLY);
10267 if (fd < 0) {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010268 if (flags & INPUT_NOFILE_OK)
10269 goto out;
Denys Vlasenkob7adf7a2016-10-25 17:00:13 +020010270 exitstatus = 127;
Denis Vlasenko9604e1b2009-03-03 18:47:56 +000010271 ash_msg_and_raise_error("can't open '%s'", fname);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010272 }
Denys Vlasenko64774602016-10-26 15:24:30 +020010273 if (fd < 10)
10274 fd = savefd(fd);
Denys Vlasenkoe19923f2016-10-26 15:38:44 +020010275 else
10276 close_on_exec_on(fd);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010277 setinputfd(fd, flags & INPUT_PUSH_FILE);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010278 out:
Denis Vlasenkob012b102007-02-19 22:43:01 +000010279 INT_ON;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010280 return fd;
Eric Andersenc470f442003-07-28 09:56:35 +000010281}
10282
Eric Andersencb57d552001-06-28 07:25:16 +000010283/*
10284 * Like setinputfile, but takes input from a string.
10285 */
Eric Andersenc470f442003-07-28 09:56:35 +000010286static void
10287setinputstring(char *string)
Eric Andersen62483552001-07-10 06:09:16 +000010288{
Denis Vlasenkob012b102007-02-19 22:43:01 +000010289 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +000010290 pushfile();
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010291 g_parsefile->next_to_pgetc = string;
10292 g_parsefile->left_in_line = strlen(string);
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010293 g_parsefile->buf = NULL;
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010294 g_parsefile->linno = 1;
Denis Vlasenkob012b102007-02-19 22:43:01 +000010295 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +000010296}
10297
10298
Denys Vlasenko70392332016-10-27 02:31:55 +020010299/*
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010300 * Routines to check for mail.
Eric Andersencb57d552001-06-28 07:25:16 +000010301 */
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010302
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010303#if ENABLE_ASH_MAIL
Eric Andersencb57d552001-06-28 07:25:16 +000010304
Denys Vlasenko23841622015-10-09 15:52:03 +020010305/* Hash of mtimes of mailboxes */
10306static unsigned mailtime_hash;
Eric Andersenc470f442003-07-28 09:56:35 +000010307/* Set if MAIL or MAILPATH is changed. */
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010308static smallint mail_var_path_changed;
Eric Andersencb57d552001-06-28 07:25:16 +000010309
Eric Andersencb57d552001-06-28 07:25:16 +000010310/*
Eric Andersenc470f442003-07-28 09:56:35 +000010311 * Print appropriate message(s) if mail has arrived.
10312 * If mail_var_path_changed is set,
10313 * then the value of MAIL has mail_var_path_changed,
10314 * so we just update the values.
Eric Andersencb57d552001-06-28 07:25:16 +000010315 */
Eric Andersenc470f442003-07-28 09:56:35 +000010316static void
10317chkmail(void)
Eric Andersencb57d552001-06-28 07:25:16 +000010318{
Eric Andersencb57d552001-06-28 07:25:16 +000010319 const char *mpath;
10320 char *p;
10321 char *q;
Denys Vlasenko23841622015-10-09 15:52:03 +020010322 unsigned new_hash;
Eric Andersencb57d552001-06-28 07:25:16 +000010323 struct stackmark smark;
10324 struct stat statb;
10325
Eric Andersencb57d552001-06-28 07:25:16 +000010326 setstackmark(&smark);
Eric Andersenc470f442003-07-28 09:56:35 +000010327 mpath = mpathset() ? mpathval() : mailval();
Denys Vlasenko23841622015-10-09 15:52:03 +020010328 new_hash = 0;
10329 for (;;) {
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020010330 p = path_advance(&mpath, nullstr);
Eric Andersencb57d552001-06-28 07:25:16 +000010331 if (p == NULL)
10332 break;
10333 if (*p == '\0')
10334 continue;
Denis Vlasenkof7d56652008-03-25 05:51:41 +000010335 for (q = p; *q; q++)
10336 continue;
Denis Vlasenkoa7189f02006-11-17 20:29:00 +000010337#if DEBUG
Eric Andersencb57d552001-06-28 07:25:16 +000010338 if (q[-1] != '/')
10339 abort();
10340#endif
Eric Andersenc470f442003-07-28 09:56:35 +000010341 q[-1] = '\0'; /* delete trailing '/' */
10342 if (stat(p, &statb) < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +000010343 continue;
Eric Andersencb57d552001-06-28 07:25:16 +000010344 }
Denys Vlasenko23841622015-10-09 15:52:03 +020010345 /* Very simplistic "hash": just a sum of all mtimes */
10346 new_hash += (unsigned)statb.st_mtime;
10347 }
10348 if (!mail_var_path_changed && mailtime_hash != new_hash) {
Denys Vlasenko4cd99e72015-10-09 16:02:53 +020010349 if (mailtime_hash != 0)
10350 out2str("you have mail\n");
Denys Vlasenko23841622015-10-09 15:52:03 +020010351 mailtime_hash = new_hash;
Eric Andersencb57d552001-06-28 07:25:16 +000010352 }
Eric Andersenc470f442003-07-28 09:56:35 +000010353 mail_var_path_changed = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010354 popstackmark(&smark);
10355}
Eric Andersencb57d552001-06-28 07:25:16 +000010356
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010357static void FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010358changemail(const char *val UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000010359{
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010360 mail_var_path_changed = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000010361}
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010362
Denis Vlasenko131ae172007-02-18 13:00:19 +000010363#endif /* ASH_MAIL */
Eric Andersenc470f442003-07-28 09:56:35 +000010364
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010365
10366/* ============ ??? */
10367
Eric Andersencb57d552001-06-28 07:25:16 +000010368/*
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010369 * Set the shell parameters.
Eric Andersencb57d552001-06-28 07:25:16 +000010370 */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010371static void
10372setparam(char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000010373{
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010374 char **newparam;
10375 char **ap;
10376 int nparam;
Eric Andersencb57d552001-06-28 07:25:16 +000010377
Denis Vlasenkof7d56652008-03-25 05:51:41 +000010378 for (nparam = 0; argv[nparam]; nparam++)
10379 continue;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010380 ap = newparam = ckmalloc((nparam + 1) * sizeof(*ap));
10381 while (*argv) {
10382 *ap++ = ckstrdup(*argv++);
Eric Andersencb57d552001-06-28 07:25:16 +000010383 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010384 *ap = NULL;
10385 freeparam(&shellparam);
Denis Vlasenko01631112007-12-16 17:20:38 +000010386 shellparam.malloced = 1;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010387 shellparam.nparam = nparam;
10388 shellparam.p = newparam;
10389#if ENABLE_ASH_GETOPTS
10390 shellparam.optind = 1;
10391 shellparam.optoff = -1;
10392#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010393}
10394
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010395/*
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010396 * Process shell options. The global variable argptr contains a pointer
10397 * to the argument list; we advance it past the options.
Denis Vlasenko94e87bc2008-02-14 16:51:58 +000010398 *
10399 * SUSv3 section 2.8.1 "Consequences of Shell Errors" says:
10400 * For a non-interactive shell, an error condition encountered
10401 * by a special built-in ... shall cause the shell to write a diagnostic message
10402 * to standard error and exit as shown in the following table:
Denis Vlasenko56244732008-02-17 15:14:04 +000010403 * Error Special Built-In
Denis Vlasenko94e87bc2008-02-14 16:51:58 +000010404 * ...
10405 * Utility syntax error (option or operand error) Shall exit
10406 * ...
10407 * However, in bug 1142 (http://busybox.net/bugs/view.php?id=1142)
10408 * we see that bash does not do that (set "finishes" with error code 1 instead,
10409 * and shell continues), and people rely on this behavior!
10410 * Testcase:
10411 * set -o barfoo 2>/dev/null
10412 * echo $?
10413 *
10414 * Oh well. Let's mimic that.
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010415 */
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010416static int
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010417plus_minus_o(char *name, int val)
Eric Andersen62483552001-07-10 06:09:16 +000010418{
10419 int i;
10420
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010421 if (name) {
10422 for (i = 0; i < NOPTS; i++) {
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000010423 if (strcmp(name, optnames(i)) == 0) {
Eric Andersenc470f442003-07-28 09:56:35 +000010424 optlist[i] = val;
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010425 return 0;
Eric Andersen62483552001-07-10 06:09:16 +000010426 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010427 }
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010428 ash_msg("illegal option %co %s", val ? '-' : '+', name);
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010429 return 1;
Eric Andersen62483552001-07-10 06:09:16 +000010430 }
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000010431 for (i = 0; i < NOPTS; i++) {
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010432 if (val) {
10433 out1fmt("%-16s%s\n", optnames(i), optlist[i] ? "on" : "off");
10434 } else {
10435 out1fmt("set %co %s\n", optlist[i] ? '-' : '+', optnames(i));
10436 }
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000010437 }
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010438 return 0;
Eric Andersen62483552001-07-10 06:09:16 +000010439}
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010440static void
10441setoption(int flag, int val)
10442{
10443 int i;
10444
10445 for (i = 0; i < NOPTS; i++) {
10446 if (optletters(i) == flag) {
10447 optlist[i] = val;
10448 return;
10449 }
10450 }
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010451 ash_msg_and_raise_error("illegal option %c%c", val ? '-' : '+', flag);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010452 /* NOTREACHED */
10453}
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010454static int
Eric Andersenc470f442003-07-28 09:56:35 +000010455options(int cmdline)
Eric Andersencb57d552001-06-28 07:25:16 +000010456{
10457 char *p;
10458 int val;
10459 int c;
10460
10461 if (cmdline)
10462 minusc = NULL;
10463 while ((p = *argptr) != NULL) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010464 c = *p++;
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010465 if (c != '-' && c != '+')
10466 break;
10467 argptr++;
10468 val = 0; /* val = 0 if c == '+' */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010469 if (c == '-') {
Eric Andersencb57d552001-06-28 07:25:16 +000010470 val = 1;
Denis Vlasenko9f739442006-12-16 23:49:13 +000010471 if (p[0] == '\0' || LONE_DASH(p)) {
Eric Andersen2870d962001-07-02 17:27:21 +000010472 if (!cmdline) {
10473 /* "-" means turn off -x and -v */
10474 if (p[0] == '\0')
10475 xflag = vflag = 0;
10476 /* "--" means reset params */
10477 else if (*argptr == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +000010478 setparam(argptr);
Eric Andersen2870d962001-07-02 17:27:21 +000010479 }
Denys Vlasenkob0b83432011-03-07 12:34:59 +010010480 break; /* "-" or "--" terminates options */
Eric Andersencb57d552001-06-28 07:25:16 +000010481 }
Eric Andersencb57d552001-06-28 07:25:16 +000010482 }
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010483 /* first char was + or - */
Eric Andersencb57d552001-06-28 07:25:16 +000010484 while ((c = *p++) != '\0') {
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010485 /* bash 3.2 indeed handles -c CMD and +c CMD the same */
Eric Andersencb57d552001-06-28 07:25:16 +000010486 if (c == 'c' && cmdline) {
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010487 minusc = p; /* command is after shell args */
Eric Andersencb57d552001-06-28 07:25:16 +000010488 } else if (c == 'o') {
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010489 if (plus_minus_o(*argptr, val)) {
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010490 /* it already printed err message */
10491 return 1; /* error */
10492 }
Eric Andersencb57d552001-06-28 07:25:16 +000010493 if (*argptr)
10494 argptr++;
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010495 } else if (cmdline && (c == 'l')) { /* -l or +l == --login */
10496 isloginsh = 1;
10497 /* bash does not accept +-login, we also won't */
10498 } else if (cmdline && val && (c == '-')) { /* long options */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010499 if (strcmp(p, "login") == 0)
Robert Griebl64f70cc2002-05-14 23:22:06 +000010500 isloginsh = 1;
10501 break;
Eric Andersencb57d552001-06-28 07:25:16 +000010502 } else {
10503 setoption(c, val);
10504 }
10505 }
10506 }
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010507 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010508}
10509
Eric Andersencb57d552001-06-28 07:25:16 +000010510/*
Eric Andersencb57d552001-06-28 07:25:16 +000010511 * The shift builtin command.
10512 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010513static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010514shiftcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000010515{
10516 int n;
10517 char **ap1, **ap2;
10518
10519 n = 1;
Denis Vlasenko68404f12008-03-17 09:00:54 +000010520 if (argv[1])
Eric Andersencb57d552001-06-28 07:25:16 +000010521 n = number(argv[1]);
10522 if (n > shellparam.nparam)
Denis Vlasenkoc90e1be2008-07-30 15:35:05 +000010523 n = 0; /* bash compat, was = shellparam.nparam; */
Denis Vlasenkob012b102007-02-19 22:43:01 +000010524 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +000010525 shellparam.nparam -= n;
Denis Vlasenko2da584f2007-02-19 22:44:05 +000010526 for (ap1 = shellparam.p; --n >= 0; ap1++) {
Denis Vlasenko01631112007-12-16 17:20:38 +000010527 if (shellparam.malloced)
Denis Vlasenkob012b102007-02-19 22:43:01 +000010528 free(*ap1);
Eric Andersencb57d552001-06-28 07:25:16 +000010529 }
10530 ap2 = shellparam.p;
Denis Vlasenkof7d56652008-03-25 05:51:41 +000010531 while ((*ap2++ = *ap1++) != NULL)
10532 continue;
Denis Vlasenko131ae172007-02-18 13:00:19 +000010533#if ENABLE_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +000010534 shellparam.optind = 1;
10535 shellparam.optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +000010536#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +000010537 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +000010538 return 0;
10539}
10540
Eric Andersencb57d552001-06-28 07:25:16 +000010541/*
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010542 * POSIX requires that 'set' (but not export or readonly) output the
10543 * variables in lexicographic order - by the locale's collating order (sigh).
10544 * Maybe we could keep them in an ordered balanced binary tree
10545 * instead of hashed lists.
10546 * For now just roll 'em through qsort for printing...
10547 */
10548static int
10549showvars(const char *sep_prefix, int on, int off)
10550{
10551 const char *sep;
10552 char **ep, **epend;
10553
10554 ep = listvars(on, off, &epend);
10555 qsort(ep, epend - ep, sizeof(char *), vpcmp);
10556
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010557 sep = *sep_prefix ? " " : sep_prefix;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010558
10559 for (; ep < epend; ep++) {
10560 const char *p;
10561 const char *q;
10562
10563 p = strchrnul(*ep, '=');
10564 q = nullstr;
10565 if (*p)
10566 q = single_quote(++p);
10567 out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
10568 }
10569 return 0;
10570}
10571
10572/*
Eric Andersencb57d552001-06-28 07:25:16 +000010573 * The set command builtin.
10574 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010575static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010576setcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +000010577{
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010578 int retval;
10579
Denis Vlasenko68404f12008-03-17 09:00:54 +000010580 if (!argv[1])
Eric Andersenc470f442003-07-28 09:56:35 +000010581 return showvars(nullstr, 0, VUNSET);
Denys Vlasenkob0b83432011-03-07 12:34:59 +010010582
Denis Vlasenkob012b102007-02-19 22:43:01 +000010583 INT_OFF;
Denys Vlasenkob0b83432011-03-07 12:34:59 +010010584 retval = options(/*cmdline:*/ 0);
10585 if (retval == 0) { /* if no parse error... */
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010586 optschanged();
10587 if (*argptr != NULL) {
10588 setparam(argptr);
10589 }
Eric Andersencb57d552001-06-28 07:25:16 +000010590 }
Denis Vlasenkob012b102007-02-19 22:43:01 +000010591 INT_ON;
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010592 return retval;
Eric Andersencb57d552001-06-28 07:25:16 +000010593}
10594
Denis Vlasenko131ae172007-02-18 13:00:19 +000010595#if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010596static void FAST_FUNC
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000010597change_random(const char *value)
Eric Andersenef02f822004-03-11 13:34:24 +000010598{
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020010599 uint32_t t;
10600
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000010601 if (value == NULL) {
Eric Andersen16767e22004-03-16 05:14:10 +000010602 /* "get", generate */
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020010603 t = next_random(&random_gen);
Eric Andersen16767e22004-03-16 05:14:10 +000010604 /* set without recursion */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +020010605 setvar(vrandom.var_text, utoa(t), VNOFUNC);
Eric Andersen16767e22004-03-16 05:14:10 +000010606 vrandom.flags &= ~VNOFUNC;
10607 } else {
10608 /* set/reset */
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020010609 t = strtoul(value, NULL, 10);
10610 INIT_RANDOM_T(&random_gen, (t ? t : 1), t);
Eric Andersen16767e22004-03-16 05:14:10 +000010611 }
Eric Andersenef02f822004-03-11 13:34:24 +000010612}
Eric Andersen16767e22004-03-16 05:14:10 +000010613#endif
10614
Denis Vlasenko131ae172007-02-18 13:00:19 +000010615#if ENABLE_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +000010616static int
Denys Vlasenko35c2a132016-10-26 17:34:26 +020010617getopts(char *optstr, char *optvar, char **optfirst)
Eric Andersencb57d552001-06-28 07:25:16 +000010618{
10619 char *p, *q;
10620 char c = '?';
10621 int done = 0;
Denys Vlasenko9c541002015-10-07 15:44:36 +020010622 char sbuf[2];
Eric Andersena48b0a32003-10-22 10:56:47 +000010623 char **optnext;
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010624 int ind = shellparam.optind;
10625 int off = shellparam.optoff;
Eric Andersencb57d552001-06-28 07:25:16 +000010626
Denys Vlasenko9c541002015-10-07 15:44:36 +020010627 sbuf[1] = '\0';
10628
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010629 shellparam.optind = -1;
10630 optnext = optfirst + ind - 1;
Eric Andersena48b0a32003-10-22 10:56:47 +000010631
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010632 if (ind <= 1 || off < 0 || (int)strlen(optnext[-1]) < off)
Eric Andersencb57d552001-06-28 07:25:16 +000010633 p = NULL;
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010634 else
10635 p = optnext[-1] + off;
Eric Andersencb57d552001-06-28 07:25:16 +000010636 if (p == NULL || *p == '\0') {
10637 /* Current word is done, advance */
Eric Andersencb57d552001-06-28 07:25:16 +000010638 p = *optnext;
10639 if (p == NULL || *p != '-' || *++p == '\0') {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010640 atend:
Eric Andersencb57d552001-06-28 07:25:16 +000010641 p = NULL;
10642 done = 1;
10643 goto out;
10644 }
10645 optnext++;
Denis Vlasenko9f739442006-12-16 23:49:13 +000010646 if (LONE_DASH(p)) /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +000010647 goto atend;
10648 }
10649
10650 c = *p++;
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +000010651 for (q = optstr; *q != c;) {
Eric Andersencb57d552001-06-28 07:25:16 +000010652 if (*q == '\0') {
10653 if (optstr[0] == ':') {
Denys Vlasenko9c541002015-10-07 15:44:36 +020010654 sbuf[0] = c;
10655 /*sbuf[1] = '\0'; - already is */
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010656 setvar0("OPTARG", sbuf);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010657 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010658 fprintf(stderr, "Illegal option -%c\n", c);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010659 unsetvar("OPTARG");
Eric Andersencb57d552001-06-28 07:25:16 +000010660 }
10661 c = '?';
Eric Andersenc470f442003-07-28 09:56:35 +000010662 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +000010663 }
10664 if (*++q == ':')
10665 q++;
10666 }
10667
10668 if (*++q == ':') {
10669 if (*p == '\0' && (p = *optnext) == NULL) {
10670 if (optstr[0] == ':') {
Denys Vlasenko9c541002015-10-07 15:44:36 +020010671 sbuf[0] = c;
10672 /*sbuf[1] = '\0'; - already is */
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010673 setvar0("OPTARG", sbuf);
Eric Andersencb57d552001-06-28 07:25:16 +000010674 c = ':';
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010675 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010676 fprintf(stderr, "No arg for -%c option\n", c);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010677 unsetvar("OPTARG");
Eric Andersencb57d552001-06-28 07:25:16 +000010678 c = '?';
10679 }
Eric Andersenc470f442003-07-28 09:56:35 +000010680 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +000010681 }
10682
10683 if (p == *optnext)
10684 optnext++;
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010685 setvar0("OPTARG", p);
Eric Andersencb57d552001-06-28 07:25:16 +000010686 p = NULL;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010687 } else
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010688 setvar0("OPTARG", nullstr);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010689 out:
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010690 ind = optnext - optfirst + 1;
10691 setvar("OPTIND", itoa(ind), VNOFUNC);
Denys Vlasenko9c541002015-10-07 15:44:36 +020010692 sbuf[0] = c;
10693 /*sbuf[1] = '\0'; - already is */
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010694 setvar0(optvar, sbuf);
10695
10696 shellparam.optoff = p ? p - *(optnext - 1) : -1;
10697 shellparam.optind = ind;
10698
Eric Andersencb57d552001-06-28 07:25:16 +000010699 return done;
10700}
Eric Andersenc470f442003-07-28 09:56:35 +000010701
10702/*
10703 * The getopts builtin. Shellparam.optnext points to the next argument
10704 * to be processed. Shellparam.optptr points to the next character to
10705 * be processed in the current argument. If shellparam.optnext is NULL,
10706 * then it's the first time getopts has been called.
10707 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010708static int FAST_FUNC
Eric Andersenc470f442003-07-28 09:56:35 +000010709getoptscmd(int argc, char **argv)
10710{
10711 char **optbase;
10712
10713 if (argc < 3)
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +000010714 ash_msg_and_raise_error("usage: getopts optstring var [arg]");
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010715 if (argc == 3) {
Eric Andersenc470f442003-07-28 09:56:35 +000010716 optbase = shellparam.p;
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010717 if ((unsigned)shellparam.optind > shellparam.nparam + 1) {
Eric Andersenc470f442003-07-28 09:56:35 +000010718 shellparam.optind = 1;
10719 shellparam.optoff = -1;
10720 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010721 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010722 optbase = &argv[3];
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010723 if ((unsigned)shellparam.optind > argc - 2) {
Eric Andersenc470f442003-07-28 09:56:35 +000010724 shellparam.optind = 1;
10725 shellparam.optoff = -1;
10726 }
10727 }
10728
Denys Vlasenko35c2a132016-10-26 17:34:26 +020010729 return getopts(argv[1], argv[2], optbase);
Eric Andersenc470f442003-07-28 09:56:35 +000010730}
Denis Vlasenko131ae172007-02-18 13:00:19 +000010731#endif /* ASH_GETOPTS */
Eric Andersencb57d552001-06-28 07:25:16 +000010732
Eric Andersencb57d552001-06-28 07:25:16 +000010733
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010734/* ============ Shell parser */
Eric Andersencb57d552001-06-28 07:25:16 +000010735
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010736struct heredoc {
10737 struct heredoc *next; /* next here document in list */
10738 union node *here; /* redirection node */
10739 char *eofmark; /* string indicating end of input */
10740 smallint striptabs; /* if set, strip leading tabs */
10741};
10742
10743static smallint tokpushback; /* last token pushed back */
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010744static smallint quoteflag; /* set if (part of) last token was quoted */
10745static token_id_t lasttoken; /* last token read (integer id Txxx) */
10746static struct heredoc *heredoclist; /* list of here documents to read */
10747static char *wordtext; /* text of last word returned by readtoken */
10748static struct nodelist *backquotelist;
10749static union node *redirnode;
10750static struct heredoc *heredoc;
Denis Vlasenko99eb8502007-02-23 21:09:49 +000010751
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010752static const char *
10753tokname(char *buf, int tok)
10754{
10755 if (tok < TSEMI)
Denys Vlasenko888527c2016-10-02 16:54:17 +020010756 return tokname_array[tok];
10757 sprintf(buf, "\"%s\"", tokname_array[tok]);
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010758 return buf;
10759}
10760
10761/* raise_error_unexpected_syntax:
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010762 * Called when an unexpected token is read during the parse. The argument
10763 * is the token that is expected, or -1 if more than one type of token can
10764 * occur at this point.
10765 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010766static void raise_error_unexpected_syntax(int) NORETURN;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010767static void
10768raise_error_unexpected_syntax(int token)
10769{
10770 char msg[64];
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010771 char buf[16];
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010772 int l;
10773
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010774 l = sprintf(msg, "unexpected %s", tokname(buf, lasttoken));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010775 if (token >= 0)
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010776 sprintf(msg + l, " (expecting %s)", tokname(buf, token));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010777 raise_error_syntax(msg);
10778 /* NOTREACHED */
10779}
Eric Andersencb57d552001-06-28 07:25:16 +000010780
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010781#define EOFMARKLEN 79
Eric Andersencb57d552001-06-28 07:25:16 +000010782
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010783/* parsing is heavily cross-recursive, need these forward decls */
10784static union node *andor(void);
10785static union node *pipeline(void);
10786static union node *parse_command(void);
10787static void parseheredoc(void);
Ron Yorstonc0e00762015-10-29 11:30:55 +000010788static int peektoken(void);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010789static int readtoken(void);
Eric Andersencb57d552001-06-28 07:25:16 +000010790
Eric Andersenc470f442003-07-28 09:56:35 +000010791static union node *
10792list(int nlflag)
Eric Andersencb57d552001-06-28 07:25:16 +000010793{
10794 union node *n1, *n2, *n3;
10795 int tok;
10796
Eric Andersencb57d552001-06-28 07:25:16 +000010797 n1 = NULL;
10798 for (;;) {
Ron Yorstonc0e00762015-10-29 11:30:55 +000010799 switch (peektoken()) {
10800 case TNL:
10801 if (!(nlflag & 1))
10802 break;
10803 parseheredoc();
10804 return n1;
10805
10806 case TEOF:
10807 if (!n1 && (nlflag & 1))
10808 n1 = NODE_EOF;
10809 parseheredoc();
10810 return n1;
10811 }
10812
10813 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Denys Vlasenko888527c2016-10-02 16:54:17 +020010814 if (nlflag == 2 && ((1 << peektoken()) & tokendlist))
Ron Yorstonc0e00762015-10-29 11:30:55 +000010815 return n1;
10816 nlflag |= 2;
10817
Eric Andersencb57d552001-06-28 07:25:16 +000010818 n2 = andor();
10819 tok = readtoken();
10820 if (tok == TBACKGND) {
Eric Andersenc470f442003-07-28 09:56:35 +000010821 if (n2->type == NPIPE) {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +000010822 n2->npipe.pipe_backgnd = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010823 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010824 if (n2->type != NREDIR) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000010825 n3 = stzalloc(sizeof(struct nredir));
Eric Andersenc470f442003-07-28 09:56:35 +000010826 n3->nredir.n = n2;
Denis Vlasenko597906c2008-02-20 16:38:54 +000010827 /*n3->nredir.redirect = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000010828 n2 = n3;
10829 }
10830 n2->type = NBACKGND;
Eric Andersencb57d552001-06-28 07:25:16 +000010831 }
10832 }
10833 if (n1 == NULL) {
10834 n1 = n2;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010835 } else {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010836 n3 = stzalloc(sizeof(struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +000010837 n3->type = NSEMI;
10838 n3->nbinary.ch1 = n1;
10839 n3->nbinary.ch2 = n2;
10840 n1 = n3;
10841 }
10842 switch (tok) {
Ron Yorstonc0e00762015-10-29 11:30:55 +000010843 case TNL:
10844 case TEOF:
10845 tokpushback = 1;
10846 /* fall through */
Eric Andersencb57d552001-06-28 07:25:16 +000010847 case TBACKGND:
10848 case TSEMI:
Eric Andersencb57d552001-06-28 07:25:16 +000010849 break;
Eric Andersencb57d552001-06-28 07:25:16 +000010850 default:
Ron Yorstonc0e00762015-10-29 11:30:55 +000010851 if ((nlflag & 1))
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010852 raise_error_unexpected_syntax(-1);
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010853 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010854 return n1;
10855 }
10856 }
10857}
10858
Eric Andersenc470f442003-07-28 09:56:35 +000010859static union node *
10860andor(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010861{
Eric Andersencb57d552001-06-28 07:25:16 +000010862 union node *n1, *n2, *n3;
10863 int t;
10864
Eric Andersencb57d552001-06-28 07:25:16 +000010865 n1 = pipeline();
10866 for (;;) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010867 t = readtoken();
10868 if (t == TAND) {
Eric Andersencb57d552001-06-28 07:25:16 +000010869 t = NAND;
10870 } else if (t == TOR) {
10871 t = NOR;
10872 } else {
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010873 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010874 return n1;
10875 }
Eric Andersenc470f442003-07-28 09:56:35 +000010876 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000010877 n2 = pipeline();
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010878 n3 = stzalloc(sizeof(struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +000010879 n3->type = t;
10880 n3->nbinary.ch1 = n1;
10881 n3->nbinary.ch2 = n2;
10882 n1 = n3;
10883 }
10884}
10885
Eric Andersenc470f442003-07-28 09:56:35 +000010886static union node *
10887pipeline(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010888{
Eric Andersencb57d552001-06-28 07:25:16 +000010889 union node *n1, *n2, *pipenode;
10890 struct nodelist *lp, *prev;
10891 int negate;
10892
10893 negate = 0;
10894 TRACE(("pipeline: entered\n"));
10895 if (readtoken() == TNOT) {
10896 negate = !negate;
Eric Andersenc470f442003-07-28 09:56:35 +000010897 checkkwd = CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000010898 } else
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010899 tokpushback = 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010900 n1 = parse_command();
Eric Andersencb57d552001-06-28 07:25:16 +000010901 if (readtoken() == TPIPE) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000010902 pipenode = stzalloc(sizeof(struct npipe));
Eric Andersencb57d552001-06-28 07:25:16 +000010903 pipenode->type = NPIPE;
Denis Vlasenko2dc240c2008-07-24 06:07:50 +000010904 /*pipenode->npipe.pipe_backgnd = 0; - stzalloc did it */
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010905 lp = stzalloc(sizeof(struct nodelist));
Eric Andersencb57d552001-06-28 07:25:16 +000010906 pipenode->npipe.cmdlist = lp;
10907 lp->n = n1;
10908 do {
10909 prev = lp;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010910 lp = stzalloc(sizeof(struct nodelist));
Eric Andersenc470f442003-07-28 09:56:35 +000010911 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010912 lp->n = parse_command();
Eric Andersencb57d552001-06-28 07:25:16 +000010913 prev->next = lp;
10914 } while (readtoken() == TPIPE);
10915 lp->next = NULL;
10916 n1 = pipenode;
10917 }
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010918 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010919 if (negate) {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010920 n2 = stzalloc(sizeof(struct nnot));
Eric Andersencb57d552001-06-28 07:25:16 +000010921 n2->type = NNOT;
10922 n2->nnot.com = n1;
10923 return n2;
Denis Vlasenko2da584f2007-02-19 22:44:05 +000010924 }
10925 return n1;
Eric Andersencb57d552001-06-28 07:25:16 +000010926}
10927
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010928static union node *
10929makename(void)
10930{
10931 union node *n;
10932
Denis Vlasenko597906c2008-02-20 16:38:54 +000010933 n = stzalloc(sizeof(struct narg));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010934 n->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000010935 /*n->narg.next = NULL; - stzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010936 n->narg.text = wordtext;
10937 n->narg.backquote = backquotelist;
10938 return n;
10939}
10940
10941static void
10942fixredir(union node *n, const char *text, int err)
10943{
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000010944 int fd;
10945
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010946 TRACE(("Fix redir %s %d\n", text, err));
10947 if (!err)
10948 n->ndup.vname = NULL;
10949
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000010950 fd = bb_strtou(text, NULL, 10);
10951 if (!errno && fd >= 0)
10952 n->ndup.dupfd = fd;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010953 else if (LONE_DASH(text))
10954 n->ndup.dupfd = -1;
10955 else {
10956 if (err)
Denis Vlasenko559691a2008-10-05 18:39:31 +000010957 raise_error_syntax("bad fd number");
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010958 n->ndup.vname = makename();
10959 }
10960}
10961
10962/*
10963 * Returns true if the text contains nothing to expand (no dollar signs
10964 * or backquotes).
10965 */
10966static int
Denis Vlasenko68819d12008-12-15 11:26:36 +000010967noexpand(const char *text)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010968{
Denys Vlasenkocd716832009-11-28 22:14:02 +010010969 unsigned char c;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010970
Denys Vlasenkocd716832009-11-28 22:14:02 +010010971 while ((c = *text++) != '\0') {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010972 if (c == CTLQUOTEMARK)
10973 continue;
10974 if (c == CTLESC)
Denys Vlasenkocd716832009-11-28 22:14:02 +010010975 text++;
Denys Vlasenko76bc2d62009-11-29 01:37:46 +010010976 else if (SIT(c, BASESYNTAX) == CCTL)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010977 return 0;
10978 }
10979 return 1;
10980}
10981
10982static void
10983parsefname(void)
10984{
10985 union node *n = redirnode;
10986
10987 if (readtoken() != TWORD)
10988 raise_error_unexpected_syntax(-1);
10989 if (n->type == NHERE) {
10990 struct heredoc *here = heredoc;
10991 struct heredoc *p;
10992 int i;
10993
10994 if (quoteflag == 0)
10995 n->type = NXHERE;
10996 TRACE(("Here document %d\n", n->type));
10997 if (!noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
Denis Vlasenko559691a2008-10-05 18:39:31 +000010998 raise_error_syntax("illegal eof marker for << redirection");
Denys Vlasenkob6c84342009-08-29 20:23:20 +020010999 rmescapes(wordtext, 0);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011000 here->eofmark = wordtext;
11001 here->next = NULL;
11002 if (heredoclist == NULL)
11003 heredoclist = here;
11004 else {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011005 for (p = heredoclist; p->next; p = p->next)
11006 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011007 p->next = here;
11008 }
11009 } else if (n->type == NTOFD || n->type == NFROMFD) {
11010 fixredir(n, wordtext, 0);
11011 } else {
11012 n->nfile.fname = makename();
11013 }
11014}
Eric Andersencb57d552001-06-28 07:25:16 +000011015
Eric Andersenc470f442003-07-28 09:56:35 +000011016static union node *
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011017simplecmd(void)
11018{
11019 union node *args, **app;
11020 union node *n = NULL;
11021 union node *vars, **vpp;
11022 union node **rpp, *redir;
11023 int savecheckkwd;
Denis Vlasenko80591b02008-03-25 07:49:43 +000011024#if ENABLE_ASH_BASH_COMPAT
11025 smallint double_brackets_flag = 0;
Ron Yorston95ebcf72015-11-03 09:42:23 +000011026 smallint function_flag = 0;
Denis Vlasenko80591b02008-03-25 07:49:43 +000011027#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011028
11029 args = NULL;
11030 app = &args;
11031 vars = NULL;
11032 vpp = &vars;
11033 redir = NULL;
11034 rpp = &redir;
11035
11036 savecheckkwd = CHKALIAS;
11037 for (;;) {
Denis Vlasenko80591b02008-03-25 07:49:43 +000011038 int t;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011039 checkkwd = savecheckkwd;
Denis Vlasenko80591b02008-03-25 07:49:43 +000011040 t = readtoken();
11041 switch (t) {
11042#if ENABLE_ASH_BASH_COMPAT
Ron Yorston95ebcf72015-11-03 09:42:23 +000011043 case TFUNCTION:
11044 if (peektoken() != TWORD)
11045 raise_error_unexpected_syntax(TWORD);
11046 function_flag = 1;
11047 break;
Denis Vlasenko80591b02008-03-25 07:49:43 +000011048 case TAND: /* "&&" */
11049 case TOR: /* "||" */
11050 if (!double_brackets_flag) {
11051 tokpushback = 1;
11052 goto out;
11053 }
11054 wordtext = (char *) (t == TAND ? "-a" : "-o");
11055#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011056 case TWORD:
Denis Vlasenko597906c2008-02-20 16:38:54 +000011057 n = stzalloc(sizeof(struct narg));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011058 n->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011059 /*n->narg.next = NULL; - stzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011060 n->narg.text = wordtext;
Denis Vlasenko80591b02008-03-25 07:49:43 +000011061#if ENABLE_ASH_BASH_COMPAT
11062 if (strcmp("[[", wordtext) == 0)
11063 double_brackets_flag = 1;
11064 else if (strcmp("]]", wordtext) == 0)
11065 double_brackets_flag = 0;
11066#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011067 n->narg.backquote = backquotelist;
11068 if (savecheckkwd && isassignment(wordtext)) {
11069 *vpp = n;
11070 vpp = &n->narg.next;
11071 } else {
11072 *app = n;
11073 app = &n->narg.next;
11074 savecheckkwd = 0;
11075 }
Ron Yorston95ebcf72015-11-03 09:42:23 +000011076#if ENABLE_ASH_BASH_COMPAT
11077 if (function_flag) {
11078 checkkwd = CHKNL | CHKKWD;
11079 switch (peektoken()) {
11080 case TBEGIN:
11081 case TIF:
11082 case TCASE:
11083 case TUNTIL:
11084 case TWHILE:
11085 case TFOR:
11086 goto do_func;
11087 case TLP:
11088 function_flag = 0;
11089 break;
11090 case TWORD:
11091 if (strcmp("[[", wordtext) == 0)
11092 goto do_func;
11093 /* fall through */
11094 default:
11095 raise_error_unexpected_syntax(-1);
11096 }
11097 }
11098#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011099 break;
11100 case TREDIR:
11101 *rpp = n = redirnode;
11102 rpp = &n->nfile.next;
11103 parsefname(); /* read name of redirection file */
11104 break;
11105 case TLP:
Ron Yorston95ebcf72015-11-03 09:42:23 +000011106 IF_ASH_BASH_COMPAT(do_func:)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011107 if (args && app == &args->narg.next
11108 && !vars && !redir
11109 ) {
11110 struct builtincmd *bcmd;
11111 const char *name;
11112
11113 /* We have a function */
Ron Yorston95ebcf72015-11-03 09:42:23 +000011114 if (IF_ASH_BASH_COMPAT(!function_flag &&) readtoken() != TRP)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011115 raise_error_unexpected_syntax(TRP);
11116 name = n->narg.text;
11117 if (!goodname(name)
11118 || ((bcmd = find_builtin(name)) && IS_BUILTIN_SPECIAL(bcmd))
11119 ) {
Denis Vlasenko559691a2008-10-05 18:39:31 +000011120 raise_error_syntax("bad function name");
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011121 }
11122 n->type = NDEFUN;
11123 checkkwd = CHKNL | CHKKWD | CHKALIAS;
11124 n->narg.next = parse_command();
11125 return n;
11126 }
Ron Yorston95ebcf72015-11-03 09:42:23 +000011127 IF_ASH_BASH_COMPAT(function_flag = 0;)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011128 /* fall through */
11129 default:
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011130 tokpushback = 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011131 goto out;
11132 }
11133 }
11134 out:
11135 *app = NULL;
11136 *vpp = NULL;
11137 *rpp = NULL;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011138 n = stzalloc(sizeof(struct ncmd));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011139 n->type = NCMD;
11140 n->ncmd.args = args;
11141 n->ncmd.assign = vars;
11142 n->ncmd.redirect = redir;
11143 return n;
11144}
11145
11146static union node *
11147parse_command(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011148{
Eric Andersencb57d552001-06-28 07:25:16 +000011149 union node *n1, *n2;
11150 union node *ap, **app;
11151 union node *cp, **cpp;
11152 union node *redir, **rpp;
Eric Andersenc470f442003-07-28 09:56:35 +000011153 union node **rpp2;
Eric Andersencb57d552001-06-28 07:25:16 +000011154 int t;
11155
11156 redir = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +000011157 rpp2 = &redir;
Eric Andersen88cec252001-09-06 17:35:20 +000011158
Eric Andersencb57d552001-06-28 07:25:16 +000011159 switch (readtoken()) {
Eric Andersenc470f442003-07-28 09:56:35 +000011160 default:
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011161 raise_error_unexpected_syntax(-1);
Eric Andersenc470f442003-07-28 09:56:35 +000011162 /* NOTREACHED */
Eric Andersencb57d552001-06-28 07:25:16 +000011163 case TIF:
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011164 n1 = stzalloc(sizeof(struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +000011165 n1->type = NIF;
11166 n1->nif.test = list(0);
11167 if (readtoken() != TTHEN)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011168 raise_error_unexpected_syntax(TTHEN);
Eric Andersencb57d552001-06-28 07:25:16 +000011169 n1->nif.ifpart = list(0);
11170 n2 = n1;
11171 while (readtoken() == TELIF) {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011172 n2->nif.elsepart = stzalloc(sizeof(struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +000011173 n2 = n2->nif.elsepart;
11174 n2->type = NIF;
11175 n2->nif.test = list(0);
11176 if (readtoken() != TTHEN)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011177 raise_error_unexpected_syntax(TTHEN);
Eric Andersencb57d552001-06-28 07:25:16 +000011178 n2->nif.ifpart = list(0);
11179 }
11180 if (lasttoken == TELSE)
11181 n2->nif.elsepart = list(0);
11182 else {
11183 n2->nif.elsepart = NULL;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011184 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011185 }
Eric Andersenc470f442003-07-28 09:56:35 +000011186 t = TFI;
Eric Andersencb57d552001-06-28 07:25:16 +000011187 break;
11188 case TWHILE:
Eric Andersenc470f442003-07-28 09:56:35 +000011189 case TUNTIL: {
Eric Andersencb57d552001-06-28 07:25:16 +000011190 int got;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011191 n1 = stzalloc(sizeof(struct nbinary));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011192 n1->type = (lasttoken == TWHILE) ? NWHILE : NUNTIL;
Eric Andersencb57d552001-06-28 07:25:16 +000011193 n1->nbinary.ch1 = list(0);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011194 got = readtoken();
11195 if (got != TDO) {
Denys Vlasenko888527c2016-10-02 16:54:17 +020011196 TRACE(("expecting DO got '%s' %s\n", tokname_array[got],
Denis Vlasenko131ae172007-02-18 13:00:19 +000011197 got == TWORD ? wordtext : ""));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011198 raise_error_unexpected_syntax(TDO);
Eric Andersencb57d552001-06-28 07:25:16 +000011199 }
11200 n1->nbinary.ch2 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +000011201 t = TDONE;
Eric Andersencb57d552001-06-28 07:25:16 +000011202 break;
11203 }
11204 case TFOR:
Denis Vlasenko2dc240c2008-07-24 06:07:50 +000011205 if (readtoken() != TWORD || quoteflag || !goodname(wordtext))
Denis Vlasenko559691a2008-10-05 18:39:31 +000011206 raise_error_syntax("bad for loop variable");
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011207 n1 = stzalloc(sizeof(struct nfor));
Eric Andersencb57d552001-06-28 07:25:16 +000011208 n1->type = NFOR;
11209 n1->nfor.var = wordtext;
Ron Yorstonab80e012015-08-03 13:46:00 +010011210 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000011211 if (readtoken() == TIN) {
11212 app = &ap;
11213 while (readtoken() == TWORD) {
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 Andersencb57d552001-06-28 07:25:16 +000011217 n2->narg.text = wordtext;
11218 n2->narg.backquote = backquotelist;
11219 *app = n2;
11220 app = &n2->narg.next;
11221 }
11222 *app = NULL;
11223 n1->nfor.args = ap;
11224 if (lasttoken != TNL && lasttoken != TSEMI)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011225 raise_error_unexpected_syntax(-1);
Eric Andersencb57d552001-06-28 07:25:16 +000011226 } else {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011227 n2 = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000011228 n2->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011229 /*n2->narg.next = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011230 n2->narg.text = (char *)dolatstr;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011231 /*n2->narg.backquote = NULL;*/
Eric Andersencb57d552001-06-28 07:25:16 +000011232 n1->nfor.args = n2;
11233 /*
11234 * Newline or semicolon here is optional (but note
11235 * that the original Bourne shell only allowed NL).
11236 */
Ron Yorstonab80e012015-08-03 13:46:00 +010011237 if (lasttoken != TSEMI)
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011238 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011239 }
Eric Andersenc470f442003-07-28 09:56:35 +000011240 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000011241 if (readtoken() != TDO)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011242 raise_error_unexpected_syntax(TDO);
Eric Andersencb57d552001-06-28 07:25:16 +000011243 n1->nfor.body = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +000011244 t = TDONE;
Eric Andersencb57d552001-06-28 07:25:16 +000011245 break;
11246 case TCASE:
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011247 n1 = stzalloc(sizeof(struct ncase));
Eric Andersencb57d552001-06-28 07:25:16 +000011248 n1->type = NCASE;
11249 if (readtoken() != TWORD)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011250 raise_error_unexpected_syntax(TWORD);
Denis Vlasenko597906c2008-02-20 16:38:54 +000011251 n1->ncase.expr = n2 = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000011252 n2->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011253 /*n2->narg.next = NULL; - stzalloc did it */
Eric Andersencb57d552001-06-28 07:25:16 +000011254 n2->narg.text = wordtext;
11255 n2->narg.backquote = backquotelist;
Ron Yorston383b8852015-08-03 13:46:25 +010011256 checkkwd = CHKNL | CHKKWD | CHKALIAS;
11257 if (readtoken() != TIN)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011258 raise_error_unexpected_syntax(TIN);
Eric Andersencb57d552001-06-28 07:25:16 +000011259 cpp = &n1->ncase.cases;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011260 next_case:
Eric Andersenc470f442003-07-28 09:56:35 +000011261 checkkwd = CHKNL | CHKKWD;
11262 t = readtoken();
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011263 while (t != TESAC) {
Eric Andersencb57d552001-06-28 07:25:16 +000011264 if (lasttoken == TLP)
11265 readtoken();
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011266 *cpp = cp = stzalloc(sizeof(struct nclist));
Eric Andersencb57d552001-06-28 07:25:16 +000011267 cp->type = NCLIST;
11268 app = &cp->nclist.pattern;
11269 for (;;) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011270 *app = ap = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000011271 ap->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011272 /*ap->narg.next = NULL; - stzalloc did it */
Eric Andersencb57d552001-06-28 07:25:16 +000011273 ap->narg.text = wordtext;
11274 ap->narg.backquote = backquotelist;
Eric Andersenc470f442003-07-28 09:56:35 +000011275 if (readtoken() != TPIPE)
Eric Andersencb57d552001-06-28 07:25:16 +000011276 break;
11277 app = &ap->narg.next;
11278 readtoken();
11279 }
Denis Vlasenko597906c2008-02-20 16:38:54 +000011280 //ap->narg.next = NULL;
Eric Andersencb57d552001-06-28 07:25:16 +000011281 if (lasttoken != TRP)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011282 raise_error_unexpected_syntax(TRP);
Eric Andersenc470f442003-07-28 09:56:35 +000011283 cp->nclist.body = list(2);
Eric Andersencb57d552001-06-28 07:25:16 +000011284
Eric Andersenc470f442003-07-28 09:56:35 +000011285 cpp = &cp->nclist.next;
11286
11287 checkkwd = CHKNL | CHKKWD;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011288 t = readtoken();
11289 if (t != TESAC) {
Eric Andersencb57d552001-06-28 07:25:16 +000011290 if (t != TENDCASE)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011291 raise_error_unexpected_syntax(TENDCASE);
11292 goto next_case;
Eric Andersencb57d552001-06-28 07:25:16 +000011293 }
Eric Andersenc470f442003-07-28 09:56:35 +000011294 }
Eric Andersencb57d552001-06-28 07:25:16 +000011295 *cpp = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +000011296 goto redir;
Eric Andersencb57d552001-06-28 07:25:16 +000011297 case TLP:
Denis Vlasenko597906c2008-02-20 16:38:54 +000011298 n1 = stzalloc(sizeof(struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +000011299 n1->type = NSUBSHELL;
11300 n1->nredir.n = list(0);
Denis Vlasenko597906c2008-02-20 16:38:54 +000011301 /*n1->nredir.redirect = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011302 t = TRP;
Eric Andersencb57d552001-06-28 07:25:16 +000011303 break;
11304 case TBEGIN:
11305 n1 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +000011306 t = TEND;
Eric Andersencb57d552001-06-28 07:25:16 +000011307 break;
Ron Yorston95ebcf72015-11-03 09:42:23 +000011308 IF_ASH_BASH_COMPAT(case TFUNCTION:)
Eric Andersencb57d552001-06-28 07:25:16 +000011309 case TWORD:
Eric Andersenc470f442003-07-28 09:56:35 +000011310 case TREDIR:
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011311 tokpushback = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000011312 return simplecmd();
Eric Andersencb57d552001-06-28 07:25:16 +000011313 }
11314
Eric Andersenc470f442003-07-28 09:56:35 +000011315 if (readtoken() != t)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011316 raise_error_unexpected_syntax(t);
Eric Andersenc470f442003-07-28 09:56:35 +000011317
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011318 redir:
Eric Andersencb57d552001-06-28 07:25:16 +000011319 /* Now check for redirection which may follow command */
Eric Andersenc470f442003-07-28 09:56:35 +000011320 checkkwd = CHKKWD | CHKALIAS;
11321 rpp = rpp2;
Eric Andersencb57d552001-06-28 07:25:16 +000011322 while (readtoken() == TREDIR) {
11323 *rpp = n2 = redirnode;
11324 rpp = &n2->nfile.next;
11325 parsefname();
11326 }
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011327 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011328 *rpp = NULL;
11329 if (redir) {
11330 if (n1->type != NSUBSHELL) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011331 n2 = stzalloc(sizeof(struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +000011332 n2->type = NREDIR;
11333 n2->nredir.n = n1;
11334 n1 = n2;
11335 }
11336 n1->nredir.redirect = redir;
11337 }
Eric Andersencb57d552001-06-28 07:25:16 +000011338 return n1;
11339}
11340
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011341#if ENABLE_ASH_BASH_COMPAT
Denys Vlasenko37dc08b2016-10-02 04:38:07 +020011342static int
11343decode_dollar_squote(void)
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011344{
11345 static const char C_escapes[] ALIGN1 = "nrbtfav""x\\01234567";
11346 int c, cnt;
11347 char *p;
11348 char buf[4];
11349
11350 c = pgetc();
11351 p = strchr(C_escapes, c);
11352 if (p) {
11353 buf[0] = c;
11354 p = buf;
11355 cnt = 3;
11356 if ((unsigned char)(c - '0') <= 7) { /* \ooo */
11357 do {
11358 c = pgetc();
11359 *++p = c;
11360 } while ((unsigned char)(c - '0') <= 7 && --cnt);
11361 pungetc();
11362 } else if (c == 'x') { /* \xHH */
11363 do {
11364 c = pgetc();
11365 *++p = c;
11366 } while (isxdigit(c) && --cnt);
11367 pungetc();
11368 if (cnt == 3) { /* \x but next char is "bad" */
11369 c = 'x';
11370 goto unrecognized;
11371 }
11372 } else { /* simple seq like \\ or \t */
11373 p++;
11374 }
11375 *p = '\0';
11376 p = buf;
11377 c = bb_process_escape_sequence((void*)&p);
11378 } else { /* unrecognized "\z": print both chars unless ' or " */
11379 if (c != '\'' && c != '"') {
11380 unrecognized:
11381 c |= 0x100; /* "please encode \, then me" */
11382 }
11383 }
11384 return c;
11385}
11386#endif
11387
Eric Andersencb57d552001-06-28 07:25:16 +000011388/*
11389 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
11390 * is not NULL, read a here document. In the latter case, eofmark is the
11391 * word which marks the end of the document and striptabs is true if
Denys Vlasenkocd716832009-11-28 22:14:02 +010011392 * leading tabs should be stripped from the document. The argument c
Eric Andersencb57d552001-06-28 07:25:16 +000011393 * is the first character of the input token or document.
11394 *
11395 * Because C does not have internal subroutines, I have simulated them
11396 * using goto's to implement the subroutine linkage. The following macros
11397 * will run code that appears at the end of readtoken1.
11398 */
Eric Andersen2870d962001-07-02 17:27:21 +000011399#define CHECKEND() {goto checkend; checkend_return:;}
11400#define PARSEREDIR() {goto parseredir; parseredir_return:;}
11401#define PARSESUB() {goto parsesub; parsesub_return:;}
11402#define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
11403#define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
11404#define PARSEARITH() {goto parsearith; parsearith_return:;}
Eric Andersencb57d552001-06-28 07:25:16 +000011405static int
Denys Vlasenkocd716832009-11-28 22:14:02 +010011406readtoken1(int c, int syntax, char *eofmark, int striptabs)
Manuel Novoa III 16815d42001-08-10 19:36:07 +000011407{
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011408 /* NB: syntax parameter fits into smallint */
Denys Vlasenkocd716832009-11-28 22:14:02 +010011409 /* c parameter is an unsigned char or PEOF or PEOA */
Eric Andersencb57d552001-06-28 07:25:16 +000011410 char *out;
Denys Vlasenko50e6d422016-09-30 11:35:54 +020011411 size_t len;
Eric Andersencb57d552001-06-28 07:25:16 +000011412 char line[EOFMARKLEN + 1];
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011413 struct nodelist *bqlist;
11414 smallint quotef;
11415 smallint dblquote;
11416 smallint oldstyle;
Denys Vlasenko0b883582016-12-23 16:49:07 +010011417 IF_FEATURE_SH_MATH(smallint prevsyntax;) /* syntax before arithmetic */
Denis Vlasenko46a53062007-09-24 18:30:02 +000011418#if ENABLE_ASH_EXPAND_PRMT
11419 smallint pssyntax; /* we are expanding a prompt string */
11420#endif
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011421 int varnest; /* levels of variables expansion */
Denys Vlasenko0b883582016-12-23 16:49:07 +010011422 IF_FEATURE_SH_MATH(int arinest;) /* levels of arithmetic expansion */
11423 IF_FEATURE_SH_MATH(int parenlevel;) /* levels of parens in arithmetic */
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011424 int dqvarnest; /* levels of variables expansion within double quotes */
11425
Denis Vlasenko5e34ff22009-04-21 11:09:40 +000011426 IF_ASH_BASH_COMPAT(smallint bash_dollar_squote = 0;)
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011427
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011428 startlinno = g_parsefile->linno;
Eric Andersencb57d552001-06-28 07:25:16 +000011429 bqlist = NULL;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011430 quotef = 0;
Denys Vlasenko0b883582016-12-23 16:49:07 +010011431 IF_FEATURE_SH_MATH(prevsyntax = 0;)
Denis Vlasenko46a53062007-09-24 18:30:02 +000011432#if ENABLE_ASH_EXPAND_PRMT
11433 pssyntax = (syntax == PSSYNTAX);
11434 if (pssyntax)
11435 syntax = DQSYNTAX;
11436#endif
11437 dblquote = (syntax == DQSYNTAX);
Eric Andersencb57d552001-06-28 07:25:16 +000011438 varnest = 0;
Denys Vlasenko0b883582016-12-23 16:49:07 +010011439 IF_FEATURE_SH_MATH(arinest = 0;)
11440 IF_FEATURE_SH_MATH(parenlevel = 0;)
Eric Andersencb57d552001-06-28 07:25:16 +000011441 dqvarnest = 0;
11442
11443 STARTSTACKSTR(out);
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011444 loop:
11445 /* For each line, until end of word */
Denys Vlasenko958581a2010-09-12 15:04:27 +020011446 CHECKEND(); /* set c to PEOF if at end of here document */
11447 for (;;) { /* until end of line or end of word */
11448 CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */
11449 switch (SIT(c, syntax)) {
11450 case CNL: /* '\n' */
11451 if (syntax == BASESYNTAX)
11452 goto endword; /* exit outer loop */
11453 USTPUTC(c, out);
Denys Vlasenkoce332a22016-10-02 23:47:34 +020011454 nlprompt();
Denys Vlasenko958581a2010-09-12 15:04:27 +020011455 c = pgetc();
11456 goto loop; /* continue outer loop */
11457 case CWORD:
11458 USTPUTC(c, out);
11459 break;
11460 case CCTL:
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011461#if ENABLE_ASH_BASH_COMPAT
Denys Vlasenko958581a2010-09-12 15:04:27 +020011462 if (c == '\\' && bash_dollar_squote) {
11463 c = decode_dollar_squote();
Denys Vlasenko13f20912016-09-25 20:54:25 +020011464 if (c == '\0') {
11465 /* skip $'\000', $'\x00' (like bash) */
11466 break;
11467 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020011468 if (c & 0x100) {
Denys Vlasenko13f20912016-09-25 20:54:25 +020011469 /* Unknown escape. Encode as '\z' */
Denys Vlasenko958581a2010-09-12 15:04:27 +020011470 c = (unsigned char)c;
Denys Vlasenko13f20912016-09-25 20:54:25 +020011471 if (eofmark == NULL || dblquote)
11472 USTPUTC(CTLESC, out);
11473 USTPUTC('\\', out);
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011474 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020011475 }
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011476#endif
Denys Vlasenko13f20912016-09-25 20:54:25 +020011477 if (eofmark == NULL || dblquote)
11478 USTPUTC(CTLESC, out);
Denys Vlasenko958581a2010-09-12 15:04:27 +020011479 USTPUTC(c, out);
11480 break;
11481 case CBACK: /* backslash */
11482 c = pgetc_without_PEOA();
11483 if (c == PEOF) {
11484 USTPUTC(CTLESC, out);
11485 USTPUTC('\\', out);
11486 pungetc();
11487 } else if (c == '\n') {
Denys Vlasenkoce332a22016-10-02 23:47:34 +020011488 nlprompt();
Denys Vlasenko958581a2010-09-12 15:04:27 +020011489 } else {
11490#if ENABLE_ASH_EXPAND_PRMT
11491 if (c == '$' && pssyntax) {
Eric Andersenc470f442003-07-28 09:56:35 +000011492 USTPUTC(CTLESC, out);
Eric Andersencb57d552001-06-28 07:25:16 +000011493 USTPUTC('\\', out);
Denys Vlasenko958581a2010-09-12 15:04:27 +020011494 }
Denis Vlasenko46a53062007-09-24 18:30:02 +000011495#endif
Denys Vlasenko958581a2010-09-12 15:04:27 +020011496 /* Backslash is retained if we are in "str" and next char isn't special */
11497 if (dblquote
11498 && c != '\\'
11499 && c != '`'
11500 && c != '$'
11501 && (c != '"' || eofmark != NULL)
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011502 ) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020011503 USTPUTC('\\', out);
Eric Andersencb57d552001-06-28 07:25:16 +000011504 }
Ron Yorston549deab2015-05-18 09:57:51 +020011505 USTPUTC(CTLESC, out);
Denys Vlasenko0ff78a02010-08-30 15:20:07 +020011506 USTPUTC(c, out);
Denys Vlasenko958581a2010-09-12 15:04:27 +020011507 quotef = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011508 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020011509 break;
11510 case CSQUOTE:
11511 syntax = SQSYNTAX;
11512 quotemark:
11513 if (eofmark == NULL) {
11514 USTPUTC(CTLQUOTEMARK, out);
11515 }
11516 break;
11517 case CDQUOTE:
11518 syntax = DQSYNTAX;
11519 dblquote = 1;
11520 goto quotemark;
11521 case CENDQUOTE:
11522 IF_ASH_BASH_COMPAT(bash_dollar_squote = 0;)
Ron Yorston7e4ed262015-05-18 09:54:43 +020011523 if (eofmark != NULL && varnest == 0) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020011524 USTPUTC(c, out);
11525 } else {
11526 if (dqvarnest == 0) {
11527 syntax = BASESYNTAX;
11528 dblquote = 0;
11529 }
11530 quotef = 1;
11531 goto quotemark;
11532 }
11533 break;
11534 case CVAR: /* '$' */
11535 PARSESUB(); /* parse substitution */
11536 break;
11537 case CENDVAR: /* '}' */
11538 if (varnest > 0) {
11539 varnest--;
11540 if (dqvarnest > 0) {
11541 dqvarnest--;
11542 }
11543 c = CTLENDVAR;
11544 }
11545 USTPUTC(c, out);
11546 break;
Denys Vlasenko0b883582016-12-23 16:49:07 +010011547#if ENABLE_FEATURE_SH_MATH
Denys Vlasenko958581a2010-09-12 15:04:27 +020011548 case CLP: /* '(' in arithmetic */
11549 parenlevel++;
11550 USTPUTC(c, out);
11551 break;
11552 case CRP: /* ')' in arithmetic */
11553 if (parenlevel > 0) {
11554 parenlevel--;
11555 } else {
Denys Vlasenko459293b2016-09-29 17:58:58 +020011556 if (pgetc_eatbnl() == ')') {
Ron Yorstonad88bde2015-05-18 09:56:16 +020011557 c = CTLENDARI;
Denys Vlasenko958581a2010-09-12 15:04:27 +020011558 if (--arinest == 0) {
11559 syntax = prevsyntax;
Denys Vlasenko958581a2010-09-12 15:04:27 +020011560 }
11561 } else {
11562 /*
11563 * unbalanced parens
11564 * (don't 2nd guess - no error)
11565 */
11566 pungetc();
11567 }
11568 }
11569 USTPUTC(c, out);
11570 break;
11571#endif
11572 case CBQUOTE: /* '`' */
11573 PARSEBACKQOLD();
11574 break;
11575 case CENDFILE:
11576 goto endword; /* exit outer loop */
11577 case CIGN:
11578 break;
11579 default:
11580 if (varnest == 0) {
11581#if ENABLE_ASH_BASH_COMPAT
11582 if (c == '&') {
Denys Vlasenko459293b2016-09-29 17:58:58 +020011583//Can't call pgetc_eatbnl() here, this requires three-deep pungetc()
Denys Vlasenko958581a2010-09-12 15:04:27 +020011584 if (pgetc() == '>')
11585 c = 0x100 + '>'; /* flag &> */
11586 pungetc();
11587 }
11588#endif
11589 goto endword; /* exit outer loop */
11590 }
11591 IF_ASH_ALIAS(if (c != PEOA))
11592 USTPUTC(c, out);
11593 }
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020011594 c = pgetc();
Denys Vlasenko958581a2010-09-12 15:04:27 +020011595 } /* for (;;) */
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011596 endword:
Denys Vlasenko958581a2010-09-12 15:04:27 +020011597
Denys Vlasenko0b883582016-12-23 16:49:07 +010011598#if ENABLE_FEATURE_SH_MATH
Eric Andersencb57d552001-06-28 07:25:16 +000011599 if (syntax == ARISYNTAX)
Denis Vlasenko559691a2008-10-05 18:39:31 +000011600 raise_error_syntax("missing '))'");
Eric Andersenc470f442003-07-28 09:56:35 +000011601#endif
Ron Yorston0e056f72015-07-01 16:45:40 +010011602 if (syntax != BASESYNTAX && eofmark == NULL)
Denis Vlasenko559691a2008-10-05 18:39:31 +000011603 raise_error_syntax("unterminated quoted string");
Eric Andersencb57d552001-06-28 07:25:16 +000011604 if (varnest != 0) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011605 startlinno = g_parsefile->linno;
Eric Andersenc470f442003-07-28 09:56:35 +000011606 /* { */
Denis Vlasenko559691a2008-10-05 18:39:31 +000011607 raise_error_syntax("missing '}'");
Eric Andersencb57d552001-06-28 07:25:16 +000011608 }
11609 USTPUTC('\0', out);
Eric Andersenc470f442003-07-28 09:56:35 +000011610 len = out - (char *)stackblock();
Eric Andersencb57d552001-06-28 07:25:16 +000011611 out = stackblock();
11612 if (eofmark == NULL) {
Denis Vlasenko5e34ff22009-04-21 11:09:40 +000011613 if ((c == '>' || c == '<' IF_ASH_BASH_COMPAT( || c == 0x100 + '>'))
Denis Vlasenko834dee72008-10-07 09:18:30 +000011614 && quotef == 0
11615 ) {
Denis Vlasenko559691a2008-10-05 18:39:31 +000011616 if (isdigit_str9(out)) {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000011617 PARSEREDIR(); /* passed as params: out, c */
11618 lasttoken = TREDIR;
11619 return lasttoken;
11620 }
11621 /* else: non-number X seen, interpret it
11622 * as "NNNX>file" = "NNNX >file" */
Eric Andersencb57d552001-06-28 07:25:16 +000011623 }
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011624 pungetc();
Eric Andersencb57d552001-06-28 07:25:16 +000011625 }
11626 quoteflag = quotef;
11627 backquotelist = bqlist;
11628 grabstackblock(len);
11629 wordtext = out;
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011630 lasttoken = TWORD;
11631 return lasttoken;
Eric Andersencb57d552001-06-28 07:25:16 +000011632/* end of readtoken routine */
11633
Eric Andersencb57d552001-06-28 07:25:16 +000011634/*
11635 * Check to see whether we are at the end of the here document. When this
11636 * is called, c is set to the first character of the next input line. If
11637 * we are at the end of the here document, this routine sets the c to PEOF.
11638 */
Eric Andersenc470f442003-07-28 09:56:35 +000011639checkend: {
11640 if (eofmark) {
Denis Vlasenko131ae172007-02-18 13:00:19 +000011641#if ENABLE_ASH_ALIAS
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010011642 if (c == PEOA)
11643 c = pgetc_without_PEOA();
Eric Andersenc470f442003-07-28 09:56:35 +000011644#endif
11645 if (striptabs) {
11646 while (c == '\t') {
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010011647 c = pgetc_without_PEOA();
Eric Andersencb57d552001-06-28 07:25:16 +000011648 }
Eric Andersenc470f442003-07-28 09:56:35 +000011649 }
11650 if (c == *eofmark) {
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011651 if (pfgets(line, sizeof(line)) != NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +000011652 char *p, *q;
Denys Vlasenko350e6862016-10-26 16:26:45 +020011653 int cc;
Eric Andersencb57d552001-06-28 07:25:16 +000011654
Eric Andersenc470f442003-07-28 09:56:35 +000011655 p = line;
Denys Vlasenko350e6862016-10-26 16:26:45 +020011656 for (q = eofmark + 1;; p++, q++) {
11657 cc = *p;
11658 if (cc == '\n')
11659 cc = 0;
11660 if (!*q || cc != *q)
11661 break;
11662 }
11663 if (cc == *q) {
Eric Andersenc470f442003-07-28 09:56:35 +000011664 c = PEOF;
Denys Vlasenkoce332a22016-10-02 23:47:34 +020011665 nlnoprompt();
Eric Andersenc470f442003-07-28 09:56:35 +000011666 } else {
11667 pushstring(line, NULL);
Eric Andersencb57d552001-06-28 07:25:16 +000011668 }
11669 }
11670 }
11671 }
Eric Andersenc470f442003-07-28 09:56:35 +000011672 goto checkend_return;
11673}
Eric Andersencb57d552001-06-28 07:25:16 +000011674
Eric Andersencb57d552001-06-28 07:25:16 +000011675/*
11676 * Parse a redirection operator. The variable "out" points to a string
11677 * specifying the fd to be redirected. The variable "c" contains the
11678 * first character of the redirection operator.
11679 */
Eric Andersenc470f442003-07-28 09:56:35 +000011680parseredir: {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000011681 /* out is already checked to be a valid number or "" */
11682 int fd = (*out == '\0' ? -1 : atoi(out));
Eric Andersenc470f442003-07-28 09:56:35 +000011683 union node *np;
Eric Andersencb57d552001-06-28 07:25:16 +000011684
Denis Vlasenko597906c2008-02-20 16:38:54 +000011685 np = stzalloc(sizeof(struct nfile));
Eric Andersenc470f442003-07-28 09:56:35 +000011686 if (c == '>') {
11687 np->nfile.fd = 1;
11688 c = pgetc();
11689 if (c == '>')
11690 np->type = NAPPEND;
11691 else if (c == '|')
11692 np->type = NCLOBBER;
11693 else if (c == '&')
11694 np->type = NTOFD;
Denis Vlasenko559691a2008-10-05 18:39:31 +000011695 /* it also can be NTO2 (>&file), but we can't figure it out yet */
Eric Andersenc470f442003-07-28 09:56:35 +000011696 else {
11697 np->type = NTO;
11698 pungetc();
Eric Andersencb57d552001-06-28 07:25:16 +000011699 }
Denis Vlasenko834dee72008-10-07 09:18:30 +000011700 }
11701#if ENABLE_ASH_BASH_COMPAT
11702 else if (c == 0x100 + '>') { /* this flags &> redirection */
11703 np->nfile.fd = 1;
11704 pgetc(); /* this is '>', no need to check */
11705 np->type = NTO2;
11706 }
11707#endif
11708 else { /* c == '<' */
Denis Vlasenko597906c2008-02-20 16:38:54 +000011709 /*np->nfile.fd = 0; - stzalloc did it */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011710 c = pgetc();
11711 switch (c) {
Eric Andersenc470f442003-07-28 09:56:35 +000011712 case '<':
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011713 if (sizeof(struct nfile) != sizeof(struct nhere)) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011714 np = stzalloc(sizeof(struct nhere));
11715 /*np->nfile.fd = 0; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011716 }
11717 np->type = NHERE;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011718 heredoc = stzalloc(sizeof(struct heredoc));
Eric Andersenc470f442003-07-28 09:56:35 +000011719 heredoc->here = np;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011720 c = pgetc();
11721 if (c == '-') {
Eric Andersenc470f442003-07-28 09:56:35 +000011722 heredoc->striptabs = 1;
11723 } else {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011724 /*heredoc->striptabs = 0; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011725 pungetc();
11726 }
11727 break;
11728
11729 case '&':
11730 np->type = NFROMFD;
11731 break;
11732
11733 case '>':
11734 np->type = NFROMTO;
11735 break;
11736
11737 default:
11738 np->type = NFROM;
11739 pungetc();
11740 break;
11741 }
Eric Andersencb57d552001-06-28 07:25:16 +000011742 }
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000011743 if (fd >= 0)
11744 np->nfile.fd = fd;
Eric Andersenc470f442003-07-28 09:56:35 +000011745 redirnode = np;
11746 goto parseredir_return;
11747}
Eric Andersencb57d552001-06-28 07:25:16 +000011748
Eric Andersencb57d552001-06-28 07:25:16 +000011749/*
11750 * Parse a substitution. At this point, we have read the dollar sign
11751 * and nothing else.
11752 */
Denis Vlasenkocc571512007-02-23 21:10:35 +000011753
11754/* is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise
11755 * (assuming ascii char codes, as the original implementation did) */
11756#define is_special(c) \
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011757 (((unsigned)(c) - 33 < 32) \
11758 && ((0xc1ff920dU >> ((unsigned)(c) - 33)) & 1))
Eric Andersenc470f442003-07-28 09:56:35 +000011759parsesub: {
Denys Vlasenkocd716832009-11-28 22:14:02 +010011760 unsigned char subtype;
Eric Andersenc470f442003-07-28 09:56:35 +000011761 int typeloc;
Eric Andersencb57d552001-06-28 07:25:16 +000011762
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011763 c = pgetc_eatbnl();
Denys Vlasenkocd716832009-11-28 22:14:02 +010011764 if (c > 255 /* PEOA or PEOF */
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011765 || (c != '(' && c != '{' && !is_name(c) && !is_special(c))
Eric Andersenc470f442003-07-28 09:56:35 +000011766 ) {
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011767#if ENABLE_ASH_BASH_COMPAT
Ron Yorston84ba50c2016-04-03 22:43:14 +010011768 if (syntax != DQSYNTAX && c == '\'')
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011769 bash_dollar_squote = 1;
11770 else
11771#endif
11772 USTPUTC('$', out);
Eric Andersenc470f442003-07-28 09:56:35 +000011773 pungetc();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011774 } else if (c == '(') {
11775 /* $(command) or $((arith)) */
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011776 if (pgetc_eatbnl() == '(') {
Denys Vlasenko0b883582016-12-23 16:49:07 +010011777#if ENABLE_FEATURE_SH_MATH
Eric Andersenc470f442003-07-28 09:56:35 +000011778 PARSEARITH();
11779#else
Mike Frysinger98a6f562008-06-09 09:38:45 +000011780 raise_error_syntax("you disabled math support for $((arith)) syntax");
Eric Andersenc470f442003-07-28 09:56:35 +000011781#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011782 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000011783 pungetc();
11784 PARSEBACKQNEW();
11785 }
11786 } else {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011787 /* $VAR, $<specialchar>, ${...}, or PEOA/PEOF */
Eric Andersenc470f442003-07-28 09:56:35 +000011788 USTPUTC(CTLVAR, out);
11789 typeloc = out - (char *)stackblock();
Denys Vlasenko3df14102016-10-26 16:41:13 +020011790 STADJUST(1, out);
Eric Andersenc470f442003-07-28 09:56:35 +000011791 subtype = VSNORMAL;
11792 if (c == '{') {
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011793 c = pgetc_eatbnl();
Denys Vlasenkof15aa572016-10-26 15:56:53 +020011794 subtype = 0;
Eric Andersenc470f442003-07-28 09:56:35 +000011795 }
Denys Vlasenkof15aa572016-10-26 15:56:53 +020011796 varname:
Denys Vlasenko3df14102016-10-26 16:41:13 +020011797 if (is_name(c)) {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011798 /* $[{[#]]NAME[}] */
Eric Andersenc470f442003-07-28 09:56:35 +000011799 do {
11800 STPUTC(c, out);
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011801 c = pgetc_eatbnl();
Denys Vlasenko3df14102016-10-26 16:41:13 +020011802 } while (is_in_name(c));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011803 } else if (isdigit(c)) {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011804 /* $[{[#]]NUM[}] */
Eric Andersenc470f442003-07-28 09:56:35 +000011805 do {
11806 STPUTC(c, out);
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011807 c = pgetc_eatbnl();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011808 } while (isdigit(c));
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011809 } else if (is_special(c)) {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011810 /* $[{[#]]<specialchar>[}] */
Denys Vlasenkof15aa572016-10-26 15:56:53 +020011811 int cc = c;
11812
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011813 c = pgetc_eatbnl();
Denys Vlasenkof15aa572016-10-26 15:56:53 +020011814 if (!subtype && cc == '#') {
11815 subtype = VSLENGTH;
11816 if (c == '_' || isalnum(c))
11817 goto varname;
11818 cc = c;
11819 c = pgetc_eatbnl();
11820 if (cc == '}' || c != '}') {
11821 pungetc();
11822 subtype = 0;
11823 c = cc;
11824 cc = '#';
11825 }
11826 }
11827 USTPUTC(cc, out);
Denis Vlasenko559691a2008-10-05 18:39:31 +000011828 } else {
Denys Vlasenko88e15702016-10-26 01:55:56 +020011829 goto badsub;
Denis Vlasenko559691a2008-10-05 18:39:31 +000011830 }
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011831 if (c != '}' && subtype == VSLENGTH) {
11832 /* ${#VAR didn't end with } */
Cristian Ionescu-Idbohrn301f5ec2009-10-05 02:07:23 +020011833 goto badsub;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011834 }
Eric Andersencb57d552001-06-28 07:25:16 +000011835
Eric Andersenc470f442003-07-28 09:56:35 +000011836 if (subtype == 0) {
Denys Vlasenkof8ddbe12016-07-25 03:56:00 +020011837 static const char types[] ALIGN1 = "}-+?=";
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011838 /* ${VAR...} but not $VAR or ${#VAR} */
11839 /* c == first char after VAR */
Eric Andersenc470f442003-07-28 09:56:35 +000011840 switch (c) {
11841 case ':':
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011842 c = pgetc_eatbnl();
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011843#if ENABLE_ASH_BASH_COMPAT
Denys Vlasenkof8ddbe12016-07-25 03:56:00 +020011844 /* This check is only needed to not misinterpret
11845 * ${VAR:-WORD}, ${VAR:+WORD}, ${VAR:=WORD}, ${VAR:?WORD}
11846 * constructs.
11847 */
11848 if (!strchr(types, c)) {
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011849 subtype = VSSUBSTR;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011850 pungetc();
Denys Vlasenko88e15702016-10-26 01:55:56 +020011851 break; /* "goto badsub" is bigger (!) */
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011852 }
11853#endif
Denys Vlasenko3df14102016-10-26 16:41:13 +020011854 subtype = VSNUL;
Eric Andersenc470f442003-07-28 09:56:35 +000011855 /*FALLTHROUGH*/
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011856 default: {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011857 const char *p = strchr(types, c);
Eric Andersenc470f442003-07-28 09:56:35 +000011858 if (p == NULL)
Denys Vlasenko88e15702016-10-26 01:55:56 +020011859 break;
Denys Vlasenko3df14102016-10-26 16:41:13 +020011860 subtype |= p - types + VSNORMAL;
Eric Andersenc470f442003-07-28 09:56:35 +000011861 break;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011862 }
Eric Andersenc470f442003-07-28 09:56:35 +000011863 case '%':
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011864 case '#': {
11865 int cc = c;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011866 subtype = (c == '#' ? VSTRIMLEFT : VSTRIMRIGHT);
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011867 c = pgetc_eatbnl();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011868 if (c != cc)
Denys Vlasenko88e15702016-10-26 01:55:56 +020011869 goto badsub;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011870 subtype++;
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011871 break;
11872 }
11873#if ENABLE_ASH_BASH_COMPAT
11874 case '/':
Denys Vlasenko6040fe82010-09-12 15:03:16 +020011875 /* ${v/[/]pattern/repl} */
11876//TODO: encode pattern and repl separately.
11877// Currently ${v/$var_with_slash/repl} is horribly broken
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011878 subtype = VSREPLACE;
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011879 c = pgetc_eatbnl();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011880 if (c != '/')
Denys Vlasenko88e15702016-10-26 01:55:56 +020011881 goto badsub;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011882 subtype++; /* VSREPLACEALL */
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011883 break;
11884#endif
Eric Andersencb57d552001-06-28 07:25:16 +000011885 }
Eric Andersenc470f442003-07-28 09:56:35 +000011886 } else {
Denys Vlasenko88e15702016-10-26 01:55:56 +020011887 badsub:
Eric Andersenc470f442003-07-28 09:56:35 +000011888 pungetc();
11889 }
Denys Vlasenko3df14102016-10-26 16:41:13 +020011890 ((unsigned char *)stackblock())[typeloc] = subtype;
Eric Andersenc470f442003-07-28 09:56:35 +000011891 if (subtype != VSNORMAL) {
11892 varnest++;
Denys Vlasenko3df14102016-10-26 16:41:13 +020011893 if (dblquote)
Eric Andersenc470f442003-07-28 09:56:35 +000011894 dqvarnest++;
Eric Andersencb57d552001-06-28 07:25:16 +000011895 }
Denys Vlasenko88e15702016-10-26 01:55:56 +020011896 STPUTC('=', out);
Eric Andersencb57d552001-06-28 07:25:16 +000011897 }
Eric Andersenc470f442003-07-28 09:56:35 +000011898 goto parsesub_return;
11899}
Eric Andersencb57d552001-06-28 07:25:16 +000011900
Eric Andersencb57d552001-06-28 07:25:16 +000011901/*
11902 * Called to parse command substitutions. Newstyle is set if the command
11903 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
11904 * list of commands (passed by reference), and savelen is the number of
11905 * characters on the top of the stack which must be preserved.
11906 */
Eric Andersenc470f442003-07-28 09:56:35 +000011907parsebackq: {
11908 struct nodelist **nlpp;
Eric Andersenc470f442003-07-28 09:56:35 +000011909 union node *n;
Ron Yorston072fc602015-07-01 16:46:18 +010011910 char *str;
Eric Andersenc470f442003-07-28 09:56:35 +000011911 size_t savelen;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011912 smallint saveprompt = 0;
11913
Eric Andersenc470f442003-07-28 09:56:35 +000011914 str = NULL;
11915 savelen = out - (char *)stackblock();
11916 if (savelen > 0) {
Denys Vlasenko7bc3d392016-09-17 20:53:47 +020011917 /*
11918 * FIXME: this can allocate very large block on stack and SEGV.
11919 * Example:
11920 * echo "..<100kbytes>..`true` $(true) `true` ..."
Denys Vlasenko73737592016-09-17 20:58:22 +020011921 * allocates 100kb for every command subst. With about
Denys Vlasenko7bc3d392016-09-17 20:53:47 +020011922 * a hundred command substitutions stack overflows.
11923 * With larger prepended string, SEGV happens sooner.
11924 */
Ron Yorston072fc602015-07-01 16:46:18 +010011925 str = alloca(savelen);
Eric Andersenc470f442003-07-28 09:56:35 +000011926 memcpy(str, stackblock(), savelen);
11927 }
Denys Vlasenko7bc3d392016-09-17 20:53:47 +020011928
Eric Andersenc470f442003-07-28 09:56:35 +000011929 if (oldstyle) {
11930 /* We must read until the closing backquote, giving special
Denys Vlasenko60cb48c2013-01-14 15:57:44 +010011931 * treatment to some slashes, and then push the string and
11932 * reread it as input, interpreting it normally.
11933 */
Eric Andersenc470f442003-07-28 09:56:35 +000011934 char *pout;
Eric Andersenc470f442003-07-28 09:56:35 +000011935 size_t psavelen;
11936 char *pstr;
11937
Eric Andersenc470f442003-07-28 09:56:35 +000011938 STARTSTACKSTR(pout);
11939 for (;;) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020011940 int pc;
11941
11942 setprompt_if(needprompt, 2);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011943 pc = pgetc();
11944 switch (pc) {
Eric Andersenc470f442003-07-28 09:56:35 +000011945 case '`':
11946 goto done;
11947
11948 case '\\':
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011949 pc = pgetc();
11950 if (pc == '\n') {
Denys Vlasenkoce332a22016-10-02 23:47:34 +020011951 nlprompt();
Eric Andersenc470f442003-07-28 09:56:35 +000011952 /*
11953 * If eating a newline, avoid putting
11954 * the newline into the new character
11955 * stream (via the STPUTC after the
11956 * switch).
11957 */
11958 continue;
11959 }
11960 if (pc != '\\' && pc != '`' && pc != '$'
Denys Vlasenko76bc2d62009-11-29 01:37:46 +010011961 && (!dblquote || pc != '"')
11962 ) {
Eric Andersenc470f442003-07-28 09:56:35 +000011963 STPUTC('\\', pout);
Denys Vlasenko76bc2d62009-11-29 01:37:46 +010011964 }
Denys Vlasenkocd716832009-11-28 22:14:02 +010011965 if (pc <= 255 /* not PEOA or PEOF */) {
Eric Andersenc470f442003-07-28 09:56:35 +000011966 break;
11967 }
11968 /* fall through */
11969
11970 case PEOF:
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010011971 IF_ASH_ALIAS(case PEOA:)
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011972 startlinno = g_parsefile->linno;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011973 raise_error_syntax("EOF in backquote substitution");
Eric Andersenc470f442003-07-28 09:56:35 +000011974
11975 case '\n':
Denys Vlasenkoce332a22016-10-02 23:47:34 +020011976 nlnoprompt();
Eric Andersenc470f442003-07-28 09:56:35 +000011977 break;
11978
11979 default:
11980 break;
11981 }
11982 STPUTC(pc, pout);
11983 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011984 done:
Eric Andersenc470f442003-07-28 09:56:35 +000011985 STPUTC('\0', pout);
11986 psavelen = pout - (char *)stackblock();
11987 if (psavelen > 0) {
11988 pstr = grabstackstr(pout);
11989 setinputstring(pstr);
11990 }
11991 }
11992 nlpp = &bqlist;
11993 while (*nlpp)
11994 nlpp = &(*nlpp)->next;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011995 *nlpp = stzalloc(sizeof(**nlpp));
11996 /* (*nlpp)->next = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011997
11998 if (oldstyle) {
11999 saveprompt = doprompt;
12000 doprompt = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000012001 }
12002
Eric Andersenc470f442003-07-28 09:56:35 +000012003 n = list(2);
12004
12005 if (oldstyle)
12006 doprompt = saveprompt;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012007 else if (readtoken() != TRP)
12008 raise_error_unexpected_syntax(TRP);
Eric Andersenc470f442003-07-28 09:56:35 +000012009
12010 (*nlpp)->n = n;
12011 if (oldstyle) {
12012 /*
12013 * Start reading from old file again, ignoring any pushed back
12014 * tokens left from the backquote parsing
12015 */
12016 popfile();
12017 tokpushback = 0;
12018 }
12019 while (stackblocksize() <= savelen)
12020 growstackblock();
12021 STARTSTACKSTR(out);
12022 if (str) {
12023 memcpy(out, str, savelen);
12024 STADJUST(savelen, out);
Eric Andersenc470f442003-07-28 09:56:35 +000012025 }
Ron Yorston549deab2015-05-18 09:57:51 +020012026 USTPUTC(CTLBACKQ, out);
Eric Andersenc470f442003-07-28 09:56:35 +000012027 if (oldstyle)
12028 goto parsebackq_oldreturn;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000012029 goto parsebackq_newreturn;
Eric Andersenc470f442003-07-28 09:56:35 +000012030}
12031
Denys Vlasenko0b883582016-12-23 16:49:07 +010012032#if ENABLE_FEATURE_SH_MATH
Eric Andersencb57d552001-06-28 07:25:16 +000012033/*
12034 * Parse an arithmetic expansion (indicate start of one and set state)
12035 */
Eric Andersenc470f442003-07-28 09:56:35 +000012036parsearith: {
Eric Andersenc470f442003-07-28 09:56:35 +000012037 if (++arinest == 1) {
12038 prevsyntax = syntax;
12039 syntax = ARISYNTAX;
Eric Andersencb57d552001-06-28 07:25:16 +000012040 }
Ron Yorstonad88bde2015-05-18 09:56:16 +020012041 USTPUTC(CTLARI, out);
Eric Andersenc470f442003-07-28 09:56:35 +000012042 goto parsearith_return;
12043}
12044#endif
Eric Andersenc470f442003-07-28 09:56:35 +000012045} /* end of readtoken */
12046
Eric Andersencb57d552001-06-28 07:25:16 +000012047/*
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012048 * Read the next input token.
12049 * If the token is a word, we set backquotelist to the list of cmds in
12050 * backquotes. We set quoteflag to true if any part of the word was
12051 * quoted.
12052 * If the token is TREDIR, then we set redirnode to a structure containing
12053 * the redirection.
12054 * In all cases, the variable startlinno is set to the number of the line
12055 * on which the token starts.
12056 *
12057 * [Change comment: here documents and internal procedures]
12058 * [Readtoken shouldn't have any arguments. Perhaps we should make the
12059 * word parsing code into a separate routine. In this case, readtoken
12060 * doesn't need to have any internal procedures, but parseword does.
12061 * We could also make parseoperator in essence the main routine, and
12062 * have parseword (readtoken1?) handle both words and redirection.]
Eric Andersencb57d552001-06-28 07:25:16 +000012063 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012064#define NEW_xxreadtoken
12065#ifdef NEW_xxreadtoken
12066/* singles must be first! */
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000012067static const char xxreadtoken_chars[7] ALIGN1 = {
Denis Vlasenko834dee72008-10-07 09:18:30 +000012068 '\n', '(', ')', /* singles */
12069 '&', '|', ';', /* doubles */
12070 0
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000012071};
Eric Andersencb57d552001-06-28 07:25:16 +000012072
Denis Vlasenko834dee72008-10-07 09:18:30 +000012073#define xxreadtoken_singles 3
12074#define xxreadtoken_doubles 3
12075
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000012076static const char xxreadtoken_tokens[] ALIGN1 = {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012077 TNL, TLP, TRP, /* only single occurrence allowed */
12078 TBACKGND, TPIPE, TSEMI, /* if single occurrence */
12079 TEOF, /* corresponds to trailing nul */
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000012080 TAND, TOR, TENDCASE /* if double occurrence */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012081};
12082
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012083static int
12084xxreadtoken(void)
12085{
12086 int c;
12087
12088 if (tokpushback) {
12089 tokpushback = 0;
12090 return lasttoken;
Eric Andersencb57d552001-06-28 07:25:16 +000012091 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020012092 setprompt_if(needprompt, 2);
Denis Vlasenko41eb3002008-11-28 03:42:31 +000012093 startlinno = g_parsefile->linno;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012094 for (;;) { /* until token or start of word found */
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020012095 c = pgetc();
Denis Vlasenko5e34ff22009-04-21 11:09:40 +000012096 if (c == ' ' || c == '\t' IF_ASH_ALIAS( || c == PEOA))
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012097 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012098
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012099 if (c == '#') {
12100 while ((c = pgetc()) != '\n' && c != PEOF)
12101 continue;
12102 pungetc();
12103 } else if (c == '\\') {
12104 if (pgetc() != '\n') {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012105 pungetc();
Denis Vlasenko834dee72008-10-07 09:18:30 +000012106 break; /* return readtoken1(...) */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012107 }
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012108 nlprompt();
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012109 } else {
12110 const char *p;
12111
12112 p = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
12113 if (c != PEOF) {
12114 if (c == '\n') {
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012115 nlnoprompt();
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012116 }
12117
12118 p = strchr(xxreadtoken_chars, c);
Denis Vlasenko834dee72008-10-07 09:18:30 +000012119 if (p == NULL)
12120 break; /* return readtoken1(...) */
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012121
Denis Vlasenko834dee72008-10-07 09:18:30 +000012122 if ((int)(p - xxreadtoken_chars) >= xxreadtoken_singles) {
12123 int cc = pgetc();
12124 if (cc == c) { /* double occurrence? */
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012125 p += xxreadtoken_doubles + 1;
12126 } else {
12127 pungetc();
Denis Vlasenko834dee72008-10-07 09:18:30 +000012128#if ENABLE_ASH_BASH_COMPAT
12129 if (c == '&' && cc == '>') /* &> */
12130 break; /* return readtoken1(...) */
12131#endif
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012132 }
12133 }
12134 }
12135 lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
12136 return lasttoken;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012137 }
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012138 } /* for (;;) */
Denis Vlasenko834dee72008-10-07 09:18:30 +000012139
12140 return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012141}
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012142#else /* old xxreadtoken */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012143#define RETURN(token) return lasttoken = token
12144static int
12145xxreadtoken(void)
12146{
12147 int c;
12148
12149 if (tokpushback) {
12150 tokpushback = 0;
12151 return lasttoken;
12152 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020012153 setprompt_if(needprompt, 2);
Denis Vlasenko41eb3002008-11-28 03:42:31 +000012154 startlinno = g_parsefile->linno;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012155 for (;;) { /* until token or start of word found */
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020012156 c = pgetc();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012157 switch (c) {
12158 case ' ': case '\t':
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010012159 IF_ASH_ALIAS(case PEOA:)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012160 continue;
12161 case '#':
Denis Vlasenkof7d56652008-03-25 05:51:41 +000012162 while ((c = pgetc()) != '\n' && c != PEOF)
12163 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012164 pungetc();
12165 continue;
12166 case '\\':
12167 if (pgetc() == '\n') {
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012168 nlprompt();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012169 continue;
12170 }
12171 pungetc();
12172 goto breakloop;
12173 case '\n':
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012174 nlnoprompt();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012175 RETURN(TNL);
12176 case PEOF:
12177 RETURN(TEOF);
12178 case '&':
12179 if (pgetc() == '&')
12180 RETURN(TAND);
12181 pungetc();
12182 RETURN(TBACKGND);
12183 case '|':
12184 if (pgetc() == '|')
12185 RETURN(TOR);
12186 pungetc();
12187 RETURN(TPIPE);
12188 case ';':
12189 if (pgetc() == ';')
12190 RETURN(TENDCASE);
12191 pungetc();
12192 RETURN(TSEMI);
12193 case '(':
12194 RETURN(TLP);
12195 case ')':
12196 RETURN(TRP);
12197 default:
12198 goto breakloop;
12199 }
12200 }
12201 breakloop:
12202 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
12203#undef RETURN
12204}
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012205#endif /* old xxreadtoken */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012206
12207static int
12208readtoken(void)
12209{
12210 int t;
Ron Yorston713f07d2015-10-29 16:44:56 +000012211 int kwd = checkkwd;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012212#if DEBUG
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000012213 smallint alreadyseen = tokpushback;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012214#endif
12215
12216#if ENABLE_ASH_ALIAS
12217 top:
12218#endif
12219
12220 t = xxreadtoken();
12221
12222 /*
12223 * eat newlines
12224 */
Ron Yorston713f07d2015-10-29 16:44:56 +000012225 if (kwd & CHKNL) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012226 while (t == TNL) {
12227 parseheredoc();
12228 t = xxreadtoken();
12229 }
12230 }
12231
12232 if (t != TWORD || quoteflag) {
12233 goto out;
12234 }
12235
12236 /*
12237 * check for keywords
12238 */
Ron Yorston713f07d2015-10-29 16:44:56 +000012239 if (kwd & CHKKWD) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012240 const char *const *pp;
12241
12242 pp = findkwd(wordtext);
12243 if (pp) {
12244 lasttoken = t = pp - tokname_array;
Denys Vlasenko888527c2016-10-02 16:54:17 +020012245 TRACE(("keyword '%s' recognized\n", tokname_array[t]));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012246 goto out;
12247 }
12248 }
12249
12250 if (checkkwd & CHKALIAS) {
12251#if ENABLE_ASH_ALIAS
12252 struct alias *ap;
12253 ap = lookupalias(wordtext, 1);
12254 if (ap != NULL) {
12255 if (*ap->val) {
12256 pushstring(ap->val, ap);
12257 }
12258 goto top;
12259 }
12260#endif
12261 }
12262 out:
12263 checkkwd = 0;
12264#if DEBUG
12265 if (!alreadyseen)
Denys Vlasenko888527c2016-10-02 16:54:17 +020012266 TRACE(("token '%s' %s\n", tokname_array[t], t == TWORD ? wordtext : ""));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012267 else
Denys Vlasenko888527c2016-10-02 16:54:17 +020012268 TRACE(("reread token '%s' %s\n", tokname_array[t], t == TWORD ? wordtext : ""));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012269#endif
12270 return t;
Eric Andersencb57d552001-06-28 07:25:16 +000012271}
12272
Ron Yorstonc0e00762015-10-29 11:30:55 +000012273static int
Ron Yorston6bd2fab2015-10-29 11:30:22 +000012274peektoken(void)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012275{
12276 int t;
12277
12278 t = readtoken();
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000012279 tokpushback = 1;
Ron Yorstonc0e00762015-10-29 11:30:55 +000012280 return t;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012281}
Eric Andersencb57d552001-06-28 07:25:16 +000012282
12283/*
Denys Vlasenko86e83ec2009-07-23 22:07:07 +020012284 * Read and parse a command. Returns NODE_EOF on end of file.
12285 * (NULL is a valid parse tree indicating a blank line.)
Eric Andersencb57d552001-06-28 07:25:16 +000012286 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012287static union node *
12288parsecmd(int interact)
Eric Andersen90898442003-08-06 11:20:52 +000012289{
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012290 tokpushback = 0;
Ron Yorstonc0e00762015-10-29 11:30:55 +000012291 checkkwd = 0;
12292 heredoclist = 0;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012293 doprompt = interact;
Denys Vlasenko958581a2010-09-12 15:04:27 +020012294 setprompt_if(doprompt, doprompt);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012295 needprompt = 0;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012296 return list(1);
12297}
12298
12299/*
12300 * Input any here documents.
12301 */
12302static void
12303parseheredoc(void)
12304{
12305 struct heredoc *here;
12306 union node *n;
12307
12308 here = heredoclist;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000012309 heredoclist = NULL;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012310
12311 while (here) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020012312 setprompt_if(needprompt, 2);
12313 readtoken1(pgetc(), here->here->type == NHERE ? SQSYNTAX : DQSYNTAX,
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012314 here->eofmark, here->striptabs);
Denis Vlasenko597906c2008-02-20 16:38:54 +000012315 n = stzalloc(sizeof(struct narg));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012316 n->narg.type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000012317 /*n->narg.next = NULL; - stzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012318 n->narg.text = wordtext;
12319 n->narg.backquote = backquotelist;
12320 here->here->nhere.doc = n;
12321 here = here->next;
Eric Andersencb57d552001-06-28 07:25:16 +000012322 }
Eric Andersencb57d552001-06-28 07:25:16 +000012323}
12324
12325
12326/*
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000012327 * called by editline -- any expansions to the prompt should be added here.
Eric Andersencb57d552001-06-28 07:25:16 +000012328 */
Denis Vlasenko131ae172007-02-18 13:00:19 +000012329#if ENABLE_ASH_EXPAND_PRMT
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012330static const char *
12331expandstr(const char *ps)
12332{
12333 union node n;
Denys Vlasenko2a6d29a2016-10-25 21:17:52 +020012334 int saveprompt;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012335
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000012336 /* XXX Fix (char *) cast. It _is_ a bug. ps is variable's value,
12337 * and token processing _can_ alter it (delete NULs etc). */
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012338 setinputstring((char *)ps);
Denys Vlasenko2a6d29a2016-10-25 21:17:52 +020012339
12340 saveprompt = doprompt;
12341 doprompt = 0;
Denis Vlasenko46a53062007-09-24 18:30:02 +000012342 readtoken1(pgetc(), PSSYNTAX, nullstr, 0);
Denys Vlasenko2a6d29a2016-10-25 21:17:52 +020012343 doprompt = saveprompt;
12344
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012345 popfile();
12346
12347 n.narg.type = NARG;
12348 n.narg.next = NULL;
12349 n.narg.text = wordtext;
12350 n.narg.backquote = backquotelist;
12351
Ron Yorston549deab2015-05-18 09:57:51 +020012352 expandarg(&n, NULL, EXP_QUOTED);
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012353 return stackblock();
12354}
12355#endif
12356
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012357/*
12358 * Execute a command or commands contained in a string.
12359 */
12360static int
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020012361evalstring(char *s, int flags)
Eric Andersenc470f442003-07-28 09:56:35 +000012362{
Denys Vlasenko493b9ca2016-10-30 18:27:14 +010012363 struct jmploc *volatile savehandler;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012364 struct jmploc jmploc;
12365 int ex;
12366
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012367 union node *n;
12368 struct stackmark smark;
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012369 int status;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012370
Denys Vlasenko8e2bc472016-09-28 23:02:57 +020012371 s = sstrdup(s);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012372 setinputstring(s);
12373 setstackmark(&smark);
12374
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012375 status = 0;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012376 /* On exception inside execution loop, we must popfile().
12377 * Try interactively:
12378 * readonly a=a
12379 * command eval "a=b" # throws "is read only" error
12380 * "command BLTIN" is not supposed to abort (even in non-interactive use).
12381 * But if we skip popfile(), we hit EOF in eval's string, and exit.
12382 */
12383 savehandler = exception_handler;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012384 ex = setjmp(jmploc.loc);
12385 if (ex)
12386 goto out;
Denys Vlasenko493b9ca2016-10-30 18:27:14 +010012387 exception_handler = &jmploc;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012388
Denys Vlasenko86e83ec2009-07-23 22:07:07 +020012389 while ((n = parsecmd(0)) != NODE_EOF) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020012390 int i;
12391
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020012392 i = evaltree(n, flags);
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012393 if (n)
12394 status = i;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012395 popstackmark(&smark);
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012396 if (evalskip)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012397 break;
12398 }
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012399 out:
Denys Vlasenko8e2bc472016-09-28 23:02:57 +020012400 popstackmark(&smark);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012401 popfile();
Denys Vlasenko8e2bc472016-09-28 23:02:57 +020012402 stunalloc(s);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012403
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012404 exception_handler = savehandler;
12405 if (ex)
12406 longjmp(exception_handler->loc, ex);
12407
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012408 return status;
Eric Andersenc470f442003-07-28 09:56:35 +000012409}
12410
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012411/*
12412 * The eval command.
12413 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012414static int FAST_FUNC
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020012415evalcmd(int argc UNUSED_PARAM, char **argv, int flags)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012416{
12417 char *p;
12418 char *concat;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012419
Denis Vlasenko68404f12008-03-17 09:00:54 +000012420 if (argv[1]) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012421 p = argv[1];
Denis Vlasenko68404f12008-03-17 09:00:54 +000012422 argv += 2;
12423 if (argv[0]) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012424 STARTSTACKSTR(concat);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012425 for (;;) {
12426 concat = stack_putstr(p, concat);
Denis Vlasenko68404f12008-03-17 09:00:54 +000012427 p = *argv++;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012428 if (p == NULL)
12429 break;
12430 STPUTC(' ', concat);
12431 }
12432 STPUTC('\0', concat);
12433 p = grabstackstr(concat);
12434 }
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020012435 return evalstring(p, flags & EV_TESTED);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012436 }
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012437 return 0;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012438}
12439
12440/*
Denys Vlasenko285ad152009-12-04 23:02:27 +010012441 * Read and execute commands.
12442 * "Top" is nonzero for the top level command loop;
12443 * it turns on prompting if the shell is interactive.
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012444 */
12445static int
12446cmdloop(int top)
12447{
12448 union node *n;
12449 struct stackmark smark;
12450 int inter;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020012451 int status = 0;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012452 int numeof = 0;
12453
12454 TRACE(("cmdloop(%d) called\n", top));
12455 for (;;) {
12456 int skip;
12457
12458 setstackmark(&smark);
12459#if JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +000012460 if (doing_jobctl)
Denys Vlasenko9c541002015-10-07 15:44:36 +020012461 showjobs(SHOW_CHANGED|SHOW_STDERR);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012462#endif
12463 inter = 0;
12464 if (iflag && top) {
12465 inter++;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012466 chkmail();
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012467 }
12468 n = parsecmd(inter);
Denys Vlasenko7cee00e2009-07-24 01:08:03 +020012469#if DEBUG
12470 if (DEBUG > 2 && debug && (n != NODE_EOF))
Denys Vlasenko883cea42009-07-11 15:31:59 +020012471 showtree(n);
Denis Vlasenko135cecb2009-04-12 00:00:57 +000012472#endif
Denys Vlasenko86e83ec2009-07-23 22:07:07 +020012473 if (n == NODE_EOF) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012474 if (!top || numeof >= 50)
12475 break;
12476 if (!stoppedjobs()) {
12477 if (!Iflag)
12478 break;
12479 out2str("\nUse \"exit\" to leave shell.\n");
12480 }
12481 numeof++;
12482 } else if (nflag == 0) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020012483 int i;
12484
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +000012485 /* job_warning can only be 2,1,0. Here 2->1, 1/0->0 */
12486 job_warning >>= 1;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012487 numeof = 0;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020012488 i = evaltree(n, 0);
12489 if (n)
12490 status = i;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012491 }
12492 popstackmark(&smark);
12493 skip = evalskip;
12494
12495 if (skip) {
Denys Vlasenko6a0710e2016-09-30 14:18:34 +020012496 evalskip &= ~SKIPFUNC;
Denys Vlasenko0840c912016-10-01 15:27:44 +020012497 break;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012498 }
12499 }
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020012500 return status;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012501}
12502
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000012503/*
12504 * Take commands from a file. To be compatible we should do a path
12505 * search for the file, which is necessary to find sub-commands.
12506 */
12507static char *
12508find_dot_file(char *name)
12509{
12510 char *fullname;
12511 const char *path = pathval();
12512 struct stat statb;
12513
12514 /* don't try this for absolute or relative paths */
12515 if (strchr(name, '/'))
12516 return name;
12517
Denis Vlasenko8ad78e12009-02-15 12:40:30 +000012518 /* IIRC standards do not say whether . is to be searched.
12519 * And it is even smaller this way, making it unconditional for now:
12520 */
12521 if (1) { /* ENABLE_ASH_BASH_COMPAT */
12522 fullname = name;
12523 goto try_cur_dir;
12524 }
12525
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020012526 while ((fullname = path_advance(&path, name)) != NULL) {
Denis Vlasenko8ad78e12009-02-15 12:40:30 +000012527 try_cur_dir:
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000012528 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
12529 /*
12530 * Don't bother freeing here, since it will
12531 * be freed by the caller.
12532 */
12533 return fullname;
12534 }
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020012535 if (fullname != name)
12536 stunalloc(fullname);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000012537 }
12538
12539 /* not found in the PATH */
12540 ash_msg_and_raise_error("%s: not found", name);
12541 /* NOTREACHED */
12542}
12543
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012544static int FAST_FUNC
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012545dotcmd(int argc_ UNUSED_PARAM, char **argv_ UNUSED_PARAM)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012546{
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012547 /* "false; . empty_file; echo $?" should print 0, not 1: */
12548 int status = 0;
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012549 char *fullname;
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012550 char **argv;
Denys Vlasenkofb87d932017-01-09 08:22:06 +010012551 char *args_need_save;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012552 struct strlist *sp;
12553 volatile struct shparam saveparam;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012554
12555 for (sp = cmdenviron; sp; sp = sp->next)
Denis Vlasenko4222ae42007-02-25 02:37:49 +000012556 setvareq(ckstrdup(sp->text), VSTRFIXED | VTEXTFIXED);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012557
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012558 nextopt(nullstr); /* handle possible "--" */
12559 argv = argptr;
12560
12561 if (!argv[0]) {
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012562 /* bash says: "bash: .: filename argument required" */
12563 return 2; /* bash compat */
12564 }
12565
Denys Vlasenko091f8312013-03-17 14:25:22 +010012566 /* This aborts if file isn't found, which is POSIXly correct.
12567 * bash returns exitcode 1 instead.
12568 */
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012569 fullname = find_dot_file(argv[0]);
12570 argv++;
Denys Vlasenkofb87d932017-01-09 08:22:06 +010012571 args_need_save = argv[0];
12572 if (args_need_save) { /* . FILE ARGS, ARGS exist */
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012573 int argc;
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012574 saveparam = shellparam;
12575 shellparam.malloced = 0;
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012576 argc = 1;
12577 while (argv[argc])
12578 argc++;
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012579 shellparam.nparam = argc;
12580 shellparam.p = argv;
12581 };
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012582
Denys Vlasenko091f8312013-03-17 14:25:22 +010012583 /* This aborts if file can't be opened, which is POSIXly correct.
12584 * bash returns exitcode 1 instead.
12585 */
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012586 setinputfile(fullname, INPUT_PUSH_FILE);
12587 commandname = fullname;
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012588 status = cmdloop(0);
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012589 popfile();
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012590
Denys Vlasenkofb87d932017-01-09 08:22:06 +010012591 if (args_need_save) {
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012592 freeparam(&shellparam);
12593 shellparam = saveparam;
12594 };
12595
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012596 return status;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012597}
12598
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012599static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012600exitcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012601{
12602 if (stoppedjobs())
12603 return 0;
Denis Vlasenko68404f12008-03-17 09:00:54 +000012604 if (argv[1])
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012605 exitstatus = number(argv[1]);
12606 raise_exception(EXEXIT);
12607 /* NOTREACHED */
12608}
12609
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012610/*
12611 * Read a file containing shell functions.
12612 */
12613static void
12614readcmdfile(char *name)
12615{
12616 setinputfile(name, INPUT_PUSH_FILE);
12617 cmdloop(0);
12618 popfile();
12619}
12620
12621
Denis Vlasenkocc571512007-02-23 21:10:35 +000012622/* ============ find_command inplementation */
12623
12624/*
12625 * Resolve a command name. If you change this routine, you may have to
12626 * change the shellexec routine as well.
12627 */
12628static void
12629find_command(char *name, struct cmdentry *entry, int act, const char *path)
12630{
12631 struct tblentry *cmdp;
12632 int idx;
12633 int prev;
12634 char *fullname;
12635 struct stat statb;
12636 int e;
12637 int updatetbl;
12638 struct builtincmd *bcmd;
12639
12640 /* If name contains a slash, don't use PATH or hash table */
12641 if (strchr(name, '/') != NULL) {
12642 entry->u.index = -1;
12643 if (act & DO_ABS) {
12644 while (stat(name, &statb) < 0) {
12645#ifdef SYSV
12646 if (errno == EINTR)
12647 continue;
12648#endif
12649 entry->cmdtype = CMDUNKNOWN;
12650 return;
12651 }
12652 }
12653 entry->cmdtype = CMDNORMAL;
12654 return;
12655 }
12656
Denis Vlasenkof20de5b2007-04-29 23:42:54 +000012657/* #if ENABLE_FEATURE_SH_STANDALONE... moved after builtin check */
Denis Vlasenkocc571512007-02-23 21:10:35 +000012658
12659 updatetbl = (path == pathval());
12660 if (!updatetbl) {
12661 act |= DO_ALTPATH;
12662 if (strstr(path, "%builtin") != NULL)
12663 act |= DO_ALTBLTIN;
12664 }
12665
12666 /* If name is in the table, check answer will be ok */
12667 cmdp = cmdlookup(name, 0);
12668 if (cmdp != NULL) {
12669 int bit;
12670
12671 switch (cmdp->cmdtype) {
12672 default:
12673#if DEBUG
12674 abort();
12675#endif
12676 case CMDNORMAL:
12677 bit = DO_ALTPATH;
12678 break;
12679 case CMDFUNCTION:
12680 bit = DO_NOFUNC;
12681 break;
12682 case CMDBUILTIN:
12683 bit = DO_ALTBLTIN;
12684 break;
12685 }
12686 if (act & bit) {
12687 updatetbl = 0;
12688 cmdp = NULL;
12689 } else if (cmdp->rehash == 0)
12690 /* if not invalidated by cd, we're done */
12691 goto success;
12692 }
12693
12694 /* If %builtin not in path, check for builtin next */
12695 bcmd = find_builtin(name);
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000012696 if (bcmd) {
12697 if (IS_BUILTIN_REGULAR(bcmd))
12698 goto builtin_success;
12699 if (act & DO_ALTPATH) {
12700 if (!(act & DO_ALTBLTIN))
12701 goto builtin_success;
12702 } else if (builtinloc <= 0) {
12703 goto builtin_success;
Denis Vlasenko8e858e22007-03-07 09:35:43 +000012704 }
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000012705 }
Denis Vlasenkocc571512007-02-23 21:10:35 +000012706
Denis Vlasenkof20de5b2007-04-29 23:42:54 +000012707#if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko7465dbc2008-04-13 02:25:53 +000012708 {
12709 int applet_no = find_applet_by_name(name);
12710 if (applet_no >= 0) {
12711 entry->cmdtype = CMDNORMAL;
12712 entry->u.index = -2 - applet_no;
12713 return;
12714 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +000012715 }
12716#endif
12717
Denis Vlasenkocc571512007-02-23 21:10:35 +000012718 /* We have to search path. */
12719 prev = -1; /* where to start */
12720 if (cmdp && cmdp->rehash) { /* doing a rehash */
12721 if (cmdp->cmdtype == CMDBUILTIN)
12722 prev = builtinloc;
12723 else
12724 prev = cmdp->param.index;
12725 }
12726
12727 e = ENOENT;
12728 idx = -1;
12729 loop:
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020012730 while ((fullname = path_advance(&path, name)) != NULL) {
Denis Vlasenkocc571512007-02-23 21:10:35 +000012731 stunalloc(fullname);
Denis Vlasenkodee82b62007-07-29 14:05:27 +000012732 /* NB: code below will still use fullname
12733 * despite it being "unallocated" */
Denis Vlasenkocc571512007-02-23 21:10:35 +000012734 idx++;
12735 if (pathopt) {
12736 if (prefix(pathopt, "builtin")) {
12737 if (bcmd)
12738 goto builtin_success;
12739 continue;
Denis Vlasenko4a9ca132008-04-12 20:07:08 +000012740 }
12741 if ((act & DO_NOFUNC)
12742 || !prefix(pathopt, "func")
Denys Vlasenkoe4dcba12010-10-28 18:57:19 +020012743 ) { /* ignore unimplemented options */
Denis Vlasenkocc571512007-02-23 21:10:35 +000012744 continue;
12745 }
12746 }
12747 /* if rehash, don't redo absolute path names */
12748 if (fullname[0] == '/' && idx <= prev) {
12749 if (idx < prev)
12750 continue;
12751 TRACE(("searchexec \"%s\": no change\n", name));
12752 goto success;
12753 }
12754 while (stat(fullname, &statb) < 0) {
12755#ifdef SYSV
12756 if (errno == EINTR)
12757 continue;
12758#endif
12759 if (errno != ENOENT && errno != ENOTDIR)
12760 e = errno;
12761 goto loop;
12762 }
12763 e = EACCES; /* if we fail, this will be the error */
12764 if (!S_ISREG(statb.st_mode))
12765 continue;
12766 if (pathopt) { /* this is a %func directory */
12767 stalloc(strlen(fullname) + 1);
Denis Vlasenkodee82b62007-07-29 14:05:27 +000012768 /* NB: stalloc will return space pointed by fullname
12769 * (because we don't have any intervening allocations
12770 * between stunalloc above and this stalloc) */
Denis Vlasenkocc571512007-02-23 21:10:35 +000012771 readcmdfile(fullname);
12772 cmdp = cmdlookup(name, 0);
12773 if (cmdp == NULL || cmdp->cmdtype != CMDFUNCTION)
12774 ash_msg_and_raise_error("%s not defined in %s", name, fullname);
12775 stunalloc(fullname);
12776 goto success;
12777 }
12778 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
12779 if (!updatetbl) {
12780 entry->cmdtype = CMDNORMAL;
12781 entry->u.index = idx;
12782 return;
12783 }
12784 INT_OFF;
12785 cmdp = cmdlookup(name, 1);
12786 cmdp->cmdtype = CMDNORMAL;
12787 cmdp->param.index = idx;
12788 INT_ON;
12789 goto success;
12790 }
12791
12792 /* We failed. If there was an entry for this command, delete it */
12793 if (cmdp && updatetbl)
12794 delete_cmd_entry();
12795 if (act & DO_ERR)
12796 ash_msg("%s: %s", name, errmsg(e, "not found"));
12797 entry->cmdtype = CMDUNKNOWN;
12798 return;
12799
12800 builtin_success:
12801 if (!updatetbl) {
12802 entry->cmdtype = CMDBUILTIN;
12803 entry->u.cmd = bcmd;
12804 return;
12805 }
12806 INT_OFF;
12807 cmdp = cmdlookup(name, 1);
12808 cmdp->cmdtype = CMDBUILTIN;
12809 cmdp->param.cmd = bcmd;
12810 INT_ON;
12811 success:
12812 cmdp->rehash = 0;
12813 entry->cmdtype = cmdp->cmdtype;
12814 entry->u = cmdp->param;
12815}
12816
12817
Eric Andersencb57d552001-06-28 07:25:16 +000012818/*
Eric Andersencb57d552001-06-28 07:25:16 +000012819 * The trap builtin.
12820 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012821static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012822trapcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +000012823{
12824 char *action;
12825 char **ap;
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010012826 int signo, exitcode;
Eric Andersencb57d552001-06-28 07:25:16 +000012827
Eric Andersenc470f442003-07-28 09:56:35 +000012828 nextopt(nullstr);
12829 ap = argptr;
12830 if (!*ap) {
Denis Vlasenko2da584f2007-02-19 22:44:05 +000012831 for (signo = 0; signo < NSIG; signo++) {
Denys Vlasenko21d87d42009-09-25 00:06:51 +020012832 char *tr = trap_ptr[signo];
12833 if (tr) {
Denys Vlasenkoe74aaf92009-09-27 02:05:45 +020012834 /* note: bash adds "SIG", but only if invoked
12835 * as "bash". If called as "sh", or if set -o posix,
12836 * then it prints short signal names.
12837 * We are printing short names: */
12838 out1fmt("trap -- %s %s\n",
Denys Vlasenko21d87d42009-09-25 00:06:51 +020012839 single_quote(tr),
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +000012840 get_signame(signo));
Denys Vlasenko726e1a02009-09-25 02:58:20 +020012841 /* trap_ptr != trap only if we are in special-cased `trap` code.
12842 * In this case, we will exit very soon, no need to free(). */
Denys Vlasenkoe74aaf92009-09-27 02:05:45 +020012843 /* if (trap_ptr != trap && tp[0]) */
Denys Vlasenko726e1a02009-09-25 02:58:20 +020012844 /* free(tr); */
Eric Andersencb57d552001-06-28 07:25:16 +000012845 }
12846 }
Denys Vlasenko726e1a02009-09-25 02:58:20 +020012847 /*
Denys Vlasenko21d87d42009-09-25 00:06:51 +020012848 if (trap_ptr != trap) {
12849 free(trap_ptr);
12850 trap_ptr = trap;
12851 }
Denys Vlasenko726e1a02009-09-25 02:58:20 +020012852 */
Eric Andersencb57d552001-06-28 07:25:16 +000012853 return 0;
12854 }
Denys Vlasenko21d87d42009-09-25 00:06:51 +020012855
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +000012856 action = NULL;
12857 if (ap[1])
Eric Andersencb57d552001-06-28 07:25:16 +000012858 action = *ap++;
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010012859 exitcode = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000012860 while (*ap) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000012861 signo = get_signum(*ap);
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010012862 if (signo < 0) {
12863 /* Mimic bash message exactly */
12864 ash_msg("%s: invalid signal specification", *ap);
12865 exitcode = 1;
12866 goto next;
12867 }
Denis Vlasenkob012b102007-02-19 22:43:01 +000012868 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +000012869 if (action) {
Denis Vlasenko9f739442006-12-16 23:49:13 +000012870 if (LONE_DASH(action))
Eric Andersencb57d552001-06-28 07:25:16 +000012871 action = NULL;
Denys Vlasenkob4f51d32016-10-27 12:55:09 +020012872 else {
12873 if (action[0]) /* not NULL and not "" and not "-" */
12874 may_have_traps = 1;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012875 action = ckstrdup(action);
Denys Vlasenkob4f51d32016-10-27 12:55:09 +020012876 }
Eric Andersencb57d552001-06-28 07:25:16 +000012877 }
Denis Vlasenko60818682007-09-28 22:07:23 +000012878 free(trap[signo]);
Eric Andersencb57d552001-06-28 07:25:16 +000012879 trap[signo] = action;
12880 if (signo != 0)
12881 setsignal(signo);
Denis Vlasenkob012b102007-02-19 22:43:01 +000012882 INT_ON;
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010012883 next:
Eric Andersencb57d552001-06-28 07:25:16 +000012884 ap++;
12885 }
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010012886 return exitcode;
Eric Andersencb57d552001-06-28 07:25:16 +000012887}
12888
Eric Andersenc470f442003-07-28 09:56:35 +000012889
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000012890/* ============ Builtins */
Eric Andersenc470f442003-07-28 09:56:35 +000012891
Denys Vlasenko2ec34962014-09-08 16:52:39 +020012892#if ENABLE_ASH_HELP
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012893static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012894helpcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000012895{
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000012896 unsigned col;
12897 unsigned i;
Eric Andersenc470f442003-07-28 09:56:35 +000012898
Denys Vlasenkod6b05eb2009-06-06 20:59:55 +020012899 out1fmt(
Denis Vlasenko34d4d892009-04-04 20:24:37 +000012900 "Built-in commands:\n"
12901 "------------------\n");
Denis Vlasenkob71c6682007-07-21 15:08:09 +000012902 for (col = 0, i = 0; i < ARRAY_SIZE(builtintab); i++) {
Eric Andersenc470f442003-07-28 09:56:35 +000012903 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
Denis Vlasenko52764022007-02-24 13:42:56 +000012904 builtintab[i].name + 1);
Eric Andersenc470f442003-07-28 09:56:35 +000012905 if (col > 60) {
12906 out1fmt("\n");
12907 col = 0;
12908 }
12909 }
Denys Vlasenko2ec34962014-09-08 16:52:39 +020012910# if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko1aa7e472007-11-28 06:49:03 +000012911 {
12912 const char *a = applet_names;
12913 while (*a) {
12914 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), a);
12915 if (col > 60) {
12916 out1fmt("\n");
12917 col = 0;
12918 }
Ron Yorston2b919582016-04-08 11:57:20 +010012919 while (*a++ != '\0')
12920 continue;
Eric Andersenc470f442003-07-28 09:56:35 +000012921 }
12922 }
Denys Vlasenko2ec34962014-09-08 16:52:39 +020012923# endif
Denys Vlasenkoebedb942016-10-02 18:45:09 +020012924 newline_and_flush(stdout);
Eric Andersenc470f442003-07-28 09:56:35 +000012925 return EXIT_SUCCESS;
12926}
Denys Vlasenko2ec34962014-09-08 16:52:39 +020012927#endif
Eric Andersenc470f442003-07-28 09:56:35 +000012928
Flemming Madsend96ffda2013-04-07 18:47:24 +020012929#if MAX_HISTORY
12930static int FAST_FUNC
12931historycmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12932{
12933 show_history(line_input_state);
12934 return EXIT_SUCCESS;
12935}
12936#endif
12937
Eric Andersencb57d552001-06-28 07:25:16 +000012938/*
Eric Andersencb57d552001-06-28 07:25:16 +000012939 * The export and readonly commands.
12940 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012941static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012942exportcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000012943{
12944 struct var *vp;
12945 char *name;
12946 const char *p;
Eric Andersenc470f442003-07-28 09:56:35 +000012947 char **aptr;
Denys Vlasenkod5275882012-10-01 13:41:17 +020012948 char opt;
12949 int flag;
12950 int flag_off;
Eric Andersencb57d552001-06-28 07:25:16 +000012951
Denys Vlasenkod5275882012-10-01 13:41:17 +020012952 /* "readonly" in bash accepts, but ignores -n.
12953 * We do the same: it saves a conditional in nextopt's param.
12954 */
12955 flag_off = 0;
12956 while ((opt = nextopt("np")) != '\0') {
12957 if (opt == 'n')
12958 flag_off = VEXPORT;
12959 }
12960 flag = VEXPORT;
12961 if (argv[0][0] == 'r') {
12962 flag = VREADONLY;
12963 flag_off = 0; /* readonly ignores -n */
12964 }
12965 flag_off = ~flag_off;
12966
12967 /*if (opt_p_not_specified) - bash doesnt check this. Try "export -p NAME" */
12968 {
Denis Vlasenko2da584f2007-02-19 22:44:05 +000012969 aptr = argptr;
12970 name = *aptr;
12971 if (name) {
12972 do {
12973 p = strchr(name, '=');
12974 if (p != NULL) {
12975 p++;
12976 } else {
12977 vp = *findvar(hashvar(name), name);
12978 if (vp) {
Denys Vlasenkod5275882012-10-01 13:41:17 +020012979 vp->flags = ((vp->flags | flag) & flag_off);
Denis Vlasenko2da584f2007-02-19 22:44:05 +000012980 continue;
12981 }
Eric Andersencb57d552001-06-28 07:25:16 +000012982 }
Denys Vlasenkod5275882012-10-01 13:41:17 +020012983 setvar(name, p, (flag & flag_off));
Denis Vlasenko2da584f2007-02-19 22:44:05 +000012984 } while ((name = *++aptr) != NULL);
12985 return 0;
12986 }
Eric Andersencb57d552001-06-28 07:25:16 +000012987 }
Denys Vlasenkod5275882012-10-01 13:41:17 +020012988
12989 /* No arguments. Show the list of exported or readonly vars.
12990 * -n is ignored.
12991 */
Denis Vlasenko2da584f2007-02-19 22:44:05 +000012992 showvars(argv[0], flag, 0);
Eric Andersencb57d552001-06-28 07:25:16 +000012993 return 0;
12994}
12995
Eric Andersencb57d552001-06-28 07:25:16 +000012996/*
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000012997 * Delete a function if it exists.
Eric Andersencb57d552001-06-28 07:25:16 +000012998 */
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +000012999static void
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000013000unsetfunc(const char *name)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000013001{
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000013002 struct tblentry *cmdp;
Eric Andersencb57d552001-06-28 07:25:16 +000013003
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000013004 cmdp = cmdlookup(name, 0);
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020013005 if (cmdp != NULL && cmdp->cmdtype == CMDFUNCTION)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000013006 delete_cmd_entry();
Eric Andersenc470f442003-07-28 09:56:35 +000013007}
13008
Eric Andersencb57d552001-06-28 07:25:16 +000013009/*
Eric Andersencb57d552001-06-28 07:25:16 +000013010 * The unset builtin command. We unset the function before we unset the
13011 * variable to allow a function to be unset when there is a readonly variable
13012 * with the same name.
13013 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013014static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013015unsetcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +000013016{
13017 char **ap;
13018 int i;
Eric Andersenc470f442003-07-28 09:56:35 +000013019 int flag = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000013020 int ret = 0;
13021
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020013022 while ((i = nextopt("vf")) != 0) {
Eric Andersenc470f442003-07-28 09:56:35 +000013023 flag = i;
Eric Andersencb57d552001-06-28 07:25:16 +000013024 }
Eric Andersencb57d552001-06-28 07:25:16 +000013025
Denis Vlasenko2da584f2007-02-19 22:44:05 +000013026 for (ap = argptr; *ap; ap++) {
Eric Andersenc470f442003-07-28 09:56:35 +000013027 if (flag != 'f') {
13028 i = unsetvar(*ap);
13029 ret |= i;
13030 if (!(i & 2))
13031 continue;
13032 }
13033 if (flag != 'v')
Eric Andersencb57d552001-06-28 07:25:16 +000013034 unsetfunc(*ap);
Eric Andersencb57d552001-06-28 07:25:16 +000013035 }
Eric Andersenc470f442003-07-28 09:56:35 +000013036 return ret & 1;
Eric Andersencb57d552001-06-28 07:25:16 +000013037}
13038
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000013039static const unsigned char timescmd_str[] ALIGN1 = {
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013040 ' ', offsetof(struct tms, tms_utime),
13041 '\n', offsetof(struct tms, tms_stime),
13042 ' ', offsetof(struct tms, tms_cutime),
13043 '\n', offsetof(struct tms, tms_cstime),
13044 0
13045};
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013046static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013047timescmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013048{
Denys Vlasenko8cd9f342010-06-18 15:36:48 +020013049 unsigned long clk_tck, s, t;
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013050 const unsigned char *p;
13051 struct tms buf;
13052
Bartosz Golaszewski5d2e4092014-06-22 14:01:13 +020013053 clk_tck = bb_clk_tck();
Eric Andersencb57d552001-06-28 07:25:16 +000013054 times(&buf);
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013055
13056 p = timescmd_str;
13057 do {
13058 t = *(clock_t *)(((char *) &buf) + p[1]);
13059 s = t / clk_tck;
Denys Vlasenko8cd9f342010-06-18 15:36:48 +020013060 t = t % clk_tck;
13061 out1fmt("%lum%lu.%03lus%c",
13062 s / 60, s % 60,
13063 (t * 1000) / clk_tck,
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013064 p[0]);
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020013065 p += 2;
13066 } while (*p);
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013067
Eric Andersencb57d552001-06-28 07:25:16 +000013068 return 0;
13069}
13070
Denys Vlasenko0b883582016-12-23 16:49:07 +010013071#if ENABLE_FEATURE_SH_MATH
Eric Andersenc470f442003-07-28 09:56:35 +000013072/*
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020013073 * The let builtin. Partially stolen from GNU Bash, the Bourne Again SHell.
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +000013074 * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
Eric Andersen90898442003-08-06 11:20:52 +000013075 *
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +000013076 * Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
Eric Andersenc470f442003-07-28 09:56:35 +000013077 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013078static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013079letcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersenc470f442003-07-28 09:56:35 +000013080{
Denis Vlasenko68404f12008-03-17 09:00:54 +000013081 arith_t i;
Eric Andersenc470f442003-07-28 09:56:35 +000013082
Denis Vlasenko68404f12008-03-17 09:00:54 +000013083 argv++;
13084 if (!*argv)
Denis Vlasenkob012b102007-02-19 22:43:01 +000013085 ash_msg_and_raise_error("expression expected");
Denis Vlasenko68404f12008-03-17 09:00:54 +000013086 do {
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +000013087 i = ash_arith(*argv);
Denis Vlasenko68404f12008-03-17 09:00:54 +000013088 } while (*++argv);
Eric Andersenc470f442003-07-28 09:56:35 +000013089
Denis Vlasenkod9e15f22006-11-27 16:49:55 +000013090 return !i;
Eric Andersenc470f442003-07-28 09:56:35 +000013091}
Eric Andersenc470f442003-07-28 09:56:35 +000013092#endif
Eric Andersen74bcd162001-07-30 21:41:37 +000013093
Eric Andersenc470f442003-07-28 09:56:35 +000013094/*
Denis Vlasenko59f351c2008-03-25 00:07:12 +000013095 * The read builtin. Options:
13096 * -r Do not interpret '\' specially
13097 * -s Turn off echo (tty only)
13098 * -n NCHARS Read NCHARS max
13099 * -p PROMPT Display PROMPT on stderr (if input is from tty)
13100 * -t SECONDS Timeout after SECONDS (tty or pipe only)
13101 * -u FD Read from given FD instead of fd 0
Eric Andersenc470f442003-07-28 09:56:35 +000013102 * This uses unbuffered input, which may be avoidable in some cases.
Denis Vlasenko59f351c2008-03-25 00:07:12 +000013103 * TODO: bash also has:
13104 * -a ARRAY Read into array[0],[1],etc
13105 * -d DELIM End on DELIM char, not newline
13106 * -e Use line editing (tty only)
Eric Andersenc470f442003-07-28 09:56:35 +000013107 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013108static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013109readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000013110{
Denys Vlasenko73067272010-01-12 22:11:24 +010013111 char *opt_n = NULL;
13112 char *opt_p = NULL;
13113 char *opt_t = NULL;
13114 char *opt_u = NULL;
13115 int read_flags = 0;
13116 const char *r;
Eric Andersenc470f442003-07-28 09:56:35 +000013117 int i;
13118
Denys Vlasenko73067272010-01-12 22:11:24 +010013119 while ((i = nextopt("p:u:rt:n:s")) != '\0') {
Denis Vlasenkobf0a2012006-12-26 10:42:51 +000013120 switch (i) {
Paul Fox02eb9342005-09-07 16:56:02 +000013121 case 'p':
Denys Vlasenko73067272010-01-12 22:11:24 +010013122 opt_p = optionarg;
Paul Fox02eb9342005-09-07 16:56:02 +000013123 break;
Paul Fox02eb9342005-09-07 16:56:02 +000013124 case 'n':
Denys Vlasenko73067272010-01-12 22:11:24 +010013125 opt_n = optionarg;
Paul Fox02eb9342005-09-07 16:56:02 +000013126 break;
13127 case 's':
Denys Vlasenko73067272010-01-12 22:11:24 +010013128 read_flags |= BUILTIN_READ_SILENT;
Paul Fox02eb9342005-09-07 16:56:02 +000013129 break;
Paul Fox02eb9342005-09-07 16:56:02 +000013130 case 't':
Denys Vlasenko73067272010-01-12 22:11:24 +010013131 opt_t = optionarg;
Paul Fox02eb9342005-09-07 16:56:02 +000013132 break;
Paul Fox02eb9342005-09-07 16:56:02 +000013133 case 'r':
Denys Vlasenko73067272010-01-12 22:11:24 +010013134 read_flags |= BUILTIN_READ_RAW;
Paul Fox02eb9342005-09-07 16:56:02 +000013135 break;
Denis Vlasenko59f351c2008-03-25 00:07:12 +000013136 case 'u':
Denys Vlasenko73067272010-01-12 22:11:24 +010013137 opt_u = optionarg;
Denis Vlasenko59f351c2008-03-25 00:07:12 +000013138 break;
Paul Fox02eb9342005-09-07 16:56:02 +000013139 default:
13140 break;
13141 }
Eric Andersenc470f442003-07-28 09:56:35 +000013142 }
Paul Fox02eb9342005-09-07 16:56:02 +000013143
Denys Vlasenko9e71e3c2012-09-06 13:28:10 +020013144 /* "read -s" needs to save/restore termios, can't allow ^C
13145 * to jump out of it.
13146 */
13147 INT_OFF;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020013148 r = shell_builtin_read(setvar0,
Denys Vlasenko73067272010-01-12 22:11:24 +010013149 argptr,
13150 bltinlookup("IFS"), /* can be NULL */
13151 read_flags,
13152 opt_n,
13153 opt_p,
13154 opt_t,
13155 opt_u
13156 );
Denys Vlasenko9e71e3c2012-09-06 13:28:10 +020013157 INT_ON;
Denis Vlasenko46aeab92009-03-31 19:18:17 +000013158
Denys Vlasenko73067272010-01-12 22:11:24 +010013159 if ((uintptr_t)r > 1)
13160 ash_msg_and_raise_error(r);
Denis Vlasenko037576d2007-10-20 18:30:38 +000013161
Denys Vlasenko73067272010-01-12 22:11:24 +010013162 return (uintptr_t)r;
Eric Andersenc470f442003-07-28 09:56:35 +000013163}
13164
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013165static int FAST_FUNC
Denys Vlasenko6283f982015-10-07 16:56:20 +020013166umaskcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000013167{
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013168 static const char permuser[3] ALIGN1 = "ogu";
Eric Andersenc470f442003-07-28 09:56:35 +000013169
Eric Andersenc470f442003-07-28 09:56:35 +000013170 mode_t mask;
Eric Andersenc470f442003-07-28 09:56:35 +000013171 int symbolic_mode = 0;
13172
13173 while (nextopt("S") != '\0') {
13174 symbolic_mode = 1;
13175 }
13176
Denis Vlasenkob012b102007-02-19 22:43:01 +000013177 INT_OFF;
Eric Andersenc470f442003-07-28 09:56:35 +000013178 mask = umask(0);
13179 umask(mask);
Denis Vlasenkob012b102007-02-19 22:43:01 +000013180 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +000013181
Denys Vlasenko6283f982015-10-07 16:56:20 +020013182 if (*argptr == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +000013183 if (symbolic_mode) {
Denys Vlasenko005c4922015-10-10 20:17:12 +020013184 char buf[sizeof(",u=rwx,g=rwx,o=rwx")];
Eric Andersenc470f442003-07-28 09:56:35 +000013185 char *p = buf;
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013186 int i;
Eric Andersenc470f442003-07-28 09:56:35 +000013187
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013188 i = 2;
13189 for (;;) {
Denys Vlasenko005c4922015-10-10 20:17:12 +020013190 *p++ = ',';
Eric Andersenc470f442003-07-28 09:56:35 +000013191 *p++ = permuser[i];
13192 *p++ = '=';
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013193 /* mask is 0..0uuugggooo. i=2 selects uuu bits */
Denys Vlasenko005c4922015-10-10 20:17:12 +020013194 if (!(mask & 0400)) *p++ = 'r';
13195 if (!(mask & 0200)) *p++ = 'w';
13196 if (!(mask & 0100)) *p++ = 'x';
13197 mask <<= 3;
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013198 if (--i < 0)
13199 break;
Eric Andersenc470f442003-07-28 09:56:35 +000013200 }
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013201 *p = '\0';
Denys Vlasenko005c4922015-10-10 20:17:12 +020013202 puts(buf + 1);
Eric Andersenc470f442003-07-28 09:56:35 +000013203 } else {
Denys Vlasenkoec046f72015-10-07 17:57:53 +020013204 out1fmt("%04o\n", mask);
Eric Andersenc470f442003-07-28 09:56:35 +000013205 }
13206 } else {
Denys Vlasenko6283f982015-10-07 16:56:20 +020013207 char *modestr = *argptr;
13208 /* numeric umasks are taken as-is */
13209 /* symbolic umasks are inverted: "umask a=rx" calls umask(222) */
13210 if (!isdigit(modestr[0]))
13211 mask ^= 0777;
Denys Vlasenko5711a2a2015-10-07 17:55:33 +020013212 mask = bb_parse_mode(modestr, mask);
13213 if ((unsigned)mask > 0777) {
Denys Vlasenko6283f982015-10-07 16:56:20 +020013214 ash_msg_and_raise_error("illegal mode: %s", modestr);
Eric Andersenc470f442003-07-28 09:56:35 +000013215 }
Denys Vlasenko6283f982015-10-07 16:56:20 +020013216 if (!isdigit(modestr[0]))
13217 mask ^= 0777;
13218 umask(mask);
Eric Andersenc470f442003-07-28 09:56:35 +000013219 }
13220 return 0;
13221}
13222
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013223static int FAST_FUNC
Denys Vlasenkof3c742f2010-03-06 20:12:00 +010013224ulimitcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersenc470f442003-07-28 09:56:35 +000013225{
Denys Vlasenkof3c742f2010-03-06 20:12:00 +010013226 return shell_builtin_ulimit(argv);
Eric Andersenc470f442003-07-28 09:56:35 +000013227}
13228
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013229/* ============ main() and helpers */
13230
13231/*
13232 * Called to exit the shell.
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013233 */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013234static void
13235exitshell(void)
13236{
13237 struct jmploc loc;
13238 char *p;
13239 int status;
13240
Denys Vlasenkobede2152011-09-04 16:12:33 +020013241#if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT
13242 save_history(line_input_state);
13243#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013244 status = exitstatus;
13245 TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
13246 if (setjmp(loc.loc)) {
Denis Vlasenko7f88e342009-03-19 03:36:18 +000013247 if (exception_type == EXEXIT)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013248 status = exitstatus;
13249 goto out;
13250 }
13251 exception_handler = &loc;
13252 p = trap[0];
13253 if (p) {
13254 trap[0] = NULL;
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020013255 evalskip = 0;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013256 evalstring(p, 0);
Denys Vlasenkof37e1152016-10-07 03:17:28 +020013257 /*free(p); - we'll exit soon */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013258 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013259 out:
Denys Vlasenkof37e1152016-10-07 03:17:28 +020013260 /* dash wraps setjobctl(0) in "if (setjmp(loc.loc) == 0) {...}".
13261 * our setjobctl(0) does not panic if tcsetpgrp fails inside it.
13262 */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013263 setjobctl(0);
Denys Vlasenkocaee80c2016-10-25 20:49:53 +020013264 flush_stdout_stderr();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013265 _exit(status);
13266 /* NOTREACHED */
13267}
13268
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +000013269static void
13270init(void)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013271{
Denys Vlasenko82dd14a2010-05-17 10:10:01 +020013272 /* we will never free this */
13273 basepf.next_to_pgetc = basepf.buf = ckmalloc(IBUFSIZ);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013274
Denys Vlasenko458c1f22016-10-27 23:51:19 +020013275 sigmode[SIGCHLD - 1] = S_DFL;
13276 setsignal(SIGCHLD);
13277
Denys Vlasenko7a7b0342009-12-04 04:18:31 +010013278 /* bash re-enables SIGHUP which is SIG_IGNed on entry.
13279 * Try: "trap '' HUP; bash; echo RET" and type "kill -HUP $$"
13280 */
Denys Vlasenkocacb2cd2010-10-05 00:13:02 +020013281 signal(SIGHUP, SIG_DFL);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013282
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013283 {
13284 char **envp;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013285 const char *p;
13286 struct stat st1, st2;
13287
13288 initvar();
13289 for (envp = environ; envp && *envp; envp++) {
Denys Vlasenkob6838b52016-09-30 11:33:47 +020013290 p = endofname(*envp);
13291 if (p != *envp && *p == '=') {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013292 setvareq(*envp, VEXPORT|VTEXTFIXED);
13293 }
13294 }
13295
Denys Vlasenkoe627ac92016-09-30 14:36:59 +020013296 setvareq((char*)defoptindvar, VTEXTFIXED);
13297
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020013298 setvar0("PPID", utoa(getppid()));
Bernhard Reutner-Fischer80f8cdf2013-11-08 14:25:24 +010013299#if ENABLE_ASH_BASH_COMPAT
13300 p = lookupvar("SHLVL");
Denys Vlasenko5680e982014-01-07 16:12:48 +010013301 setvar("SHLVL", utoa((p ? atoi(p) : 0) + 1), VEXPORT);
Denys Vlasenko3fa97af2014-04-15 11:43:29 +020013302 if (!lookupvar("HOSTNAME")) {
13303 struct utsname uts;
13304 uname(&uts);
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020013305 setvar0("HOSTNAME", uts.nodename);
Denys Vlasenko3fa97af2014-04-15 11:43:29 +020013306 }
Bernhard Reutner-Fischer80f8cdf2013-11-08 14:25:24 +010013307#endif
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013308 p = lookupvar("PWD");
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013309 if (p) {
Denys Vlasenkoef159702016-09-01 11:16:22 +020013310 if (p[0] != '/' || stat(p, &st1) || stat(".", &st2)
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013311 || st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino
13312 ) {
Denys Vlasenkoef159702016-09-01 11:16:22 +020013313 p = NULL;
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013314 }
13315 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013316 setpwd(p, 0);
13317 }
13318}
13319
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013320
13321//usage:#define ash_trivial_usage
Denys Vlasenko6b6af532011-03-08 10:24:17 +010013322//usage: "[-/+OPTIONS] [-/+o OPT]... [-c 'SCRIPT' [ARG0 [ARGS]] / FILE [ARGS]]"
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013323//usage:#define ash_full_usage "\n\n"
13324//usage: "Unix shell interpreter"
13325
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013326/*
13327 * Process the shell command line arguments.
13328 */
13329static void
Denis Vlasenko68404f12008-03-17 09:00:54 +000013330procargs(char **argv)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013331{
13332 int i;
13333 const char *xminusc;
13334 char **xargv;
13335
13336 xargv = argv;
13337 arg0 = xargv[0];
Denis Vlasenko68404f12008-03-17 09:00:54 +000013338 /* if (xargv[0]) - mmm, this is always true! */
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013339 xargv++;
13340 for (i = 0; i < NOPTS; i++)
13341 optlist[i] = 2;
13342 argptr = xargv;
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013343 if (options(/*cmdline:*/ 1)) {
Denis Vlasenko28bf6712008-02-14 15:01:47 +000013344 /* it already printed err message */
13345 raise_exception(EXERROR);
13346 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013347 xargv = argptr;
13348 xminusc = minusc;
13349 if (*xargv == NULL) {
13350 if (xminusc)
13351 ash_msg_and_raise_error(bb_msg_requires_arg, "-c");
13352 sflag = 1;
13353 }
13354 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
13355 iflag = 1;
13356 if (mflag == 2)
13357 mflag = iflag;
13358 for (i = 0; i < NOPTS; i++)
13359 if (optlist[i] == 2)
13360 optlist[i] = 0;
13361#if DEBUG == 2
13362 debug = 1;
13363#endif
13364 /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
13365 if (xminusc) {
13366 minusc = *xargv++;
13367 if (*xargv)
13368 goto setarg0;
13369 } else if (!sflag) {
13370 setinputfile(*xargv, 0);
13371 setarg0:
13372 arg0 = *xargv++;
13373 commandname = arg0;
13374 }
13375
13376 shellparam.p = xargv;
13377#if ENABLE_ASH_GETOPTS
13378 shellparam.optind = 1;
13379 shellparam.optoff = -1;
13380#endif
Denis Vlasenko01631112007-12-16 17:20:38 +000013381 /* assert(shellparam.malloced == 0 && shellparam.nparam == 0); */
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013382 while (*xargv) {
13383 shellparam.nparam++;
13384 xargv++;
13385 }
13386 optschanged();
13387}
13388
13389/*
Denys Vlasenko2eb0a7e2016-10-27 11:28:59 +020013390 * Read /etc/profile, ~/.profile, $ENV.
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013391 */
13392static void
13393read_profile(const char *name)
13394{
Denys Vlasenko2eb0a7e2016-10-27 11:28:59 +020013395 name = expandstr(name);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013396 if (setinputfile(name, INPUT_PUSH_FILE | INPUT_NOFILE_OK) < 0)
13397 return;
Denys Vlasenko0840c912016-10-01 15:27:44 +020013398 cmdloop(0);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013399 popfile();
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013400}
13401
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013402/*
13403 * This routine is called when an error or an interrupt occurs in an
13404 * interactive shell and control is returned to the main command loop.
Denys Vlasenko5ac04f22016-10-27 14:46:50 +020013405 * (In dash, this function is auto-generated by build machinery).
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013406 */
13407static void
13408reset(void)
13409{
13410 /* from eval.c: */
13411 evalskip = 0;
13412 loopnest = 0;
Denys Vlasenko5ac04f22016-10-27 14:46:50 +020013413
13414 /* from expand.c: */
13415 ifsfree();
13416
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013417 /* from input.c: */
Denis Vlasenko41eb3002008-11-28 03:42:31 +000013418 g_parsefile->left_in_buffer = 0;
13419 g_parsefile->left_in_line = 0; /* clear input buffer */
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013420 popallfiles();
Denys Vlasenko5ac04f22016-10-27 14:46:50 +020013421
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013422 /* from redir.c: */
Denys Vlasenkoe19923f2016-10-26 15:38:44 +020013423 while (redirlist)
13424 popredir(/*drop:*/ 0, /*restore:*/ 0);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013425}
13426
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013427#if PROFILE
13428static short profile_buf[16384];
13429extern int etext();
13430#endif
13431
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013432/*
13433 * Main routine. We initialize things, parse the arguments, execute
13434 * profiles if we're a login shell, and then call cmdloop to execute
13435 * commands. The setjmp call sets up the location to jump to when an
13436 * exception occurs. When an exception occurs the variable "state"
13437 * is used to figure out how far we had gotten.
13438 */
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +000013439int ash_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013440int ash_main(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013441{
Denis Vlasenko4e12b1a2008-12-23 23:36:47 +000013442 volatile smallint state;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013443 struct jmploc jmploc;
13444 struct stackmark smark;
13445
Denis Vlasenko01631112007-12-16 17:20:38 +000013446 /* Initialize global data */
13447 INIT_G_misc();
13448 INIT_G_memstack();
13449 INIT_G_var();
Denis Vlasenkoee87ebf2007-12-21 22:18:16 +000013450#if ENABLE_ASH_ALIAS
Denis Vlasenko01631112007-12-16 17:20:38 +000013451 INIT_G_alias();
Denis Vlasenkoee87ebf2007-12-21 22:18:16 +000013452#endif
Denis Vlasenko01631112007-12-16 17:20:38 +000013453 INIT_G_cmdtable();
13454
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013455#if PROFILE
13456 monitor(4, etext, profile_buf, sizeof(profile_buf), 50);
13457#endif
13458
13459#if ENABLE_FEATURE_EDITING
13460 line_input_state = new_line_input_t(FOR_SHELL | WITH_PATH_LOOKUP);
13461#endif
13462 state = 0;
13463 if (setjmp(jmploc.loc)) {
Denis Vlasenko7f88e342009-03-19 03:36:18 +000013464 smallint e;
Denis Vlasenko4e12b1a2008-12-23 23:36:47 +000013465 smallint s;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013466
13467 reset();
13468
Denis Vlasenko7f88e342009-03-19 03:36:18 +000013469 e = exception_type;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013470 s = state;
Denys Vlasenkob563f622010-09-25 17:15:13 +020013471 if (e == EXEXIT || s == 0 || iflag == 0 || shlvl) {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013472 exitshell();
Denys Vlasenkob563f622010-09-25 17:15:13 +020013473 }
13474 if (e == EXINT) {
Denys Vlasenko9c541002015-10-07 15:44:36 +020013475 newline_and_flush(stderr);
Denys Vlasenkob563f622010-09-25 17:15:13 +020013476 }
Denis Vlasenko7f88e342009-03-19 03:36:18 +000013477
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013478 popstackmark(&smark);
13479 FORCE_INT_ON; /* enable interrupts */
13480 if (s == 1)
13481 goto state1;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000013482 if (s == 2)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013483 goto state2;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000013484 if (s == 3)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013485 goto state3;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000013486 goto state4;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013487 }
13488 exception_handler = &jmploc;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013489 rootpid = getpid();
13490
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013491 init();
13492 setstackmark(&smark);
Denis Vlasenko68404f12008-03-17 09:00:54 +000013493 procargs(argv);
Denys Vlasenko474ed062016-10-30 18:30:29 +010013494#if DEBUG
13495 TRACE(("Shell args: "));
13496 trace_puts_args(argv);
13497#endif
Denis Vlasenko68404f12008-03-17 09:00:54 +000013498
Denys Vlasenko6088e132010-12-25 23:58:42 +010013499 if (argv[0] && argv[0][0] == '-')
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013500 isloginsh = 1;
13501 if (isloginsh) {
Stefan Hellermann4ef14392013-03-15 02:45:50 +010013502 const char *hp;
13503
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013504 state = 1;
13505 read_profile("/etc/profile");
13506 state1:
13507 state = 2;
Stefan Hellermann4ef14392013-03-15 02:45:50 +010013508 hp = lookupvar("HOME");
Denys Vlasenko2eb0a7e2016-10-27 11:28:59 +020013509 if (hp)
13510 read_profile("$HOME/.profile");
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013511 }
13512 state2:
13513 state = 3;
13514 if (
13515#ifndef linux
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013516 getuid() == geteuid() && getgid() == getegid() &&
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013517#endif
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013518 iflag
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013519 ) {
Denys Vlasenko2eb0a7e2016-10-27 11:28:59 +020013520 const char *shinit = lookupvar("ENV");
13521 if (shinit != NULL && *shinit != '\0')
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013522 read_profile(shinit);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013523 }
Denys Vlasenko2eb0a7e2016-10-27 11:28:59 +020013524 popstackmark(&smark);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013525 state3:
13526 state = 4;
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000013527 if (minusc) {
13528 /* evalstring pushes parsefile stack.
13529 * Ensure we don't falsely claim that 0 (stdin)
Denis Vlasenko5368ad52009-03-20 10:20:08 +000013530 * is one of stacked source fds.
13531 * Testcase: ash -c 'exec 1>&0' must not complain. */
Denys Vlasenko79b3d422010-06-03 04:29:08 +020013532 // if (!sflag) g_parsefile->pf_fd = -1;
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +020013533 // ^^ not necessary since now we special-case fd 0
13534 // in is_hidden_fd() to not be considered "hidden fd"
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013535 evalstring(minusc, 0);
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000013536 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013537
13538 if (sflag || minusc == NULL) {
Denys Vlasenko4840ae82011-09-04 15:28:03 +020013539#if MAX_HISTORY > 0 && ENABLE_FEATURE_EDITING_SAVEHISTORY
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +000013540 if (iflag) {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013541 const char *hp = lookupvar("HISTFILE");
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010013542 if (!hp) {
13543 hp = lookupvar("HOME");
Stefan Hellermann4ef14392013-03-15 02:45:50 +010013544 if (hp) {
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010013545 hp = concat_path_file(hp, ".ash_history");
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020013546 setvar0("HISTFILE", hp);
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010013547 free((char*)hp);
13548 hp = lookupvar("HISTFILE");
13549 }
13550 }
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000013551 if (hp)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013552 line_input_state->hist_file = hp;
Denys Vlasenko2c4de5b2011-03-31 13:16:52 +020013553# if ENABLE_FEATURE_SH_HISTFILESIZE
13554 hp = lookupvar("HISTFILESIZE");
13555 line_input_state->max_history = size_from_HISTFILESIZE(hp);
13556# endif
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013557 }
13558#endif
13559 state4: /* XXX ??? - why isn't this before the "if" statement */
13560 cmdloop(1);
13561 }
13562#if PROFILE
13563 monitor(0);
13564#endif
13565#ifdef GPROF
13566 {
13567 extern void _mcleanup(void);
13568 _mcleanup();
13569 }
13570#endif
Denys Vlasenkob563f622010-09-25 17:15:13 +020013571 TRACE(("End of main reached\n"));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013572 exitshell();
13573 /* NOTREACHED */
13574}
13575
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013576
Eric Andersendf82f612001-06-28 07:46:40 +000013577/*-
13578 * Copyright (c) 1989, 1991, 1993, 1994
Eric Andersen2870d962001-07-02 17:27:21 +000013579 * The Regents of the University of California. All rights reserved.
Eric Andersendf82f612001-06-28 07:46:40 +000013580 *
13581 * This code is derived from software contributed to Berkeley by
13582 * Kenneth Almquist.
13583 *
13584 * Redistribution and use in source and binary forms, with or without
13585 * modification, are permitted provided that the following conditions
13586 * are met:
13587 * 1. Redistributions of source code must retain the above copyright
13588 * notice, this list of conditions and the following disclaimer.
13589 * 2. Redistributions in binary form must reproduce the above copyright
13590 * notice, this list of conditions and the following disclaimer in the
13591 * documentation and/or other materials provided with the distribution.
"Vladimir N. Oleynik"ddc280e2005-12-15 12:01:49 +000013592 * 3. Neither the name of the University nor the names of its contributors
Eric Andersendf82f612001-06-28 07:46:40 +000013593 * may be used to endorse or promote products derived from this software
13594 * without specific prior written permission.
13595 *
13596 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
13597 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
13598 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
13599 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
13600 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
13601 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
13602 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
13603 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
13604 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
13605 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
13606 * SUCH DAMAGE.
13607 */