blob: aee3d419c7b243fbe4c1d8ef8ee3e6e887e9edc3 [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;
5436 i = fcntl(fd, F_DUPFD, minfd);
Denis Vlasenko5a867312008-07-24 19:46:38 +00005437/* You'd expect copy to be CLOEXECed. Currently these extra "saved" fds
5438 * are closed in popredir() in the child, preventing them from leaking
5439 * into child. (popredir() also cleans up the mess in case of failures)
5440 */
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 */
5455 /* "exec fd>&-" should not close fds
5456 * which point to script file(s).
5457 * Force them to be restored afterwards */
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005458 if (is_hidden_fd(sv, fd))
5459 i |= COPYFD_RESTORE;
Denis Vlasenko22f74142008-07-24 22:34:43 +00005460 }
Denis Vlasenko5a867312008-07-24 19:46:38 +00005461 if (fd == 2)
5462 copied_fd2 = i;
5463 sv->two_fd[sv_pos].orig = fd;
5464 sv->two_fd[sv_pos].copy = i;
5465 sv_pos++;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005466 }
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005467 if (newfd < 0) {
5468 /* NTOFD/NFROMFD: copy redir->ndup.dupfd to fd */
Denis Vlasenko22f74142008-07-24 22:34:43 +00005469 if (redir->ndup.dupfd < 0) { /* "fd>&-" */
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +00005470 /* Don't want to trigger debugging */
5471 if (fd != -1)
5472 close(fd);
Denis Vlasenko5a867312008-07-24 19:46:38 +00005473 } else {
Denys Vlasenko64774602016-10-26 15:24:30 +02005474 dup2_or_raise(redir->ndup.dupfd, fd);
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005475 }
Denis Vlasenko5a867312008-07-24 19:46:38 +00005476 } else if (fd != newfd) { /* move newfd to fd */
Denys Vlasenko64774602016-10-26 15:24:30 +02005477 dup2_or_raise(newfd, fd);
Denis Vlasenko559691a2008-10-05 18:39:31 +00005478#if ENABLE_ASH_BASH_COMPAT
5479 if (!(redir->nfile.type == NTO2 && fd == 2))
5480#endif
5481 close(newfd);
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005482 }
Denis Vlasenko559691a2008-10-05 18:39:31 +00005483#if ENABLE_ASH_BASH_COMPAT
5484 if (redir->nfile.type == NTO2 && fd == 1) {
5485 /* We already redirected it to fd 1, now copy it to 2 */
5486 newfd = 1;
5487 fd = 2;
5488 goto redirect_more;
5489 }
5490#endif
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00005491 } while ((redir = redir->nfile.next) != NULL);
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005492
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005493 INT_ON;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005494 if ((flags & REDIR_SAVEFD2) && copied_fd2 >= 0)
5495 preverrout_fd = copied_fd2;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005496}
5497
5498/*
5499 * Undo the effects of the last redirection.
5500 */
5501static void
Denis Vlasenko34c73c42008-08-16 11:48:02 +00005502popredir(int drop, int restore)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005503{
5504 struct redirtab *rp;
5505 int i;
5506
Denys Vlasenkoeaf94362016-10-25 21:46:03 +02005507 if (redirlist == NULL)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005508 return;
5509 INT_OFF;
5510 rp = redirlist;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005511 for (i = 0; i < rp->pair_count; i++) {
5512 int fd = rp->two_fd[i].orig;
Denis Vlasenko22f74142008-07-24 22:34:43 +00005513 int copy = rp->two_fd[i].copy;
5514 if (copy == CLOSED) {
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005515 if (!drop)
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005516 close(fd);
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005517 continue;
5518 }
Denis Vlasenko22f74142008-07-24 22:34:43 +00005519 if (copy != EMPTY) {
Denis Vlasenko34c73c42008-08-16 11:48:02 +00005520 if (!drop || (restore && (copy & COPYFD_RESTORE))) {
Denis Vlasenko22f74142008-07-24 22:34:43 +00005521 copy &= ~COPYFD_RESTORE;
Denis Vlasenko5a867312008-07-24 19:46:38 +00005522 /*close(fd);*/
Denys Vlasenko64774602016-10-26 15:24:30 +02005523 dup2_or_raise(copy, fd);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005524 }
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +00005525 close(copy & ~COPYFD_RESTORE);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005526 }
5527 }
5528 redirlist = rp->next;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005529 free(rp);
5530 INT_ON;
5531}
5532
5533/*
5534 * Undo all redirections. Called on error or interrupt.
5535 */
5536
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005537static int
5538redirectsafe(union node *redir, int flags)
5539{
5540 int err;
5541 volatile int saveint;
5542 struct jmploc *volatile savehandler = exception_handler;
5543 struct jmploc jmploc;
5544
5545 SAVE_INT(saveint);
Denis Vlasenko5a867312008-07-24 19:46:38 +00005546 /* "echo 9>/dev/null; echo >&9; echo result: $?" - result should be 1, not 2! */
5547 err = setjmp(jmploc.loc); // huh?? was = setjmp(jmploc.loc) * 2;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005548 if (!err) {
5549 exception_handler = &jmploc;
5550 redirect(redir, flags);
5551 }
5552 exception_handler = savehandler;
Denis Vlasenko7f88e342009-03-19 03:36:18 +00005553 if (err && exception_type != EXERROR)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005554 longjmp(exception_handler->loc, 1);
5555 RESTORE_INT(saveint);
5556 return err;
5557}
5558
5559
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005560/* ============ Routines to expand arguments to commands
5561 *
5562 * We have to deal with backquotes, shell variables, and file metacharacters.
5563 */
5564
Denys Vlasenko0b883582016-12-23 16:49:07 +01005565#if ENABLE_FEATURE_SH_MATH
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005566static arith_t
5567ash_arith(const char *s)
5568{
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005569 arith_state_t math_state;
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005570 arith_t result;
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005571
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005572 math_state.lookupvar = lookupvar;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02005573 math_state.setvar = setvar0;
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005574 //math_state.endofname = endofname;
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005575
5576 INT_OFF;
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005577 result = arith(&math_state, s);
Denys Vlasenko063847d2010-09-15 13:33:02 +02005578 if (math_state.errmsg)
5579 ash_msg_and_raise_error(math_state.errmsg);
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005580 INT_ON;
5581
5582 return result;
5583}
Denis Vlasenko448d30e2008-06-27 00:24:11 +00005584#endif
5585
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005586/*
5587 * expandarg flags
5588 */
5589#define EXP_FULL 0x1 /* perform word splitting & file globbing */
5590#define EXP_TILDE 0x2 /* do normal tilde expansion */
5591#define EXP_VARTILDE 0x4 /* expand tildes in an assignment */
5592#define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */
Denys Vlasenkodb74c6c2016-10-24 21:12:33 +02005593/* ^^^^^^^^^^^^^^ this is meant to support constructs such as "cmd >file*.txt"
5594 * POSIX says for this case:
5595 * Pathname expansion shall not be performed on the word by a
5596 * non-interactive shell; an interactive shell may perform it, but shall
5597 * do so only when the expansion would result in one word.
5598 * Currently, our code complies to the above rule by never globbing
5599 * redirection filenames.
5600 * Bash performs globbing, unless it is non-interactive and in POSIX mode.
5601 * (this means that on a typical Linux distro, bash almost always
5602 * performs globbing, and thus diverges from what we do).
5603 */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005604#define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */
Ron Yorston549deab2015-05-18 09:57:51 +02005605#define EXP_QPAT 0x20 /* pattern in quoted parameter expansion */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005606#define EXP_VARTILDE2 0x40 /* expand tildes after colons only */
5607#define EXP_WORD 0x80 /* expand word in parameter expansion */
Ron Yorston3df47f92015-05-18 09:53:26 +02005608#define EXP_QUOTED 0x100 /* expand word in double quotes */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005609/*
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005610 * rmescape() flags
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005611 */
5612#define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
5613#define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005614#define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */
5615#define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */
Ron Yorston417622c2015-05-18 09:59:14 +02005616#define RMESCAPE_SLASH 0x20 /* Stop globbing after slash */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005617
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005618/* Add CTLESC when necessary. */
Ron Yorston549deab2015-05-18 09:57:51 +02005619#define QUOTES_ESC (EXP_FULL | EXP_CASE | EXP_QPAT | EXP_REDIR)
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005620/* Do not skip NUL characters. */
5621#define QUOTES_KEEPNUL EXP_TILDE
5622
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005623/*
5624 * Structure specifying which parts of the string should be searched
5625 * for IFS characters.
5626 */
5627struct ifsregion {
5628 struct ifsregion *next; /* next region in list */
5629 int begoff; /* offset of start of region */
5630 int endoff; /* offset of end of region */
5631 int nulonly; /* search for nul bytes only */
5632};
5633
5634struct arglist {
5635 struct strlist *list;
5636 struct strlist **lastp;
5637};
5638
5639/* output of current string */
5640static char *expdest;
5641/* list of back quote expressions */
5642static struct nodelist *argbackq;
5643/* first struct in list of ifs regions */
5644static struct ifsregion ifsfirst;
5645/* last struct in list */
5646static struct ifsregion *ifslastp;
5647/* holds expanded arg list */
5648static struct arglist exparg;
5649
5650/*
5651 * Our own itoa().
5652 */
Denys Vlasenko0b883582016-12-23 16:49:07 +01005653#if !ENABLE_FEATURE_SH_MATH
Denys Vlasenko26777aa2010-11-22 23:49:10 +01005654/* cvtnum() is used even if math support is off (to prepare $? values and such) */
5655typedef long arith_t;
5656# define ARITH_FMT "%ld"
5657#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005658static int
5659cvtnum(arith_t num)
5660{
5661 int len;
5662
Denys Vlasenko9c541002015-10-07 15:44:36 +02005663 expdest = makestrspace(sizeof(arith_t)*3 + 2, expdest);
5664 len = fmtstr(expdest, sizeof(arith_t)*3 + 2, ARITH_FMT, num);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005665 STADJUST(len, expdest);
5666 return len;
5667}
5668
Denys Vlasenko455e4222016-10-27 14:45:13 +02005669/*
5670 * Break the argument string into pieces based upon IFS and add the
5671 * strings to the argument list. The regions of the string to be
5672 * searched for IFS characters have been stored by recordregion.
5673 */
5674static void
5675ifsbreakup(char *string, struct arglist *arglist)
5676{
5677 struct ifsregion *ifsp;
5678 struct strlist *sp;
5679 char *start;
5680 char *p;
5681 char *q;
5682 const char *ifs, *realifs;
5683 int ifsspc;
5684 int nulonly;
5685
5686 start = string;
5687 if (ifslastp != NULL) {
5688 ifsspc = 0;
5689 nulonly = 0;
5690 realifs = ifsset() ? ifsval() : defifs;
5691 ifsp = &ifsfirst;
5692 do {
5693 p = string + ifsp->begoff;
5694 nulonly = ifsp->nulonly;
5695 ifs = nulonly ? nullstr : realifs;
5696 ifsspc = 0;
5697 while (p < string + ifsp->endoff) {
5698 q = p;
5699 if ((unsigned char)*p == CTLESC)
5700 p++;
5701 if (!strchr(ifs, *p)) {
5702 p++;
5703 continue;
5704 }
5705 if (!nulonly)
5706 ifsspc = (strchr(defifs, *p) != NULL);
5707 /* Ignore IFS whitespace at start */
5708 if (q == start && ifsspc) {
5709 p++;
5710 start = p;
5711 continue;
5712 }
5713 *q = '\0';
5714 sp = stzalloc(sizeof(*sp));
5715 sp->text = start;
5716 *arglist->lastp = sp;
5717 arglist->lastp = &sp->next;
5718 p++;
5719 if (!nulonly) {
5720 for (;;) {
5721 if (p >= string + ifsp->endoff) {
5722 break;
5723 }
5724 q = p;
5725 if ((unsigned char)*p == CTLESC)
5726 p++;
5727 if (strchr(ifs, *p) == NULL) {
5728 p = q;
5729 break;
5730 }
5731 if (strchr(defifs, *p) == NULL) {
5732 if (ifsspc) {
5733 p++;
5734 ifsspc = 0;
5735 } else {
5736 p = q;
5737 break;
5738 }
5739 } else
5740 p++;
5741 }
5742 }
5743 start = p;
5744 } /* while */
5745 ifsp = ifsp->next;
5746 } while (ifsp != NULL);
5747 if (nulonly)
5748 goto add;
5749 }
5750
5751 if (!*start)
5752 return;
5753
5754 add:
5755 sp = stzalloc(sizeof(*sp));
5756 sp->text = start;
5757 *arglist->lastp = sp;
5758 arglist->lastp = &sp->next;
5759}
5760
5761static void
5762ifsfree(void)
5763{
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02005764 struct ifsregion *p = ifsfirst.next;
5765
5766 if (!p)
5767 goto out;
Denys Vlasenko455e4222016-10-27 14:45:13 +02005768
5769 INT_OFF;
Denys Vlasenko455e4222016-10-27 14:45:13 +02005770 do {
5771 struct ifsregion *ifsp;
5772 ifsp = p->next;
5773 free(p);
5774 p = ifsp;
5775 } while (p);
Denys Vlasenko455e4222016-10-27 14:45:13 +02005776 ifsfirst.next = NULL;
5777 INT_ON;
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02005778 out:
5779 ifslastp = NULL;
Denys Vlasenko455e4222016-10-27 14:45:13 +02005780}
5781
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005782static size_t
5783esclen(const char *start, const char *p)
5784{
5785 size_t esc = 0;
5786
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005787 while (p > start && (unsigned char)*--p == CTLESC) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005788 esc++;
5789 }
5790 return esc;
5791}
5792
5793/*
5794 * Remove any CTLESC characters from a string.
5795 */
5796static char *
Denys Vlasenkob6c84342009-08-29 20:23:20 +02005797rmescapes(char *str, int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005798{
Ron Yorston417622c2015-05-18 09:59:14 +02005799 static const char qchars[] ALIGN1 = {
5800 IF_ASH_BASH_COMPAT('/',) CTLESC, CTLQUOTEMARK, '\0' };
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00005801
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005802 char *p, *q, *r;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005803 unsigned inquotes;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005804 unsigned protect_against_glob;
5805 unsigned globbing;
Ron Yorston417622c2015-05-18 09:59:14 +02005806 IF_ASH_BASH_COMPAT(unsigned slash = flag & RMESCAPE_SLASH;)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005807
Ron Yorston417622c2015-05-18 09:59:14 +02005808 p = strpbrk(str, qchars IF_ASH_BASH_COMPAT(+ !slash));
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005809 if (!p)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005810 return str;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005811
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005812 q = p;
5813 r = str;
5814 if (flag & RMESCAPE_ALLOC) {
5815 size_t len = p - str;
5816 size_t fulllen = len + strlen(p) + 1;
5817
5818 if (flag & RMESCAPE_GROW) {
Colin Watson3963d942010-04-26 14:21:27 +02005819 int strloc = str - (char *)stackblock();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005820 r = makestrspace(fulllen, expdest);
Colin Watson3963d942010-04-26 14:21:27 +02005821 /* p and str may be invalidated by makestrspace */
5822 str = (char *)stackblock() + strloc;
5823 p = str + len;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005824 } else if (flag & RMESCAPE_HEAP) {
5825 r = ckmalloc(fulllen);
5826 } else {
5827 r = stalloc(fulllen);
5828 }
5829 q = r;
5830 if (len > 0) {
Denis Vlasenko29eb3592008-05-18 14:06:08 +00005831 q = (char *)memcpy(q, str, len) + len;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005832 }
5833 }
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005834
Ron Yorston549deab2015-05-18 09:57:51 +02005835 inquotes = 0;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005836 globbing = flag & RMESCAPE_GLOB;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005837 protect_against_glob = globbing;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005838 while (*p) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01005839 if ((unsigned char)*p == CTLQUOTEMARK) {
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005840// Note: both inquotes and protect_against_glob only affect whether
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005841 inquotes = ~inquotes;
5842 p++;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005843 protect_against_glob = globbing;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005844 continue;
5845 }
Ron Yorston549deab2015-05-18 09:57:51 +02005846 if ((unsigned char)*p == CTLESC) {
5847 p++;
Denys Vlasenko13f20912016-09-25 20:54:25 +02005848#if DEBUG
5849 if (*p == '\0')
5850 ash_msg_and_raise_error("CTLESC at EOL (shouldn't happen)");
5851#endif
Ron Yorston549deab2015-05-18 09:57:51 +02005852 if (protect_against_glob) {
5853 *q++ = '\\';
5854 }
5855 } else if (*p == '\\' && !inquotes) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005856 /* naked back slash */
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005857 protect_against_glob = 0;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005858 goto copy;
5859 }
Ron Yorston417622c2015-05-18 09:59:14 +02005860#if ENABLE_ASH_BASH_COMPAT
5861 else if (*p == '/' && slash) {
5862 /* stop handling globbing and mark location of slash */
5863 globbing = slash = 0;
5864 *p = CTLESC;
5865 }
5866#endif
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005867 protect_against_glob = globbing;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005868 copy:
5869 *q++ = *p++;
5870 }
5871 *q = '\0';
5872 if (flag & RMESCAPE_GROW) {
5873 expdest = r;
5874 STADJUST(q - r + 1, expdest);
5875 }
5876 return r;
5877}
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005878#define pmatch(a, b) !fnmatch((a), (b), 0)
5879
5880/*
5881 * Prepare a pattern for a expmeta (internal glob(3)) call.
5882 *
5883 * Returns an stalloced string.
5884 */
5885static char *
Ron Yorston549deab2015-05-18 09:57:51 +02005886preglob(const char *pattern, int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005887{
Ron Yorston549deab2015-05-18 09:57:51 +02005888 return rmescapes((char *)pattern, flag | RMESCAPE_GLOB);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005889}
5890
5891/*
5892 * Put a string on the stack.
5893 */
5894static void
5895memtodest(const char *p, size_t len, int syntax, int quotes)
5896{
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005897 char *q;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005898
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005899 if (!len)
5900 return;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005901
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005902 q = makestrspace((quotes & QUOTES_ESC) ? len * 2 : len, expdest);
5903
5904 do {
Denys Vlasenkocd716832009-11-28 22:14:02 +01005905 unsigned char c = *p++;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005906 if (c) {
Denys Vlasenko2fe66b12016-12-12 17:39:12 +01005907 if (quotes & QUOTES_ESC) {
5908 int n = SIT(c, syntax);
5909 if (n == CCTL
5910 || (((quotes & EXP_FULL) || syntax != BASESYNTAX)
5911 && n == CBACK
5912 )
5913 ) {
5914 USTPUTC(CTLESC, q);
5915 }
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02005916 }
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005917 } else if (!(quotes & QUOTES_KEEPNUL))
5918 continue;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005919 USTPUTC(c, q);
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005920 } while (--len);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005921
5922 expdest = q;
5923}
5924
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005925static size_t
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005926strtodest(const char *p, int syntax, int quotes)
5927{
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005928 size_t len = strlen(p);
5929 memtodest(p, len, syntax, quotes);
5930 return len;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005931}
5932
5933/*
5934 * Record the fact that we have to scan this region of the
5935 * string for IFS characters.
5936 */
5937static void
5938recordregion(int start, int end, int nulonly)
5939{
5940 struct ifsregion *ifsp;
5941
5942 if (ifslastp == NULL) {
5943 ifsp = &ifsfirst;
5944 } else {
5945 INT_OFF;
Denis Vlasenko597906c2008-02-20 16:38:54 +00005946 ifsp = ckzalloc(sizeof(*ifsp));
5947 /*ifsp->next = NULL; - ckzalloc did it */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005948 ifslastp->next = ifsp;
5949 INT_ON;
5950 }
5951 ifslastp = ifsp;
5952 ifslastp->begoff = start;
5953 ifslastp->endoff = end;
5954 ifslastp->nulonly = nulonly;
5955}
5956
5957static void
5958removerecordregions(int endoff)
5959{
5960 if (ifslastp == NULL)
5961 return;
5962
5963 if (ifsfirst.endoff > endoff) {
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02005964 while (ifsfirst.next) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005965 struct ifsregion *ifsp;
5966 INT_OFF;
5967 ifsp = ifsfirst.next->next;
5968 free(ifsfirst.next);
5969 ifsfirst.next = ifsp;
5970 INT_ON;
5971 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02005972 if (ifsfirst.begoff > endoff) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005973 ifslastp = NULL;
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02005974 } else {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005975 ifslastp = &ifsfirst;
5976 ifsfirst.endoff = endoff;
5977 }
5978 return;
5979 }
5980
5981 ifslastp = &ifsfirst;
5982 while (ifslastp->next && ifslastp->next->begoff < endoff)
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02005983 ifslastp = ifslastp->next;
5984 while (ifslastp->next) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005985 struct ifsregion *ifsp;
5986 INT_OFF;
5987 ifsp = ifslastp->next->next;
5988 free(ifslastp->next);
5989 ifslastp->next = ifsp;
5990 INT_ON;
5991 }
5992 if (ifslastp->endoff > endoff)
5993 ifslastp->endoff = endoff;
5994}
5995
5996static char *
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005997exptilde(char *startp, char *p, int flags)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005998{
Denys Vlasenkocd716832009-11-28 22:14:02 +01005999 unsigned char c;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006000 char *name;
6001 struct passwd *pw;
6002 const char *home;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006003 int quotes = flags & QUOTES_ESC;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006004
6005 name = p + 1;
6006
6007 while ((c = *++p) != '\0') {
6008 switch (c) {
6009 case CTLESC:
6010 return startp;
6011 case CTLQUOTEMARK:
6012 return startp;
6013 case ':':
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006014 if (flags & EXP_VARTILDE)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006015 goto done;
6016 break;
6017 case '/':
6018 case CTLENDVAR:
6019 goto done;
6020 }
6021 }
6022 done:
6023 *p = '\0';
6024 if (*name == '\0') {
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02006025 home = lookupvar("HOME");
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006026 } else {
6027 pw = getpwnam(name);
6028 if (pw == NULL)
6029 goto lose;
6030 home = pw->pw_dir;
6031 }
6032 if (!home || !*home)
6033 goto lose;
6034 *p = c;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006035 strtodest(home, SQSYNTAX, quotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006036 return p;
6037 lose:
6038 *p = c;
6039 return startp;
6040}
6041
6042/*
6043 * Execute a command inside back quotes. If it's a builtin command, we
6044 * want to save its output in a block obtained from malloc. Otherwise
6045 * we fork off a subprocess and get the output of the command via a pipe.
6046 * Should be called with interrupts off.
6047 */
6048struct backcmd { /* result of evalbackcmd */
6049 int fd; /* file descriptor to read from */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006050 int nleft; /* number of chars in buffer */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00006051 char *buf; /* buffer */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006052 struct job *jp; /* job structure for command */
6053};
6054
6055/* These forward decls are needed to use "eval" code for backticks handling: */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006056#define EV_EXIT 01 /* exit after evaluating tree */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02006057static int evaltree(union node *, int);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006058
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02006059static void FAST_FUNC
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006060evalbackcmd(union node *n, struct backcmd *result)
6061{
Denys Vlasenko579ad102016-10-25 21:10:20 +02006062 int pip[2];
6063 struct job *jp;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006064
6065 result->fd = -1;
6066 result->buf = NULL;
6067 result->nleft = 0;
6068 result->jp = NULL;
Denys Vlasenko579ad102016-10-25 21:10:20 +02006069 if (n == NULL) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006070 goto out;
Denys Vlasenko579ad102016-10-25 21:10:20 +02006071 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006072
Denys Vlasenko579ad102016-10-25 21:10:20 +02006073 if (pipe(pip) < 0)
6074 ash_msg_and_raise_error("pipe call failed");
6075 jp = makejob(/*n,*/ 1);
6076 if (forkshell(jp, n, FORK_NOJOB) == 0) {
Denys Vlasenko70392332016-10-27 02:31:55 +02006077 /* child */
Denys Vlasenko579ad102016-10-25 21:10:20 +02006078 FORCE_INT_ON;
6079 close(pip[0]);
6080 if (pip[1] != 1) {
6081 /*close(1);*/
Denys Vlasenko64774602016-10-26 15:24:30 +02006082 dup2_or_raise(pip[1], 1);
Denys Vlasenko579ad102016-10-25 21:10:20 +02006083 close(pip[1]);
6084 }
Denys Vlasenko960ca382016-10-25 18:12:15 +02006085/* TODO: eflag clearing makes the following not abort:
6086 * ash -c 'set -e; z=$(false;echo foo); echo $z'
6087 * which is what bash does (unless it is in POSIX mode).
6088 * dash deleted "eflag = 0" line in the commit
6089 * Date: Mon, 28 Jun 2010 17:11:58 +1000
6090 * [EVAL] Don't clear eflag in evalbackcmd
6091 * For now, preserve bash-like behavior, it seems to be somewhat more useful:
6092 */
Denys Vlasenko579ad102016-10-25 21:10:20 +02006093 eflag = 0;
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02006094 ifsfree();
Denys Vlasenko579ad102016-10-25 21:10:20 +02006095 evaltree(n, EV_EXIT); /* actually evaltreenr... */
6096 /* NOTREACHED */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006097 }
Denys Vlasenko70392332016-10-27 02:31:55 +02006098 /* parent */
Denys Vlasenko579ad102016-10-25 21:10:20 +02006099 close(pip[1]);
6100 result->fd = pip[0];
6101 result->jp = jp;
6102
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006103 out:
6104 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
6105 result->fd, result->buf, result->nleft, result->jp));
6106}
6107
6108/*
6109 * Expand stuff in backwards quotes.
6110 */
6111static void
Ron Yorston549deab2015-05-18 09:57:51 +02006112expbackq(union node *cmd, int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006113{
6114 struct backcmd in;
6115 int i;
6116 char buf[128];
6117 char *p;
6118 char *dest;
6119 int startloc;
Ron Yorston549deab2015-05-18 09:57:51 +02006120 int syntax = flag & EXP_QUOTED ? DQSYNTAX : BASESYNTAX;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006121 struct stackmark smark;
6122
6123 INT_OFF;
Denys Vlasenko60ca8342016-09-30 11:21:21 +02006124 startloc = expdest - (char *)stackblock();
6125 pushstackmark(&smark, startloc);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006126 evalbackcmd(cmd, &in);
6127 popstackmark(&smark);
6128
6129 p = in.buf;
6130 i = in.nleft;
6131 if (i == 0)
6132 goto read;
6133 for (;;) {
Ron Yorston549deab2015-05-18 09:57:51 +02006134 memtodest(p, i, syntax, flag & QUOTES_ESC);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006135 read:
6136 if (in.fd < 0)
6137 break;
Ron Yorston61d6ae22015-04-19 10:50:25 +01006138 i = nonblock_immune_read(in.fd, buf, sizeof(buf));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006139 TRACE(("expbackq: read returns %d\n", i));
6140 if (i <= 0)
6141 break;
6142 p = buf;
6143 }
6144
Denis Vlasenko60818682007-09-28 22:07:23 +00006145 free(in.buf);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006146 if (in.fd >= 0) {
6147 close(in.fd);
6148 back_exitstatus = waitforjob(in.jp);
6149 }
6150 INT_ON;
6151
6152 /* Eat all trailing newlines */
6153 dest = expdest;
6154 for (; dest > (char *)stackblock() && dest[-1] == '\n';)
6155 STUNPUTC(dest);
6156 expdest = dest;
6157
Ron Yorston549deab2015-05-18 09:57:51 +02006158 if (!(flag & EXP_QUOTED))
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006159 recordregion(startloc, dest - (char *)stackblock(), 0);
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006160 TRACE(("evalbackq: size:%d:'%.*s'\n",
6161 (int)((dest - (char *)stackblock()) - startloc),
6162 (int)((dest - (char *)stackblock()) - startloc),
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006163 stackblock() + startloc));
6164}
6165
Denys Vlasenko0b883582016-12-23 16:49:07 +01006166#if ENABLE_FEATURE_SH_MATH
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006167/*
6168 * Expand arithmetic expression. Backup to start of expression,
6169 * evaluate, place result in (backed up) result, adjust string position.
6170 */
6171static void
Ron Yorston549deab2015-05-18 09:57:51 +02006172expari(int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006173{
6174 char *p, *start;
6175 int begoff;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006176 int len;
6177
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006178 /* ifsfree(); */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006179
6180 /*
6181 * This routine is slightly over-complicated for
6182 * efficiency. Next we scan backwards looking for the
6183 * start of arithmetic.
6184 */
6185 start = stackblock();
6186 p = expdest - 1;
6187 *p = '\0';
6188 p--;
Denys Vlasenko940c7202011-03-02 04:07:14 +01006189 while (1) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006190 int esc;
6191
Denys Vlasenkocd716832009-11-28 22:14:02 +01006192 while ((unsigned char)*p != CTLARI) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006193 p--;
6194#if DEBUG
6195 if (p < start) {
6196 ash_msg_and_raise_error("missing CTLARI (shouldn't happen)");
6197 }
6198#endif
6199 }
6200
6201 esc = esclen(start, p);
6202 if (!(esc % 2)) {
6203 break;
6204 }
6205
6206 p -= esc + 1;
Denys Vlasenko940c7202011-03-02 04:07:14 +01006207 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006208
6209 begoff = p - start;
6210
6211 removerecordregions(begoff);
6212
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006213 expdest = p;
6214
Ron Yorston549deab2015-05-18 09:57:51 +02006215 if (flag & QUOTES_ESC)
6216 rmescapes(p + 1, 0);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006217
Ron Yorston549deab2015-05-18 09:57:51 +02006218 len = cvtnum(ash_arith(p + 1));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006219
Ron Yorston549deab2015-05-18 09:57:51 +02006220 if (!(flag & EXP_QUOTED))
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006221 recordregion(begoff, begoff + len, 0);
6222}
6223#endif
6224
6225/* argstr needs it */
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006226static char *evalvar(char *p, int flags, struct strlist *var_str_list);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006227
6228/*
6229 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
6230 * characters to allow for further processing. Otherwise treat
6231 * $@ like $* since no splitting will be performed.
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006232 *
6233 * var_str_list (can be NULL) is a list of "VAR=val" strings which take precedence
6234 * over shell varables. Needed for "A=a B=$A; echo $B" case - we use it
6235 * for correct expansion of "B=$A" word.
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006236 */
6237static void
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006238argstr(char *p, int flags, struct strlist *var_str_list)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006239{
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00006240 static const char spclchars[] ALIGN1 = {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006241 '=',
6242 ':',
6243 CTLQUOTEMARK,
6244 CTLENDVAR,
6245 CTLESC,
6246 CTLVAR,
6247 CTLBACKQ,
Denys Vlasenko0b883582016-12-23 16:49:07 +01006248#if ENABLE_FEATURE_SH_MATH
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006249 CTLENDARI,
6250#endif
Denys Vlasenkocd716832009-11-28 22:14:02 +01006251 '\0'
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006252 };
6253 const char *reject = spclchars;
Ron Yorston3df47f92015-05-18 09:53:26 +02006254 int breakall = (flags & (EXP_WORD | EXP_QUOTED)) == EXP_WORD;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006255 int inquotes;
6256 size_t length;
6257 int startloc;
6258
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006259 if (!(flags & EXP_VARTILDE)) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006260 reject += 2;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006261 } else if (flags & EXP_VARTILDE2) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006262 reject++;
6263 }
6264 inquotes = 0;
6265 length = 0;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006266 if (flags & EXP_TILDE) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006267 char *q;
6268
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006269 flags &= ~EXP_TILDE;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006270 tilde:
6271 q = p;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006272 if (*q == '~')
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006273 p = exptilde(p, q, flags);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006274 }
6275 start:
6276 startloc = expdest - (char *)stackblock();
6277 for (;;) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006278 unsigned char c;
6279
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006280 length += strcspn(p + length, reject);
Denys Vlasenkocd716832009-11-28 22:14:02 +01006281 c = p[length];
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006282 if (c) {
6283 if (!(c & 0x80)
Denys Vlasenko0b883582016-12-23 16:49:07 +01006284 IF_FEATURE_SH_MATH(|| c == CTLENDARI)
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006285 ) {
6286 /* c == '=' || c == ':' || c == CTLENDARI */
6287 length++;
6288 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006289 }
6290 if (length > 0) {
6291 int newloc;
6292 expdest = stack_nputstr(p, length, expdest);
6293 newloc = expdest - (char *)stackblock();
6294 if (breakall && !inquotes && newloc > startloc) {
6295 recordregion(startloc, newloc, 0);
6296 }
6297 startloc = newloc;
6298 }
6299 p += length + 1;
6300 length = 0;
6301
6302 switch (c) {
6303 case '\0':
6304 goto breakloop;
6305 case '=':
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006306 if (flags & EXP_VARTILDE2) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006307 p--;
6308 continue;
6309 }
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006310 flags |= EXP_VARTILDE2;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006311 reject++;
6312 /* fall through */
6313 case ':':
6314 /*
6315 * sort of a hack - expand tildes in variable
6316 * assignments (after the first '=' and after ':'s).
6317 */
6318 if (*--p == '~') {
6319 goto tilde;
6320 }
6321 continue;
6322 }
6323
6324 switch (c) {
6325 case CTLENDVAR: /* ??? */
6326 goto breakloop;
6327 case CTLQUOTEMARK:
Ron Yorston549deab2015-05-18 09:57:51 +02006328 inquotes ^= EXP_QUOTED;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006329 /* "$@" syntax adherence hack */
Ron Yorston549deab2015-05-18 09:57:51 +02006330 if (inquotes && !memcmp(p, dolatstr + 1, DOLATSTRLEN - 1)) {
6331 p = evalvar(p + 1, flags | inquotes, /* var_str_list: */ NULL) + 1;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006332 goto start;
6333 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006334 addquote:
Ron Yorston549deab2015-05-18 09:57:51 +02006335 if (flags & QUOTES_ESC) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006336 p--;
6337 length++;
6338 startloc++;
6339 }
6340 break;
6341 case CTLESC:
6342 startloc++;
6343 length++;
Ron Yorston549deab2015-05-18 09:57:51 +02006344
6345 /*
6346 * Quoted parameter expansion pattern: remove quote
6347 * unless inside inner quotes or we have a literal
6348 * backslash.
6349 */
6350 if (((flags | inquotes) & (EXP_QPAT | EXP_QUOTED)) ==
6351 EXP_QPAT && *p != '\\')
6352 break;
6353
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006354 goto addquote;
6355 case CTLVAR:
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02006356 TRACE(("argstr: evalvar('%s')\n", p));
Ron Yorston549deab2015-05-18 09:57:51 +02006357 p = evalvar(p, flags | inquotes, var_str_list);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02006358 TRACE(("argstr: evalvar:'%s'\n", (char *)stackblock()));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006359 goto start;
6360 case CTLBACKQ:
Ron Yorston549deab2015-05-18 09:57:51 +02006361 expbackq(argbackq->n, flags | inquotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006362 argbackq = argbackq->next;
6363 goto start;
Denys Vlasenko0b883582016-12-23 16:49:07 +01006364#if ENABLE_FEATURE_SH_MATH
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006365 case CTLENDARI:
6366 p--;
Ron Yorston549deab2015-05-18 09:57:51 +02006367 expari(flags | inquotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006368 goto start;
6369#endif
6370 }
6371 }
Denys Vlasenko958581a2010-09-12 15:04:27 +02006372 breakloop: ;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006373}
6374
6375static char *
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006376scanleft(char *startp, char *rmesc, char *rmescend UNUSED_PARAM,
6377 char *pattern, int quotes, int zero)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006378{
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006379 char *loc, *loc2;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006380 char c;
6381
6382 loc = startp;
6383 loc2 = rmesc;
6384 do {
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006385 int match;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006386 const char *s = loc2;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006387
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006388 c = *loc2;
6389 if (zero) {
6390 *loc2 = '\0';
6391 s = rmesc;
6392 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006393 match = pmatch(pattern, s);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006394
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006395 *loc2 = c;
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006396 if (match)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006397 return loc;
Denys Vlasenkocd716832009-11-28 22:14:02 +01006398 if (quotes && (unsigned char)*loc == CTLESC)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006399 loc++;
6400 loc++;
6401 loc2++;
6402 } while (c);
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006403 return NULL;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006404}
6405
6406static char *
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006407scanright(char *startp, char *rmesc, char *rmescend,
6408 char *pattern, int quotes, int match_at_start)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006409{
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006410#if !ENABLE_ASH_OPTIMIZE_FOR_SIZE
6411 int try2optimize = match_at_start;
6412#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006413 int esc = 0;
6414 char *loc;
6415 char *loc2;
6416
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006417 /* If we called by "${v/pattern/repl}" or "${v//pattern/repl}":
6418 * startp="escaped_value_of_v" rmesc="raw_value_of_v"
6419 * rmescend=""(ptr to NUL in rmesc) pattern="pattern" quotes=match_at_start=1
6420 * Logic:
6421 * loc starts at NUL at the end of startp, loc2 starts at the end of rmesc,
6422 * and on each iteration they go back two/one char until they reach the beginning.
6423 * We try to find a match in "raw_value_of_v", "raw_value_of_", "raw_value_of" etc.
6424 */
6425 /* TODO: document in what other circumstances we are called. */
6426
6427 for (loc = pattern - 1, loc2 = rmescend; loc >= startp; loc2--) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006428 int match;
6429 char c = *loc2;
6430 const char *s = loc2;
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006431 if (match_at_start) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006432 *loc2 = '\0';
6433 s = rmesc;
6434 }
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006435 match = pmatch(pattern, s);
6436 //bb_error_msg("pmatch(pattern:'%s',s:'%s'):%d", pattern, s, match);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006437 *loc2 = c;
6438 if (match)
6439 return loc;
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006440#if !ENABLE_ASH_OPTIMIZE_FOR_SIZE
6441 if (try2optimize) {
6442 /* Maybe we can optimize this:
6443 * if pattern ends with unescaped *, we can avoid checking
6444 * shorter strings: if "foo*" doesnt match "raw_value_of_v",
6445 * it wont match truncated "raw_value_of_" strings too.
6446 */
6447 unsigned plen = strlen(pattern);
6448 /* Does it end with "*"? */
6449 if (plen != 0 && pattern[--plen] == '*') {
6450 /* "xxxx*" is not escaped */
6451 /* "xxx\*" is escaped */
6452 /* "xx\\*" is not escaped */
6453 /* "x\\\*" is escaped */
6454 int slashes = 0;
6455 while (plen != 0 && pattern[--plen] == '\\')
6456 slashes++;
6457 if (!(slashes & 1))
6458 break; /* ends with unescaped "*" */
6459 }
6460 try2optimize = 0;
6461 }
6462#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006463 loc--;
6464 if (quotes) {
6465 if (--esc < 0) {
6466 esc = esclen(startp, loc);
6467 }
6468 if (esc % 2) {
6469 esc--;
6470 loc--;
6471 }
6472 }
6473 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006474 return NULL;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006475}
6476
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00006477static void varunset(const char *, const char *, const char *, int) NORETURN;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006478static void
6479varunset(const char *end, const char *var, const char *umsg, int varflags)
6480{
6481 const char *msg;
6482 const char *tail;
6483
6484 tail = nullstr;
6485 msg = "parameter not set";
6486 if (umsg) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006487 if ((unsigned char)*end == CTLENDVAR) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006488 if (varflags & VSNUL)
6489 tail = " or null";
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006490 } else {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006491 msg = umsg;
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006492 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006493 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006494 ash_msg_and_raise_error("%.*s: %s%s", (int)(end - var - 1), var, msg, tail);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006495}
6496
6497static const char *
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006498subevalvar(char *p, char *varname, int strloc, int subtype,
Ron Yorston549deab2015-05-18 09:57:51 +02006499 int startloc, int varflags, int flag, struct strlist *var_str_list)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006500{
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006501 struct nodelist *saveargbackq = argbackq;
Ron Yorston549deab2015-05-18 09:57:51 +02006502 int quotes = flag & QUOTES_ESC;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006503 char *startp;
6504 char *loc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006505 char *rmesc, *rmescend;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006506 char *str;
Ron Yorston417622c2015-05-18 09:59:14 +02006507 IF_ASH_BASH_COMPAT(char *repl = NULL;)
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00006508 IF_ASH_BASH_COMPAT(int pos, len, orig_len;)
Denys Vlasenko0b4980c2012-09-25 12:49:29 +02006509 int amount, resetloc;
6510 IF_ASH_BASH_COMPAT(int workloc;)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006511 int zero;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006512 char *(*scan)(char*, char*, char*, char*, int, int);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006513
Denys Vlasenko6040fe82010-09-12 15:03:16 +02006514 //bb_error_msg("subevalvar(p:'%s',varname:'%s',strloc:%d,subtype:%d,startloc:%d,varflags:%x,quotes:%d)",
6515 // p, varname, strloc, subtype, startloc, varflags, quotes);
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006516
Ron Yorstoneb6b48b2015-05-18 09:51:35 +02006517 argstr(p, EXP_TILDE | (subtype != VSASSIGN && subtype != VSQUESTION ?
Ron Yorston549deab2015-05-18 09:57:51 +02006518 (flag & (EXP_QUOTED | EXP_QPAT) ? EXP_QPAT : EXP_CASE) : 0),
6519 var_str_list);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006520 STPUTC('\0', expdest);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006521 argbackq = saveargbackq;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006522 startp = (char *)stackblock() + startloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006523
6524 switch (subtype) {
6525 case VSASSIGN:
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02006526 setvar0(varname, startp);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006527 amount = startp - expdest;
6528 STADJUST(amount, expdest);
6529 return startp;
6530
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006531 case VSQUESTION:
6532 varunset(p, varname, startp, varflags);
6533 /* NOTREACHED */
6534
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006535#if ENABLE_ASH_BASH_COMPAT
6536 case VSSUBSTR:
Denys Vlasenkof8ddbe12016-07-25 03:56:00 +02006537//TODO: support more general format ${v:EXPR:EXPR},
6538// where EXPR follows $(()) rules
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006539 loc = str = stackblock() + strloc;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006540 /* Read POS in ${var:POS:LEN} */
6541 pos = atoi(loc); /* number(loc) errors out on "1:4" */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006542 len = str - startp - 1;
6543
6544 /* *loc != '\0', guaranteed by parser */
6545 if (quotes) {
6546 char *ptr;
6547
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006548 /* Adjust the length by the number of escapes */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006549 for (ptr = startp; ptr < (str - 1); ptr++) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006550 if ((unsigned char)*ptr == CTLESC) {
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006551 len--;
6552 ptr++;
6553 }
6554 }
6555 }
6556 orig_len = len;
6557
6558 if (*loc++ == ':') {
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006559 /* ${var::LEN} */
6560 len = number(loc);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006561 } else {
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006562 /* Skip POS in ${var:POS:LEN} */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006563 len = orig_len;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006564 while (*loc && *loc != ':') {
6565 /* TODO?
6566 * bash complains on: var=qwe; echo ${var:1a:123}
6567 if (!isdigit(*loc))
6568 ash_msg_and_raise_error(msg_illnum, str);
6569 */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006570 loc++;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006571 }
6572 if (*loc++ == ':') {
6573 len = number(loc);
6574 }
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006575 }
Denys Vlasenko08a5dab2014-11-17 20:27:18 +01006576 if (pos < 0) {
6577 /* ${VAR:$((-n)):l} starts n chars from the end */
6578 pos = orig_len + pos;
6579 }
6580 if ((unsigned)pos >= orig_len) {
6581 /* apart from obvious ${VAR:999999:l},
6582 * covers ${VAR:$((-9999999)):l} - result is ""
6583 * (bash-compat)
6584 */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006585 pos = 0;
6586 len = 0;
6587 }
6588 if (len > (orig_len - pos))
6589 len = orig_len - pos;
6590
6591 for (str = startp; pos; str++, pos--) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006592 if (quotes && (unsigned char)*str == CTLESC)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006593 str++;
6594 }
6595 for (loc = startp; len; len--) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006596 if (quotes && (unsigned char)*str == CTLESC)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006597 *loc++ = *str++;
6598 *loc++ = *str++;
6599 }
6600 *loc = '\0';
6601 amount = loc - expdest;
6602 STADJUST(amount, expdest);
6603 return loc;
6604#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006605 }
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006606
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006607 resetloc = expdest - (char *)stackblock();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006608
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006609 /* We'll comeback here if we grow the stack while handling
6610 * a VSREPLACE or VSREPLACEALL, since our pointers into the
6611 * stack will need rebasing, and we'll need to remove our work
6612 * areas each time
6613 */
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00006614 IF_ASH_BASH_COMPAT(restart:)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006615
6616 amount = expdest - ((char *)stackblock() + resetloc);
6617 STADJUST(-amount, expdest);
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006618 startp = (char *)stackblock() + startloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006619
6620 rmesc = startp;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006621 rmescend = (char *)stackblock() + strloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006622 if (quotes) {
Denys Vlasenkob6c84342009-08-29 20:23:20 +02006623 rmesc = rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006624 if (rmesc != startp) {
6625 rmescend = expdest;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006626 startp = (char *)stackblock() + startloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006627 }
6628 }
6629 rmescend--;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006630 str = (char *)stackblock() + strloc;
Ron Yorston417622c2015-05-18 09:59:14 +02006631 /*
6632 * Example: v='a\bc'; echo ${v/\\b/_\\_\z_}
6633 * The result is a_\_z_c (not a\_\_z_c)!
6634 *
6635 * The search pattern and replace string treat backslashes differently!
6636 * RMESCAPE_SLASH causes preglob to work differently on the pattern
6637 * and string. It's only used on the first call.
6638 */
6639 preglob(str, IF_ASH_BASH_COMPAT(
6640 (subtype == VSREPLACE || subtype == VSREPLACEALL) && !repl ?
6641 RMESCAPE_SLASH :) 0);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006642
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006643#if ENABLE_ASH_BASH_COMPAT
Denys Vlasenko0b4980c2012-09-25 12:49:29 +02006644 workloc = expdest - (char *)stackblock();
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006645 if (subtype == VSREPLACE || subtype == VSREPLACEALL) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006646 char *idx, *end;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006647
Denis Vlasenkod6855d12008-09-27 14:03:25 +00006648 if (!repl) {
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02006649 repl = strchr(str, CTLESC);
6650 if (repl)
Ron Yorston417622c2015-05-18 09:59:14 +02006651 *repl++ = '\0';
6652 else
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006653 repl = nullstr;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006654 }
Ron Yorston417622c2015-05-18 09:59:14 +02006655 //bb_error_msg("str:'%s' repl:'%s'", str, repl);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006656
6657 /* If there's no pattern to match, return the expansion unmolested */
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006658 if (str[0] == '\0')
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006659 return NULL;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006660
6661 len = 0;
6662 idx = startp;
6663 end = str - 1;
6664 while (idx < end) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006665 try_to_match:
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006666 loc = scanright(idx, rmesc, rmescend, str, quotes, 1);
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006667 //bb_error_msg("scanright('%s'):'%s'", str, loc);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006668 if (!loc) {
6669 /* No match, advance */
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006670 char *restart_detect = stackblock();
6671 skip_matching:
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006672 STPUTC(*idx, expdest);
Denys Vlasenkocd716832009-11-28 22:14:02 +01006673 if (quotes && (unsigned char)*idx == CTLESC) {
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006674 idx++;
6675 len++;
6676 STPUTC(*idx, expdest);
6677 }
6678 if (stackblock() != restart_detect)
6679 goto restart;
6680 idx++;
6681 len++;
6682 rmesc++;
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006683 /* continue; - prone to quadratic behavior, smarter code: */
6684 if (idx >= end)
6685 break;
6686 if (str[0] == '*') {
6687 /* Pattern is "*foo". If "*foo" does not match "long_string",
6688 * it would never match "ong_string" etc, no point in trying.
6689 */
6690 goto skip_matching;
6691 }
6692 goto try_to_match;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006693 }
6694
6695 if (subtype == VSREPLACEALL) {
6696 while (idx < loc) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006697 if (quotes && (unsigned char)*idx == CTLESC)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006698 idx++;
6699 idx++;
6700 rmesc++;
6701 }
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006702 } else {
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006703 idx = loc;
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006704 }
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006705
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006706 //bb_error_msg("repl:'%s'", repl);
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006707 for (loc = (char*)repl; *loc; loc++) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006708 char *restart_detect = stackblock();
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006709 if (quotes && *loc == '\\') {
6710 STPUTC(CTLESC, expdest);
6711 len++;
6712 }
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006713 STPUTC(*loc, expdest);
6714 if (stackblock() != restart_detect)
6715 goto restart;
6716 len++;
6717 }
6718
6719 if (subtype == VSREPLACE) {
Denys Vlasenkof02c82f2010-08-06 19:14:47 +02006720 //bb_error_msg("tail:'%s', quotes:%x", idx, quotes);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006721 while (*idx) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006722 char *restart_detect = stackblock();
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006723 STPUTC(*idx, expdest);
6724 if (stackblock() != restart_detect)
6725 goto restart;
6726 len++;
6727 idx++;
6728 }
6729 break;
6730 }
6731 }
6732
6733 /* We've put the replaced text into a buffer at workloc, now
6734 * move it to the right place and adjust the stack.
6735 */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006736 STPUTC('\0', expdest);
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006737 startp = (char *)stackblock() + startloc;
6738 memmove(startp, (char *)stackblock() + workloc, len + 1);
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006739 //bb_error_msg("startp:'%s'", startp);
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006740 amount = expdest - (startp + len);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006741 STADJUST(-amount, expdest);
6742 return startp;
6743 }
6744#endif /* ENABLE_ASH_BASH_COMPAT */
6745
6746 subtype -= VSTRIMRIGHT;
6747#if DEBUG
6748 if (subtype < 0 || subtype > 7)
6749 abort();
6750#endif
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006751 /* zero = (subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX) */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006752 zero = subtype >> 1;
6753 /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */
6754 scan = (subtype & 1) ^ zero ? scanleft : scanright;
6755
6756 loc = scan(startp, rmesc, rmescend, str, quotes, zero);
6757 if (loc) {
6758 if (zero) {
6759 memmove(startp, loc, str - loc);
6760 loc = startp + (str - loc) - 1;
6761 }
6762 *loc = '\0';
6763 amount = loc - expdest;
6764 STADJUST(amount, expdest);
6765 }
6766 return loc;
6767}
6768
6769/*
6770 * Add the value of a specialized variable to the stack string.
Denys Vlasenko4d8873f2009-10-04 03:14:41 +02006771 * name parameter (examples):
6772 * ash -c 'echo $1' name:'1='
6773 * ash -c 'echo $qwe' name:'qwe='
6774 * ash -c 'echo $$' name:'$='
6775 * ash -c 'echo ${$}' name:'$='
6776 * ash -c 'echo ${$##q}' name:'$=q'
6777 * ash -c 'echo ${#$}' name:'$='
6778 * note: examples with bad shell syntax:
6779 * ash -c 'echo ${#$1}' name:'$=1'
6780 * ash -c 'echo ${#1#}' name:'1=#'
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006781 */
Denys Vlasenkoadf922e2009-10-08 14:35:37 +02006782static NOINLINE ssize_t
Denys Vlasenko0dd8e452016-10-01 21:02:06 +02006783varvalue(char *name, int varflags, int flags, struct strlist *var_str_list, int *quotedp)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006784{
Mike Frysinger98c52642009-04-02 10:02:37 +00006785 const char *p;
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006786 int num;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006787 int i;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006788 ssize_t len = 0;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006789 int sep;
Denys Vlasenko0dd8e452016-10-01 21:02:06 +02006790 int quoted = *quotedp;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006791 int subtype = varflags & VSTYPE;
6792 int discard = subtype == VSPLUS || subtype == VSLENGTH;
6793 int quotes = (discard ? 0 : (flags & QUOTES_ESC)) | QUOTES_KEEPNUL;
Denys Vlasenko0aaaa502016-10-02 02:46:56 +02006794 int syntax;
6795
6796 sep = (flags & EXP_FULL) << CHAR_BIT;
6797 syntax = quoted ? DQSYNTAX : BASESYNTAX;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006798
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006799 switch (*name) {
6800 case '$':
6801 num = rootpid;
6802 goto numvar;
6803 case '?':
6804 num = exitstatus;
6805 goto numvar;
6806 case '#':
6807 num = shellparam.nparam;
6808 goto numvar;
6809 case '!':
6810 num = backgndpid;
6811 if (num == 0)
6812 return -1;
6813 numvar:
6814 len = cvtnum(num);
Denys Vlasenko4d8873f2009-10-04 03:14:41 +02006815 goto check_1char_name;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006816 case '-':
Mike Frysinger98c52642009-04-02 10:02:37 +00006817 expdest = makestrspace(NOPTS, expdest);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006818 for (i = NOPTS - 1; i >= 0; i--) {
6819 if (optlist[i]) {
Mike Frysinger98c52642009-04-02 10:02:37 +00006820 USTPUTC(optletters(i), expdest);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006821 len++;
6822 }
6823 }
Denys Vlasenko4d8873f2009-10-04 03:14:41 +02006824 check_1char_name:
6825#if 0
6826 /* handles cases similar to ${#$1} */
6827 if (name[2] != '\0')
6828 raise_error_syntax("bad substitution");
6829#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006830 break;
Denys Vlasenko0aaaa502016-10-02 02:46:56 +02006831 case '@':
6832 if (quoted && sep)
6833 goto param;
6834 /* fall through */
6835 case '*': {
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006836 char **ap;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006837 char sepc;
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006838
Denys Vlasenko0aaaa502016-10-02 02:46:56 +02006839 if (quoted)
6840 sep = 0;
6841 sep |= ifsset() ? ifsval()[0] : ' ';
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006842 param:
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006843 sepc = sep;
Denys Vlasenko0dd8e452016-10-01 21:02:06 +02006844 *quotedp = !sepc;
6845 ap = shellparam.p;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006846 if (!ap)
6847 return -1;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006848 while ((p = *ap++) != NULL) {
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006849 len += strtodest(p, syntax, quotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006850
6851 if (*ap && sep) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006852 len++;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006853 memtodest(&sepc, 1, syntax, quotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006854 }
6855 }
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006856 break;
Denys Vlasenko0aaaa502016-10-02 02:46:56 +02006857 } /* case '*' */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006858 case '0':
6859 case '1':
6860 case '2':
6861 case '3':
6862 case '4':
6863 case '5':
6864 case '6':
6865 case '7':
6866 case '8':
6867 case '9':
Denys Vlasenkoa00329c2009-08-30 20:05:10 +02006868 num = atoi(name); /* number(name) fails on ${N#str} etc */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006869 if (num < 0 || num > shellparam.nparam)
6870 return -1;
6871 p = num ? shellparam.p[num - 1] : arg0;
6872 goto value;
6873 default:
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006874 /* NB: name has form "VAR=..." */
6875
6876 /* "A=a B=$A" case: var_str_list is a list of "A=a" strings
6877 * which should be considered before we check variables. */
6878 if (var_str_list) {
6879 unsigned name_len = (strchrnul(name, '=') - name) + 1;
6880 p = NULL;
6881 do {
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00006882 char *str, *eq;
6883 str = var_str_list->text;
6884 eq = strchr(str, '=');
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006885 if (!eq) /* stop at first non-assignment */
6886 break;
6887 eq++;
Denis Vlasenko6b06cb82008-05-15 21:30:45 +00006888 if (name_len == (unsigned)(eq - str)
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006889 && strncmp(str, name, name_len) == 0
6890 ) {
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006891 p = eq;
6892 /* goto value; - WRONG! */
6893 /* think "A=1 A=2 B=$A" */
6894 }
6895 var_str_list = var_str_list->next;
6896 } while (var_str_list);
6897 if (p)
6898 goto value;
6899 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006900 p = lookupvar(name);
6901 value:
6902 if (!p)
6903 return -1;
6904
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006905 len = strtodest(p, syntax, quotes);
Denys Vlasenkoc76236f2014-12-29 00:04:18 +01006906#if ENABLE_UNICODE_SUPPORT
6907 if (subtype == VSLENGTH && len > 0) {
6908 reinit_unicode_for_ash();
6909 if (unicode_status == UNICODE_ON) {
Ron Yorston3e3bfb82016-03-18 11:29:19 +00006910 STADJUST(-len, expdest);
6911 discard = 0;
Denys Vlasenkoc76236f2014-12-29 00:04:18 +01006912 len = unicode_strlen(p);
6913 }
6914 }
6915#endif
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006916 break;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006917 }
6918
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006919 if (discard)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006920 STADJUST(-len, expdest);
6921 return len;
6922}
6923
6924/*
6925 * Expand a variable, and return a pointer to the next character in the
6926 * input string.
6927 */
6928static char *
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02006929evalvar(char *p, int flag, struct strlist *var_str_list)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006930{
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006931 char varflags;
6932 char subtype;
Ron Yorston549deab2015-05-18 09:57:51 +02006933 int quoted;
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006934 char easy;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006935 char *var;
6936 int patloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006937 int startloc;
6938 ssize_t varlen;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006939
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006940 varflags = (unsigned char) *p++;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006941 subtype = varflags & VSTYPE;
Denys Vlasenko88e15702016-10-26 01:55:56 +02006942
6943 if (!subtype)
6944 raise_error_syntax("bad substitution");
6945
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02006946 quoted = flag & EXP_QUOTED;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006947 var = p;
6948 easy = (!quoted || (*var == '@' && shellparam.nparam));
6949 startloc = expdest - (char *)stackblock();
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02006950 p = strchr(p, '=') + 1; //TODO: use var_end(p)?
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006951
6952 again:
Denys Vlasenko0dd8e452016-10-01 21:02:06 +02006953 varlen = varvalue(var, varflags, flag, var_str_list, &quoted);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006954 if (varflags & VSNUL)
6955 varlen--;
6956
6957 if (subtype == VSPLUS) {
6958 varlen = -1 - varlen;
6959 goto vsplus;
6960 }
6961
6962 if (subtype == VSMINUS) {
6963 vsplus:
6964 if (varlen < 0) {
6965 argstr(
Denys Vlasenko6040fe82010-09-12 15:03:16 +02006966 p,
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02006967 flag | EXP_TILDE | EXP_WORD,
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006968 var_str_list
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006969 );
6970 goto end;
6971 }
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02006972 goto record;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006973 }
6974
6975 if (subtype == VSASSIGN || subtype == VSQUESTION) {
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02006976 if (varlen >= 0)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006977 goto record;
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02006978
6979 subevalvar(p, var, 0, subtype, startloc, varflags,
6980 flag & ~QUOTES_ESC, var_str_list);
6981 varflags &= ~VSNUL;
6982 /*
6983 * Remove any recorded regions beyond
6984 * start of variable
6985 */
6986 removerecordregions(startloc);
6987 goto again;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006988 }
6989
6990 if (varlen < 0 && uflag)
6991 varunset(p, var, 0, 0);
6992
6993 if (subtype == VSLENGTH) {
Denys Vlasenkoc76236f2014-12-29 00:04:18 +01006994 cvtnum(varlen > 0 ? varlen : 0);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006995 goto record;
6996 }
6997
6998 if (subtype == VSNORMAL) {
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02006999 record:
7000 if (!easy)
7001 goto end;
Denys Vlasenko0dd8e452016-10-01 21:02:06 +02007002 recordregion(startloc, expdest - (char *)stackblock(), quoted);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007003 goto end;
7004 }
7005
7006#if DEBUG
7007 switch (subtype) {
7008 case VSTRIMLEFT:
7009 case VSTRIMLEFTMAX:
7010 case VSTRIMRIGHT:
7011 case VSTRIMRIGHTMAX:
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007012#if ENABLE_ASH_BASH_COMPAT
7013 case VSSUBSTR:
7014 case VSREPLACE:
7015 case VSREPLACEALL:
7016#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007017 break;
7018 default:
7019 abort();
7020 }
7021#endif
7022
7023 if (varlen >= 0) {
7024 /*
7025 * Terminate the string and start recording the pattern
7026 * right after it
7027 */
7028 STPUTC('\0', expdest);
7029 patloc = expdest - (char *)stackblock();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02007030 if (NULL == subevalvar(p, /* varname: */ NULL, patloc, subtype,
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007031 startloc, varflags, flag, var_str_list)) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007032 int amount = expdest - (
7033 (char *)stackblock() + patloc - 1
7034 );
7035 STADJUST(-amount, expdest);
7036 }
7037 /* Remove any recorded regions beyond start of variable */
7038 removerecordregions(startloc);
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007039 goto record;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007040 }
7041
7042 end:
7043 if (subtype != VSNORMAL) { /* skip to end of alternative */
7044 int nesting = 1;
7045 for (;;) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01007046 unsigned char c = *p++;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007047 if (c == CTLESC)
7048 p++;
Ron Yorston549deab2015-05-18 09:57:51 +02007049 else if (c == CTLBACKQ) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007050 if (varlen >= 0)
7051 argbackq = argbackq->next;
7052 } else if (c == CTLVAR) {
7053 if ((*p++ & VSTYPE) != VSNORMAL)
7054 nesting++;
7055 } else if (c == CTLENDVAR) {
7056 if (--nesting == 0)
7057 break;
7058 }
7059 }
7060 }
7061 return p;
7062}
7063
7064/*
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007065 * Add a file name to the list.
7066 */
7067static void
7068addfname(const char *name)
7069{
7070 struct strlist *sp;
7071
Denis Vlasenko597906c2008-02-20 16:38:54 +00007072 sp = stzalloc(sizeof(*sp));
Denys Vlasenko8e2bc472016-09-28 23:02:57 +02007073 sp->text = sstrdup(name);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007074 *exparg.lastp = sp;
7075 exparg.lastp = &sp->next;
7076}
7077
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007078/* If we want to use glob() from libc... */
Denys Vlasenko514b51d2016-10-01 14:33:08 +02007079#if !ENABLE_ASH_INTERNAL_GLOB
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007080
7081/* Add the result of glob() to the list */
7082static void
7083addglob(const glob_t *pglob)
7084{
7085 char **p = pglob->gl_pathv;
7086
7087 do {
7088 addfname(*p);
7089 } while (*++p);
7090}
7091static void
7092expandmeta(struct strlist *str /*, int flag*/)
7093{
7094 /* TODO - EXP_REDIR */
7095
7096 while (str) {
7097 char *p;
7098 glob_t pglob;
7099 int i;
7100
7101 if (fflag)
7102 goto nometa;
Denys Vlasenkod4f3db92016-10-30 18:41:01 +01007103
7104 /* Avoid glob() (and thus, stat() et al) for words like "echo" */
7105 p = str->text;
7106 while (*p) {
7107 if (*p == '*')
7108 goto need_glob;
7109 if (*p == '?')
7110 goto need_glob;
7111 if (*p == '[')
7112 goto need_glob;
7113 p++;
7114 }
7115 goto nometa;
7116
7117 need_glob:
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007118 INT_OFF;
7119 p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP);
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007120// GLOB_NOMAGIC (GNU): if no *?[ chars in pattern, return it even if no match
7121// GLOB_NOCHECK: if no match, return unchanged pattern (sans \* escapes?)
7122//
7123// glibc 2.24.90 glob(GLOB_NOMAGIC) does not remove backslashes used for escaping:
7124// if you pass it "file\?", it returns "file\?", not "file?", if no match.
7125// Which means you need to unescape the string, right? Not so fast:
7126// if there _is_ a file named "file\?" (with backslash), it is returned
7127// as "file\?" too (whichever pattern you used to find it, say, "file*").
7128// You DONT KNOW by looking at the result whether you need to unescape it.
7129//
7130// Worse, globbing of "file\?" in a directory with two files, "file?" and "file\?",
7131// returns "file\?" - which is WRONG: "file\?" pattern matches "file?" file.
7132// Without GLOB_NOMAGIC, this works correctly ("file?" is returned as a match).
7133// With GLOB_NOMAGIC | GLOB_NOCHECK, this also works correctly.
7134// i = glob(p, GLOB_NOMAGIC | GLOB_NOCHECK, NULL, &pglob);
7135// i = glob(p, GLOB_NOMAGIC, NULL, &pglob);
7136 i = glob(p, 0, NULL, &pglob);
7137 //bb_error_msg("glob('%s'):%d '%s'...", p, i, pglob.gl_pathv ? pglob.gl_pathv[0] : "-");
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007138 if (p != str->text)
7139 free(p);
7140 switch (i) {
7141 case 0:
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007142#if 0 // glibc 2.24.90 bug? Patterns like "*/file", when match, don't set GLOB_MAGCHAR
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007143 /* GLOB_MAGCHAR is set if *?[ chars were seen (GNU) */
7144 if (!(pglob.gl_flags & GLOB_MAGCHAR))
7145 goto nometa2;
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007146#endif
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007147 addglob(&pglob);
7148 globfree(&pglob);
7149 INT_ON;
7150 break;
7151 case GLOB_NOMATCH:
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007152 //nometa2:
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007153 globfree(&pglob);
7154 INT_ON;
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007155 nometa:
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007156 *exparg.lastp = str;
7157 rmescapes(str->text, 0);
7158 exparg.lastp = &str->next;
7159 break;
7160 default: /* GLOB_NOSPACE */
7161 globfree(&pglob);
7162 INT_ON;
7163 ash_msg_and_raise_error(bb_msg_memory_exhausted);
7164 }
7165 str = str->next;
7166 }
7167}
7168
7169#else
Denys Vlasenko514b51d2016-10-01 14:33:08 +02007170/* ENABLE_ASH_INTERNAL_GLOB: Homegrown globbing code. (dash also has both, uses homegrown one.) */
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007171
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007172/*
7173 * Do metacharacter (i.e. *, ?, [...]) expansion.
7174 */
7175static void
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007176expmeta(char *expdir, char *enddir, char *name)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007177{
7178 char *p;
7179 const char *cp;
7180 char *start;
7181 char *endname;
7182 int metaflag;
7183 struct stat statb;
7184 DIR *dirp;
7185 struct dirent *dp;
7186 int atend;
7187 int matchdot;
Ron Yorstonca25af92015-09-04 10:32:41 +01007188 int esc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007189
7190 metaflag = 0;
7191 start = name;
Ron Yorstonca25af92015-09-04 10:32:41 +01007192 for (p = name; esc = 0, *p; p += esc + 1) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007193 if (*p == '*' || *p == '?')
7194 metaflag = 1;
7195 else if (*p == '[') {
7196 char *q = p + 1;
7197 if (*q == '!')
7198 q++;
7199 for (;;) {
7200 if (*q == '\\')
7201 q++;
7202 if (*q == '/' || *q == '\0')
7203 break;
7204 if (*++q == ']') {
7205 metaflag = 1;
7206 break;
7207 }
7208 }
Ron Yorstonca25af92015-09-04 10:32:41 +01007209 } else {
7210 if (*p == '\\')
7211 esc++;
7212 if (p[esc] == '/') {
7213 if (metaflag)
7214 break;
7215 start = p + esc + 1;
7216 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007217 }
7218 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007219 if (metaflag == 0) { /* we've reached the end of the file name */
7220 if (enddir != expdir)
7221 metaflag++;
7222 p = name;
7223 do {
7224 if (*p == '\\')
7225 p++;
7226 *enddir++ = *p;
7227 } while (*p++);
7228 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
7229 addfname(expdir);
7230 return;
7231 }
7232 endname = p;
7233 if (name < start) {
7234 p = name;
7235 do {
7236 if (*p == '\\')
7237 p++;
7238 *enddir++ = *p++;
7239 } while (p < start);
7240 }
7241 if (enddir == expdir) {
7242 cp = ".";
7243 } else if (enddir == expdir + 1 && *expdir == '/') {
7244 cp = "/";
7245 } else {
7246 cp = expdir;
7247 enddir[-1] = '\0';
7248 }
7249 dirp = opendir(cp);
7250 if (dirp == NULL)
7251 return;
7252 if (enddir != expdir)
7253 enddir[-1] = '/';
7254 if (*endname == 0) {
7255 atend = 1;
7256 } else {
7257 atend = 0;
Ron Yorstonca25af92015-09-04 10:32:41 +01007258 *endname = '\0';
7259 endname += esc + 1;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007260 }
7261 matchdot = 0;
7262 p = start;
7263 if (*p == '\\')
7264 p++;
7265 if (*p == '.')
7266 matchdot++;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02007267 while (!pending_int && (dp = readdir(dirp)) != NULL) {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00007268 if (dp->d_name[0] == '.' && !matchdot)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007269 continue;
7270 if (pmatch(start, dp->d_name)) {
7271 if (atend) {
7272 strcpy(enddir, dp->d_name);
7273 addfname(expdir);
7274 } else {
7275 for (p = enddir, cp = dp->d_name; (*p++ = *cp++) != '\0';)
7276 continue;
7277 p[-1] = '/';
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007278 expmeta(expdir, p, endname);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007279 }
7280 }
7281 }
7282 closedir(dirp);
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00007283 if (!atend)
Ron Yorstonca25af92015-09-04 10:32:41 +01007284 endname[-esc - 1] = esc ? '\\' : '/';
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007285}
7286
7287static struct strlist *
7288msort(struct strlist *list, int len)
7289{
7290 struct strlist *p, *q = NULL;
7291 struct strlist **lpp;
7292 int half;
7293 int n;
7294
7295 if (len <= 1)
7296 return list;
7297 half = len >> 1;
7298 p = list;
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +00007299 for (n = half; --n >= 0;) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007300 q = p;
7301 p = p->next;
7302 }
7303 q->next = NULL; /* terminate first half of list */
7304 q = msort(list, half); /* sort first half of list */
7305 p = msort(p, len - half); /* sort second half */
7306 lpp = &list;
7307 for (;;) {
7308#if ENABLE_LOCALE_SUPPORT
7309 if (strcoll(p->text, q->text) < 0)
7310#else
7311 if (strcmp(p->text, q->text) < 0)
7312#endif
7313 {
7314 *lpp = p;
7315 lpp = &p->next;
7316 p = *lpp;
7317 if (p == NULL) {
7318 *lpp = q;
7319 break;
7320 }
7321 } else {
7322 *lpp = q;
7323 lpp = &q->next;
7324 q = *lpp;
7325 if (q == NULL) {
7326 *lpp = p;
7327 break;
7328 }
7329 }
7330 }
7331 return list;
7332}
7333
7334/*
7335 * Sort the results of file name expansion. It calculates the number of
7336 * strings to sort and then calls msort (short for merge sort) to do the
7337 * work.
7338 */
7339static struct strlist *
7340expsort(struct strlist *str)
7341{
7342 int len;
7343 struct strlist *sp;
7344
7345 len = 0;
7346 for (sp = str; sp; sp = sp->next)
7347 len++;
7348 return msort(str, len);
7349}
7350
7351static void
Denis Vlasenko68404f12008-03-17 09:00:54 +00007352expandmeta(struct strlist *str /*, int flag*/)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007353{
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00007354 static const char metachars[] ALIGN1 = {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007355 '*', '?', '[', 0
7356 };
7357 /* TODO - EXP_REDIR */
7358
7359 while (str) {
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007360 char *expdir;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007361 struct strlist **savelastp;
7362 struct strlist *sp;
7363 char *p;
7364
7365 if (fflag)
7366 goto nometa;
7367 if (!strpbrk(str->text, metachars))
7368 goto nometa;
7369 savelastp = exparg.lastp;
7370
7371 INT_OFF;
Ron Yorston549deab2015-05-18 09:57:51 +02007372 p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007373 {
7374 int i = strlen(str->text);
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007375//BUGGY estimation of how long expanded name can be
7376 expdir = ckmalloc(i < 2048 ? 2048 : i+1);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007377 }
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007378 expmeta(expdir, expdir, p);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007379 free(expdir);
7380 if (p != str->text)
7381 free(p);
7382 INT_ON;
7383 if (exparg.lastp == savelastp) {
7384 /*
7385 * no matches
7386 */
7387 nometa:
7388 *exparg.lastp = str;
Denys Vlasenkob6c84342009-08-29 20:23:20 +02007389 rmescapes(str->text, 0);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007390 exparg.lastp = &str->next;
7391 } else {
7392 *exparg.lastp = NULL;
7393 *savelastp = sp = expsort(*savelastp);
7394 while (sp->next != NULL)
7395 sp = sp->next;
7396 exparg.lastp = &sp->next;
7397 }
7398 str = str->next;
7399 }
7400}
Denys Vlasenko514b51d2016-10-01 14:33:08 +02007401#endif /* ENABLE_ASH_INTERNAL_GLOB */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007402
7403/*
7404 * Perform variable substitution and command substitution on an argument,
7405 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
7406 * perform splitting and file name expansion. When arglist is NULL, perform
7407 * here document expansion.
7408 */
7409static void
7410expandarg(union node *arg, struct arglist *arglist, int flag)
7411{
7412 struct strlist *sp;
7413 char *p;
7414
7415 argbackq = arg->narg.backquote;
7416 STARTSTACKSTR(expdest);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02007417 TRACE(("expandarg: argstr('%s',flags:%x)\n", arg->narg.text, flag));
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00007418 argstr(arg->narg.text, flag,
7419 /* var_str_list: */ arglist ? arglist->list : NULL);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007420 p = _STPUTC('\0', expdest);
7421 expdest = p - 1;
7422 if (arglist == NULL) {
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02007423 /* here document expanded */
7424 goto out;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007425 }
7426 p = grabstackstr(p);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02007427 TRACE(("expandarg: p:'%s'\n", p));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007428 exparg.lastp = &exparg.list;
7429 /*
7430 * TODO - EXP_REDIR
7431 */
7432 if (flag & EXP_FULL) {
7433 ifsbreakup(p, &exparg);
7434 *exparg.lastp = NULL;
7435 exparg.lastp = &exparg.list;
Denis Vlasenko68404f12008-03-17 09:00:54 +00007436 expandmeta(exparg.list /*, flag*/);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007437 } else {
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02007438 if (flag & EXP_REDIR) { /*XXX - for now, just remove escapes */
Denys Vlasenkob6c84342009-08-29 20:23:20 +02007439 rmescapes(p, 0);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02007440 TRACE(("expandarg: rmescapes:'%s'\n", p));
7441 }
Denis Vlasenko597906c2008-02-20 16:38:54 +00007442 sp = stzalloc(sizeof(*sp));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007443 sp->text = p;
7444 *exparg.lastp = sp;
7445 exparg.lastp = &sp->next;
7446 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007447 *exparg.lastp = NULL;
7448 if (exparg.list) {
7449 *arglist->lastp = exparg.list;
7450 arglist->lastp = exparg.lastp;
7451 }
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02007452
7453 out:
7454 ifsfree();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007455}
7456
7457/*
7458 * Expand shell variables and backquotes inside a here document.
7459 */
7460static void
7461expandhere(union node *arg, int fd)
7462{
Ron Yorston549deab2015-05-18 09:57:51 +02007463 expandarg(arg, (struct arglist *)NULL, EXP_QUOTED);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007464 full_write(fd, stackblock(), expdest - (char *)stackblock());
7465}
7466
7467/*
7468 * Returns true if the pattern matches the string.
7469 */
7470static int
7471patmatch(char *pattern, const char *string)
7472{
Ron Yorston549deab2015-05-18 09:57:51 +02007473 return pmatch(preglob(pattern, 0), string);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007474}
7475
7476/*
7477 * See if a pattern matches in a case statement.
7478 */
7479static int
7480casematch(union node *pattern, char *val)
7481{
7482 struct stackmark smark;
7483 int result;
7484
7485 setstackmark(&smark);
7486 argbackq = pattern->narg.backquote;
7487 STARTSTACKSTR(expdest);
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00007488 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE,
7489 /* var_str_list: */ NULL);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007490 STACKSTRNUL(expdest);
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02007491 ifsfree();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007492 result = patmatch(stackblock(), val);
7493 popstackmark(&smark);
7494 return result;
7495}
7496
7497
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007498/* ============ find_command */
7499
7500struct builtincmd {
7501 const char *name;
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02007502 int (*builtin)(int, char **) FAST_FUNC;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007503 /* unsigned flags; */
7504};
7505#define IS_BUILTIN_SPECIAL(b) ((b)->name[0] & 1)
Denis Vlasenkoe26b2782008-02-12 07:40:29 +00007506/* "regular" builtins always take precedence over commands,
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007507 * regardless of PATH=....%builtin... position */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007508#define IS_BUILTIN_REGULAR(b) ((b)->name[0] & 2)
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007509#define IS_BUILTIN_ASSIGN(b) ((b)->name[0] & 4)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007510
7511struct cmdentry {
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00007512 smallint cmdtype; /* CMDxxx */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007513 union param {
7514 int index;
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00007515 /* index >= 0 for commands without path (slashes) */
7516 /* (TODO: what exactly does the value mean? PATH position?) */
7517 /* index == -1 for commands with slashes */
7518 /* index == (-2 - applet_no) for NOFORK applets */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007519 const struct builtincmd *cmd;
7520 struct funcnode *func;
7521 } u;
7522};
7523/* values of cmdtype */
7524#define CMDUNKNOWN -1 /* no entry in table for command */
7525#define CMDNORMAL 0 /* command is an executable program */
7526#define CMDFUNCTION 1 /* command is a shell function */
7527#define CMDBUILTIN 2 /* command is a shell builtin */
7528
7529/* action to find_command() */
7530#define DO_ERR 0x01 /* prints errors */
7531#define DO_ABS 0x02 /* checks absolute paths */
7532#define DO_NOFUNC 0x04 /* don't return shell functions, for command */
7533#define DO_ALTPATH 0x08 /* using alternate path */
7534#define DO_ALTBLTIN 0x20 /* %builtin in alt. path */
7535
7536static void find_command(char *, struct cmdentry *, int, const char *);
7537
7538
7539/* ============ Hashing commands */
7540
7541/*
7542 * When commands are first encountered, they are entered in a hash table.
7543 * This ensures that a full path search will not have to be done for them
7544 * on each invocation.
7545 *
7546 * We should investigate converting to a linear search, even though that
7547 * would make the command name "hash" a misnomer.
7548 */
7549
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007550struct tblentry {
7551 struct tblentry *next; /* next entry in hash chain */
7552 union param param; /* definition of builtin function */
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00007553 smallint cmdtype; /* CMDxxx */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007554 char rehash; /* if set, cd done since entry created */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00007555 char cmdname[1]; /* name of command */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007556};
7557
Denis Vlasenko01631112007-12-16 17:20:38 +00007558static struct tblentry **cmdtable;
7559#define INIT_G_cmdtable() do { \
7560 cmdtable = xzalloc(CMDTABLESIZE * sizeof(cmdtable[0])); \
7561} while (0)
7562
7563static int builtinloc = -1; /* index in path of %builtin, or -1 */
7564
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007565
7566static void
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00007567tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) char *cmd, char **argv, char **envp)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007568{
Denis Vlasenko80d14be2007-04-10 23:03:30 +00007569#if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007570 if (applet_no >= 0) {
Denis Vlasenkob7304742008-10-20 08:15:51 +00007571 if (APPLET_IS_NOEXEC(applet_no)) {
Denys Vlasenko7df28bb2010-06-18 14:23:47 +02007572 clearenv();
Denis Vlasenkob7304742008-10-20 08:15:51 +00007573 while (*envp)
7574 putenv(*envp++);
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007575 run_applet_no_and_exit(applet_no, argv);
Denis Vlasenkob7304742008-10-20 08:15:51 +00007576 }
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007577 /* re-exec ourselves with the new arguments */
7578 execve(bb_busybox_exec_path, argv, envp);
7579 /* If they called chroot or otherwise made the binary no longer
7580 * executable, fall through */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007581 }
7582#endif
7583
7584 repeat:
7585#ifdef SYSV
7586 do {
7587 execve(cmd, argv, envp);
7588 } while (errno == EINTR);
7589#else
7590 execve(cmd, argv, envp);
7591#endif
Denys Vlasenko65a8b852016-10-26 22:29:11 +02007592 if (cmd != (char*) bb_busybox_exec_path && errno == ENOEXEC) {
Denys Vlasenkoaefe1c22011-03-07 12:02:40 +01007593 /* Run "cmd" as a shell script:
7594 * http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html
7595 * "If the execve() function fails with ENOEXEC, the shell
7596 * shall execute a command equivalent to having a shell invoked
7597 * with the command name as its first operand,
7598 * with any remaining arguments passed to the new shell"
7599 *
7600 * That is, do not use $SHELL, user's shell, or /bin/sh;
7601 * just call ourselves.
Denys Vlasenko2bef5262011-12-16 00:25:17 +01007602 *
7603 * Note that bash reads ~80 chars of the file, and if it sees
7604 * a zero byte before it sees newline, it doesn't try to
7605 * interpret it, but fails with "cannot execute binary file"
Denys Vlasenkocda6ea92011-12-16 00:44:36 +01007606 * message and exit code 126. For one, this prevents attempts
7607 * to interpret foreign ELF binaries as shell scripts.
Denys Vlasenkoaefe1c22011-03-07 12:02:40 +01007608 */
Denys Vlasenko65a8b852016-10-26 22:29:11 +02007609 argv[0] = cmd;
Denys Vlasenkoaefe1c22011-03-07 12:02:40 +01007610 cmd = (char*) bb_busybox_exec_path;
Denys Vlasenko65a8b852016-10-26 22:29:11 +02007611 /* NB: this is only possible because all callers of shellexec()
7612 * ensure that the argv[-1] slot exists!
7613 */
7614 argv--;
7615 argv[0] = (char*) "ash";
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007616 goto repeat;
7617 }
7618}
7619
7620/*
7621 * Exec a program. Never returns. If you change this routine, you may
7622 * have to change the find_command routine as well.
Denys Vlasenko65a8b852016-10-26 22:29:11 +02007623 * argv[-1] must exist and be writable! See tryexec() for why.
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007624 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00007625static void shellexec(char **, const char *, int) NORETURN;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007626static void
7627shellexec(char **argv, const char *path, int idx)
7628{
7629 char *cmdname;
7630 int e;
7631 char **envp;
7632 int exerrno;
Denys Vlasenko83f103b2011-12-20 06:10:35 +01007633 int applet_no = -1; /* used only by FEATURE_SH_STANDALONE */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007634
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +02007635 envp = listvars(VEXPORT, VUNSET, /*end:*/ NULL);
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007636 if (strchr(argv[0], '/') != NULL
Denis Vlasenko80d14be2007-04-10 23:03:30 +00007637#if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007638 || (applet_no = find_applet_by_name(argv[0])) >= 0
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007639#endif
7640 ) {
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00007641 tryexec(IF_FEATURE_SH_STANDALONE(applet_no,) argv[0], argv, envp);
Denys Vlasenko83f103b2011-12-20 06:10:35 +01007642 if (applet_no >= 0) {
7643 /* We tried execing ourself, but it didn't work.
7644 * Maybe /proc/self/exe doesn't exist?
7645 * Try $PATH search.
7646 */
7647 goto try_PATH;
7648 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007649 e = errno;
7650 } else {
Denys Vlasenko83f103b2011-12-20 06:10:35 +01007651 try_PATH:
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007652 e = ENOENT;
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02007653 while ((cmdname = path_advance(&path, argv[0])) != NULL) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007654 if (--idx < 0 && pathopt == NULL) {
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00007655 tryexec(IF_FEATURE_SH_STANDALONE(-1,) cmdname, argv, envp);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007656 if (errno != ENOENT && errno != ENOTDIR)
7657 e = errno;
7658 }
7659 stunalloc(cmdname);
7660 }
7661 }
7662
7663 /* Map to POSIX errors */
7664 switch (e) {
7665 case EACCES:
7666 exerrno = 126;
7667 break;
7668 case ENOENT:
7669 exerrno = 127;
7670 break;
7671 default:
7672 exerrno = 2;
7673 break;
7674 }
7675 exitstatus = exerrno;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02007676 TRACE(("shellexec failed for %s, errno %d, suppress_int %d\n",
7677 argv[0], e, suppress_int));
Denys Vlasenko061a0902016-10-25 17:24:25 +02007678 ash_msg_and_raise(EXEXIT, "%s: %s", argv[0], errmsg(e, "not found"));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007679 /* NOTREACHED */
7680}
7681
7682static void
7683printentry(struct tblentry *cmdp)
7684{
7685 int idx;
7686 const char *path;
7687 char *name;
7688
7689 idx = cmdp->param.index;
7690 path = pathval();
7691 do {
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02007692 name = path_advance(&path, cmdp->cmdname);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007693 stunalloc(name);
7694 } while (--idx >= 0);
7695 out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr));
7696}
7697
7698/*
7699 * Clear out command entries. The argument specifies the first entry in
7700 * PATH which has changed.
7701 */
7702static void
7703clearcmdentry(int firstchange)
7704{
7705 struct tblentry **tblp;
7706 struct tblentry **pp;
7707 struct tblentry *cmdp;
7708
7709 INT_OFF;
7710 for (tblp = cmdtable; tblp < &cmdtable[CMDTABLESIZE]; tblp++) {
7711 pp = tblp;
7712 while ((cmdp = *pp) != NULL) {
7713 if ((cmdp->cmdtype == CMDNORMAL &&
7714 cmdp->param.index >= firstchange)
7715 || (cmdp->cmdtype == CMDBUILTIN &&
7716 builtinloc >= firstchange)
7717 ) {
7718 *pp = cmdp->next;
7719 free(cmdp);
7720 } else {
7721 pp = &cmdp->next;
7722 }
7723 }
7724 }
7725 INT_ON;
7726}
7727
7728/*
7729 * Locate a command in the command hash table. If "add" is nonzero,
7730 * add the command to the table if it is not already present. The
7731 * variable "lastcmdentry" is set to point to the address of the link
7732 * pointing to the entry, so that delete_cmd_entry can delete the
7733 * entry.
7734 *
7735 * Interrupts must be off if called with add != 0.
7736 */
7737static struct tblentry **lastcmdentry;
7738
7739static struct tblentry *
7740cmdlookup(const char *name, int add)
7741{
7742 unsigned int hashval;
7743 const char *p;
7744 struct tblentry *cmdp;
7745 struct tblentry **pp;
7746
7747 p = name;
7748 hashval = (unsigned char)*p << 4;
7749 while (*p)
7750 hashval += (unsigned char)*p++;
7751 hashval &= 0x7FFF;
7752 pp = &cmdtable[hashval % CMDTABLESIZE];
7753 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
7754 if (strcmp(cmdp->cmdname, name) == 0)
7755 break;
7756 pp = &cmdp->next;
7757 }
7758 if (add && cmdp == NULL) {
Denis Vlasenkob07a4962008-06-22 13:16:23 +00007759 cmdp = *pp = ckzalloc(sizeof(struct tblentry)
7760 + strlen(name)
7761 /* + 1 - already done because
7762 * tblentry::cmdname is char[1] */);
Denis Vlasenko597906c2008-02-20 16:38:54 +00007763 /*cmdp->next = NULL; - ckzalloc did it */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007764 cmdp->cmdtype = CMDUNKNOWN;
7765 strcpy(cmdp->cmdname, name);
7766 }
7767 lastcmdentry = pp;
7768 return cmdp;
7769}
7770
7771/*
7772 * Delete the command entry returned on the last lookup.
7773 */
7774static void
7775delete_cmd_entry(void)
7776{
7777 struct tblentry *cmdp;
7778
7779 INT_OFF;
7780 cmdp = *lastcmdentry;
7781 *lastcmdentry = cmdp->next;
7782 if (cmdp->cmdtype == CMDFUNCTION)
7783 freefunc(cmdp->param.func);
7784 free(cmdp);
7785 INT_ON;
7786}
7787
7788/*
7789 * Add a new command entry, replacing any existing command entry for
7790 * the same name - except special builtins.
7791 */
7792static void
7793addcmdentry(char *name, struct cmdentry *entry)
7794{
7795 struct tblentry *cmdp;
7796
7797 cmdp = cmdlookup(name, 1);
7798 if (cmdp->cmdtype == CMDFUNCTION) {
7799 freefunc(cmdp->param.func);
7800 }
7801 cmdp->cmdtype = entry->cmdtype;
7802 cmdp->param = entry->u;
7803 cmdp->rehash = 0;
7804}
7805
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02007806static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00007807hashcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007808{
7809 struct tblentry **pp;
7810 struct tblentry *cmdp;
7811 int c;
7812 struct cmdentry entry;
7813 char *name;
7814
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007815 if (nextopt("r") != '\0') {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007816 clearcmdentry(0);
7817 return 0;
7818 }
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007819
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007820 if (*argptr == NULL) {
7821 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
7822 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
7823 if (cmdp->cmdtype == CMDNORMAL)
7824 printentry(cmdp);
7825 }
7826 }
7827 return 0;
7828 }
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007829
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007830 c = 0;
7831 while ((name = *argptr) != NULL) {
7832 cmdp = cmdlookup(name, 0);
7833 if (cmdp != NULL
7834 && (cmdp->cmdtype == CMDNORMAL
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007835 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))
7836 ) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007837 delete_cmd_entry();
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007838 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007839 find_command(name, &entry, DO_ERR, pathval());
7840 if (entry.cmdtype == CMDUNKNOWN)
7841 c = 1;
7842 argptr++;
7843 }
7844 return c;
7845}
7846
7847/*
7848 * Called when a cd is done. Marks all commands so the next time they
7849 * are executed they will be rehashed.
7850 */
7851static void
7852hashcd(void)
7853{
7854 struct tblentry **pp;
7855 struct tblentry *cmdp;
7856
7857 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
7858 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007859 if (cmdp->cmdtype == CMDNORMAL
7860 || (cmdp->cmdtype == CMDBUILTIN
Denys Vlasenkoe4dcba12010-10-28 18:57:19 +02007861 && !IS_BUILTIN_REGULAR(cmdp->param.cmd)
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007862 && builtinloc > 0)
7863 ) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007864 cmdp->rehash = 1;
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007865 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007866 }
7867 }
7868}
7869
7870/*
7871 * Fix command hash table when PATH changed.
7872 * Called before PATH is changed. The argument is the new value of PATH;
7873 * pathval() still returns the old value at this point.
7874 * Called with interrupts off.
7875 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02007876static void FAST_FUNC
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007877changepath(const char *new)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007878{
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007879 const char *old;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007880 int firstchange;
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007881 int idx;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007882 int idx_bltin;
7883
7884 old = pathval();
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007885 firstchange = 9999; /* assume no change */
7886 idx = 0;
7887 idx_bltin = -1;
7888 for (;;) {
7889 if (*old != *new) {
7890 firstchange = idx;
7891 if ((*old == '\0' && *new == ':')
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +02007892 || (*old == ':' && *new == '\0')
7893 ) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007894 firstchange++;
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +02007895 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007896 old = new; /* ignore subsequent differences */
7897 }
7898 if (*new == '\0')
7899 break;
7900 if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin"))
7901 idx_bltin = idx;
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007902 if (*new == ':')
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007903 idx++;
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +02007904 new++;
7905 old++;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007906 }
7907 if (builtinloc < 0 && idx_bltin >= 0)
7908 builtinloc = idx_bltin; /* zap builtins */
7909 if (builtinloc >= 0 && idx_bltin < 0)
7910 firstchange = 0;
7911 clearcmdentry(firstchange);
7912 builtinloc = idx_bltin;
7913}
Ron Yorston95ebcf72015-11-03 09:42:23 +00007914enum {
7915 TEOF,
7916 TNL,
7917 TREDIR,
7918 TWORD,
7919 TSEMI,
7920 TBACKGND,
7921 TAND,
7922 TOR,
7923 TPIPE,
7924 TLP,
7925 TRP,
7926 TENDCASE,
7927 TENDBQUOTE,
7928 TNOT,
7929 TCASE,
7930 TDO,
7931 TDONE,
7932 TELIF,
7933 TELSE,
7934 TESAC,
7935 TFI,
7936 TFOR,
7937#if ENABLE_ASH_BASH_COMPAT
7938 TFUNCTION,
7939#endif
7940 TIF,
7941 TIN,
7942 TTHEN,
7943 TUNTIL,
7944 TWHILE,
7945 TBEGIN,
7946 TEND
7947};
Denis Vlasenkob07a4962008-06-22 13:16:23 +00007948typedef smallint token_id_t;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007949
Denys Vlasenko888527c2016-10-02 16:54:17 +02007950/* Nth bit indicates if token marks the end of a list */
7951enum {
7952 tokendlist = 0
7953 /* 0 */ | (1u << TEOF)
7954 /* 1 */ | (0u << TNL)
7955 /* 2 */ | (0u << TREDIR)
7956 /* 3 */ | (0u << TWORD)
7957 /* 4 */ | (0u << TSEMI)
7958 /* 5 */ | (0u << TBACKGND)
7959 /* 6 */ | (0u << TAND)
7960 /* 7 */ | (0u << TOR)
7961 /* 8 */ | (0u << TPIPE)
7962 /* 9 */ | (0u << TLP)
7963 /* 10 */ | (1u << TRP)
7964 /* 11 */ | (1u << TENDCASE)
7965 /* 12 */ | (1u << TENDBQUOTE)
7966 /* 13 */ | (0u << TNOT)
7967 /* 14 */ | (0u << TCASE)
7968 /* 15 */ | (1u << TDO)
7969 /* 16 */ | (1u << TDONE)
7970 /* 17 */ | (1u << TELIF)
7971 /* 18 */ | (1u << TELSE)
7972 /* 19 */ | (1u << TESAC)
7973 /* 20 */ | (1u << TFI)
7974 /* 21 */ | (0u << TFOR)
7975#if ENABLE_ASH_BASH_COMPAT
7976 /* 22 */ | (0u << TFUNCTION)
Denys Vlasenko80729a42016-10-02 22:33:15 +02007977#endif
Denys Vlasenko888527c2016-10-02 16:54:17 +02007978 /* 23 */ | (0u << TIF)
7979 /* 24 */ | (0u << TIN)
7980 /* 25 */ | (1u << TTHEN)
7981 /* 26 */ | (0u << TUNTIL)
7982 /* 27 */ | (0u << TWHILE)
7983 /* 28 */ | (0u << TBEGIN)
7984 /* 29 */ | (1u << TEND)
7985 , /* thus far 29 bits used */
7986};
7987
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007988static const char *const tokname_array[] = {
Denys Vlasenko888527c2016-10-02 16:54:17 +02007989 "end of file",
7990 "newline",
7991 "redirection",
7992 "word",
7993 ";",
7994 "&",
7995 "&&",
7996 "||",
7997 "|",
7998 "(",
7999 ")",
8000 ";;",
8001 "`",
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008002#define KWDOFFSET 13
8003 /* the following are keywords */
Denys Vlasenko888527c2016-10-02 16:54:17 +02008004 "!",
8005 "case",
8006 "do",
8007 "done",
8008 "elif",
8009 "else",
8010 "esac",
8011 "fi",
8012 "for",
Ron Yorston95ebcf72015-11-03 09:42:23 +00008013#if ENABLE_ASH_BASH_COMPAT
Denys Vlasenko888527c2016-10-02 16:54:17 +02008014 "function",
Ron Yorston95ebcf72015-11-03 09:42:23 +00008015#endif
Denys Vlasenko888527c2016-10-02 16:54:17 +02008016 "if",
8017 "in",
8018 "then",
8019 "until",
8020 "while",
8021 "{",
8022 "}",
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008023};
8024
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008025/* Wrapper around strcmp for qsort/bsearch/... */
8026static int
8027pstrcmp(const void *a, const void *b)
8028{
Denys Vlasenko888527c2016-10-02 16:54:17 +02008029 return strcmp((char*)a, *(char**)b);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008030}
8031
8032static const char *const *
8033findkwd(const char *s)
8034{
8035 return bsearch(s, tokname_array + KWDOFFSET,
Denis Vlasenko80b8b392007-06-25 10:55:35 +00008036 ARRAY_SIZE(tokname_array) - KWDOFFSET,
8037 sizeof(tokname_array[0]), pstrcmp);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008038}
8039
8040/*
8041 * Locate and print what a word is...
8042 */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008043static int
Ron Yorston3f221112015-08-03 13:47:33 +01008044describe_command(char *command, const char *path, int describe_command_verbose)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008045{
8046 struct cmdentry entry;
8047 struct tblentry *cmdp;
8048#if ENABLE_ASH_ALIAS
8049 const struct alias *ap;
8050#endif
Ron Yorston3f221112015-08-03 13:47:33 +01008051
8052 path = path ? path : pathval();
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008053
8054 if (describe_command_verbose) {
8055 out1str(command);
8056 }
8057
8058 /* First look at the keywords */
8059 if (findkwd(command)) {
8060 out1str(describe_command_verbose ? " is a shell keyword" : command);
8061 goto out;
8062 }
8063
8064#if ENABLE_ASH_ALIAS
8065 /* Then look at the aliases */
8066 ap = lookupalias(command, 0);
8067 if (ap != NULL) {
Denis Vlasenko46846e22007-05-20 13:08:31 +00008068 if (!describe_command_verbose) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008069 out1str("alias ");
8070 printalias(ap);
8071 return 0;
8072 }
Denis Vlasenko46846e22007-05-20 13:08:31 +00008073 out1fmt(" is an alias for %s", ap->val);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008074 goto out;
8075 }
8076#endif
8077 /* Then check if it is a tracked alias */
8078 cmdp = cmdlookup(command, 0);
8079 if (cmdp != NULL) {
8080 entry.cmdtype = cmdp->cmdtype;
8081 entry.u = cmdp->param;
8082 } else {
8083 /* Finally use brute force */
8084 find_command(command, &entry, DO_ABS, path);
8085 }
8086
8087 switch (entry.cmdtype) {
8088 case CMDNORMAL: {
8089 int j = entry.u.index;
8090 char *p;
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00008091 if (j < 0) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008092 p = command;
8093 } else {
8094 do {
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02008095 p = path_advance(&path, command);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008096 stunalloc(p);
8097 } while (--j >= 0);
8098 }
8099 if (describe_command_verbose) {
8100 out1fmt(" is%s %s",
8101 (cmdp ? " a tracked alias for" : nullstr), p
8102 );
8103 } else {
8104 out1str(p);
8105 }
8106 break;
8107 }
8108
8109 case CMDFUNCTION:
8110 if (describe_command_verbose) {
8111 out1str(" is a shell function");
8112 } else {
8113 out1str(command);
8114 }
8115 break;
8116
8117 case CMDBUILTIN:
8118 if (describe_command_verbose) {
8119 out1fmt(" is a %sshell builtin",
8120 IS_BUILTIN_SPECIAL(entry.u.cmd) ?
8121 "special " : nullstr
8122 );
8123 } else {
8124 out1str(command);
8125 }
8126 break;
8127
8128 default:
8129 if (describe_command_verbose) {
8130 out1str(": not found\n");
8131 }
8132 return 127;
8133 }
8134 out:
Denys Vlasenko285ad152009-12-04 23:02:27 +01008135 out1str("\n");
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008136 return 0;
8137}
8138
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02008139static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00008140typecmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008141{
Denis Vlasenko46846e22007-05-20 13:08:31 +00008142 int i = 1;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008143 int err = 0;
Denis Vlasenko46846e22007-05-20 13:08:31 +00008144 int verbose = 1;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008145
Denis Vlasenko46846e22007-05-20 13:08:31 +00008146 /* type -p ... ? (we don't bother checking for 'p') */
Denis Vlasenko1fc62382007-06-25 22:55:34 +00008147 if (argv[1] && argv[1][0] == '-') {
Denis Vlasenko46846e22007-05-20 13:08:31 +00008148 i++;
8149 verbose = 0;
8150 }
Denis Vlasenko68404f12008-03-17 09:00:54 +00008151 while (argv[i]) {
Ron Yorston3f221112015-08-03 13:47:33 +01008152 err |= describe_command(argv[i++], NULL, verbose);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008153 }
8154 return err;
8155}
8156
8157#if ENABLE_ASH_CMDCMD
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008158/* Is it "command [-p] PROG ARGS" bltin, no other opts? Return ptr to "PROG" if yes */
8159static char **
8160parse_command_args(char **argv, const char **path)
8161{
8162 char *cp, c;
8163
8164 for (;;) {
8165 cp = *++argv;
8166 if (!cp)
8167 return NULL;
8168 if (*cp++ != '-')
8169 break;
8170 c = *cp++;
8171 if (!c)
8172 break;
8173 if (c == '-' && !*cp) {
8174 if (!*++argv)
8175 return NULL;
8176 break;
8177 }
8178 do {
8179 switch (c) {
8180 case 'p':
8181 *path = bb_default_path;
8182 break;
8183 default:
8184 /* run 'typecmd' for other options */
8185 return NULL;
8186 }
8187 c = *cp++;
8188 } while (c);
8189 }
8190 return argv;
8191}
8192
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02008193static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00008194commandcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008195{
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008196 char *cmd;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008197 int c;
8198 enum {
8199 VERIFY_BRIEF = 1,
8200 VERIFY_VERBOSE = 2,
8201 } verify = 0;
Ron Yorston3f221112015-08-03 13:47:33 +01008202 const char *path = NULL;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008203
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008204 /* "command [-p] PROG ARGS" (that is, without -V or -v)
8205 * never reaches this function.
8206 */
8207
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008208 while ((c = nextopt("pvV")) != '\0')
8209 if (c == 'V')
8210 verify |= VERIFY_VERBOSE;
8211 else if (c == 'v')
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008212 /*verify |= VERIFY_BRIEF*/;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008213#if DEBUG
8214 else if (c != 'p')
8215 abort();
8216#endif
Ron Yorston3f221112015-08-03 13:47:33 +01008217 else
8218 path = bb_default_path;
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008219
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00008220 /* Mimic bash: just "command -v" doesn't complain, it's a nop */
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008221 cmd = *argptr;
8222 if (/*verify && */ cmd)
8223 return describe_command(cmd, path, verify /* - VERIFY_BRIEF*/);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008224
8225 return 0;
8226}
8227#endif
8228
8229
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008230/*static int funcblocksize; // size of structures in function */
8231/*static int funcstringsize; // size of strings in node */
Denis Vlasenko340299a2008-11-21 10:36:36 +00008232static void *funcblock; /* block to allocate function from */
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008233static char *funcstring_end; /* end of block to allocate strings from */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008234
Eric Andersencb57d552001-06-28 07:25:16 +00008235/* flags in argument to evaltree */
Denis Vlasenko340299a2008-11-21 10:36:36 +00008236#define EV_EXIT 01 /* exit after evaluating tree */
8237#define EV_TESTED 02 /* exit status is checked; ignore -e flag */
Eric Andersencb57d552001-06-28 07:25:16 +00008238
Denys Vlasenko3e134eb2016-04-22 18:09:21 +02008239static const uint8_t nodesize[N_NUMBER] ALIGN1 = {
Denis Vlasenko340299a2008-11-21 10:36:36 +00008240 [NCMD ] = SHELL_ALIGN(sizeof(struct ncmd)),
8241 [NPIPE ] = SHELL_ALIGN(sizeof(struct npipe)),
8242 [NREDIR ] = SHELL_ALIGN(sizeof(struct nredir)),
8243 [NBACKGND ] = SHELL_ALIGN(sizeof(struct nredir)),
8244 [NSUBSHELL] = SHELL_ALIGN(sizeof(struct nredir)),
8245 [NAND ] = SHELL_ALIGN(sizeof(struct nbinary)),
8246 [NOR ] = SHELL_ALIGN(sizeof(struct nbinary)),
8247 [NSEMI ] = SHELL_ALIGN(sizeof(struct nbinary)),
8248 [NIF ] = SHELL_ALIGN(sizeof(struct nif)),
8249 [NWHILE ] = SHELL_ALIGN(sizeof(struct nbinary)),
8250 [NUNTIL ] = SHELL_ALIGN(sizeof(struct nbinary)),
8251 [NFOR ] = SHELL_ALIGN(sizeof(struct nfor)),
8252 [NCASE ] = SHELL_ALIGN(sizeof(struct ncase)),
8253 [NCLIST ] = SHELL_ALIGN(sizeof(struct nclist)),
8254 [NDEFUN ] = SHELL_ALIGN(sizeof(struct narg)),
8255 [NARG ] = SHELL_ALIGN(sizeof(struct narg)),
8256 [NTO ] = SHELL_ALIGN(sizeof(struct nfile)),
Denis Vlasenkocc5feab2008-11-22 01:32:40 +00008257#if ENABLE_ASH_BASH_COMPAT
Denis Vlasenko340299a2008-11-21 10:36:36 +00008258 [NTO2 ] = SHELL_ALIGN(sizeof(struct nfile)),
Denis Vlasenkocc5feab2008-11-22 01:32:40 +00008259#endif
Denis Vlasenko340299a2008-11-21 10:36:36 +00008260 [NCLOBBER ] = SHELL_ALIGN(sizeof(struct nfile)),
8261 [NFROM ] = SHELL_ALIGN(sizeof(struct nfile)),
8262 [NFROMTO ] = SHELL_ALIGN(sizeof(struct nfile)),
8263 [NAPPEND ] = SHELL_ALIGN(sizeof(struct nfile)),
8264 [NTOFD ] = SHELL_ALIGN(sizeof(struct ndup)),
8265 [NFROMFD ] = SHELL_ALIGN(sizeof(struct ndup)),
8266 [NHERE ] = SHELL_ALIGN(sizeof(struct nhere)),
8267 [NXHERE ] = SHELL_ALIGN(sizeof(struct nhere)),
8268 [NNOT ] = SHELL_ALIGN(sizeof(struct nnot)),
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008269};
8270
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008271static int calcsize(int funcblocksize, union node *n);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008272
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008273static int
8274sizenodelist(int funcblocksize, struct nodelist *lp)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008275{
8276 while (lp) {
8277 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008278 funcblocksize = calcsize(funcblocksize, lp->n);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008279 lp = lp->next;
8280 }
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008281 return funcblocksize;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008282}
8283
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008284static int
8285calcsize(int funcblocksize, union node *n)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008286{
8287 if (n == NULL)
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008288 return funcblocksize;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008289 funcblocksize += nodesize[n->type];
8290 switch (n->type) {
8291 case NCMD:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008292 funcblocksize = calcsize(funcblocksize, n->ncmd.redirect);
8293 funcblocksize = calcsize(funcblocksize, n->ncmd.args);
8294 funcblocksize = calcsize(funcblocksize, n->ncmd.assign);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008295 break;
8296 case NPIPE:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008297 funcblocksize = sizenodelist(funcblocksize, n->npipe.cmdlist);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008298 break;
8299 case NREDIR:
8300 case NBACKGND:
8301 case NSUBSHELL:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008302 funcblocksize = calcsize(funcblocksize, n->nredir.redirect);
8303 funcblocksize = calcsize(funcblocksize, n->nredir.n);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008304 break;
8305 case NAND:
8306 case NOR:
8307 case NSEMI:
8308 case NWHILE:
8309 case NUNTIL:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008310 funcblocksize = calcsize(funcblocksize, n->nbinary.ch2);
8311 funcblocksize = calcsize(funcblocksize, n->nbinary.ch1);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008312 break;
8313 case NIF:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008314 funcblocksize = calcsize(funcblocksize, n->nif.elsepart);
8315 funcblocksize = calcsize(funcblocksize, n->nif.ifpart);
8316 funcblocksize = calcsize(funcblocksize, n->nif.test);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008317 break;
8318 case NFOR:
Denys Vlasenko561639a2016-10-07 04:28:33 +02008319 funcblocksize += SHELL_ALIGN(strlen(n->nfor.var) + 1); /* was funcstringsize += ... */
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008320 funcblocksize = calcsize(funcblocksize, n->nfor.body);
8321 funcblocksize = calcsize(funcblocksize, n->nfor.args);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008322 break;
8323 case NCASE:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008324 funcblocksize = calcsize(funcblocksize, n->ncase.cases);
8325 funcblocksize = calcsize(funcblocksize, n->ncase.expr);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008326 break;
8327 case NCLIST:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008328 funcblocksize = calcsize(funcblocksize, n->nclist.body);
8329 funcblocksize = calcsize(funcblocksize, n->nclist.pattern);
8330 funcblocksize = calcsize(funcblocksize, n->nclist.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008331 break;
8332 case NDEFUN:
8333 case NARG:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008334 funcblocksize = sizenodelist(funcblocksize, n->narg.backquote);
Denys Vlasenko561639a2016-10-07 04:28:33 +02008335 funcblocksize += SHELL_ALIGN(strlen(n->narg.text) + 1); /* was funcstringsize += ... */
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008336 funcblocksize = calcsize(funcblocksize, n->narg.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008337 break;
8338 case NTO:
Denis Vlasenko559691a2008-10-05 18:39:31 +00008339#if ENABLE_ASH_BASH_COMPAT
8340 case NTO2:
8341#endif
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008342 case NCLOBBER:
8343 case NFROM:
8344 case NFROMTO:
8345 case NAPPEND:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008346 funcblocksize = calcsize(funcblocksize, n->nfile.fname);
8347 funcblocksize = calcsize(funcblocksize, n->nfile.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008348 break;
8349 case NTOFD:
8350 case NFROMFD:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008351 funcblocksize = calcsize(funcblocksize, n->ndup.vname);
8352 funcblocksize = calcsize(funcblocksize, n->ndup.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008353 break;
8354 case NHERE:
8355 case NXHERE:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008356 funcblocksize = calcsize(funcblocksize, n->nhere.doc);
8357 funcblocksize = calcsize(funcblocksize, n->nhere.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008358 break;
8359 case NNOT:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008360 funcblocksize = calcsize(funcblocksize, n->nnot.com);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008361 break;
8362 };
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008363 return funcblocksize;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008364}
8365
8366static char *
8367nodeckstrdup(char *s)
8368{
Denys Vlasenko561639a2016-10-07 04:28:33 +02008369 funcstring_end -= SHELL_ALIGN(strlen(s) + 1);
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008370 return strcpy(funcstring_end, s);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008371}
8372
8373static union node *copynode(union node *);
8374
8375static struct nodelist *
8376copynodelist(struct nodelist *lp)
8377{
8378 struct nodelist *start;
8379 struct nodelist **lpp;
8380
8381 lpp = &start;
8382 while (lp) {
8383 *lpp = funcblock;
8384 funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist));
8385 (*lpp)->n = copynode(lp->n);
8386 lp = lp->next;
8387 lpp = &(*lpp)->next;
8388 }
8389 *lpp = NULL;
8390 return start;
8391}
8392
8393static union node *
8394copynode(union node *n)
8395{
8396 union node *new;
8397
8398 if (n == NULL)
8399 return NULL;
8400 new = funcblock;
8401 funcblock = (char *) funcblock + nodesize[n->type];
8402
8403 switch (n->type) {
8404 case NCMD:
8405 new->ncmd.redirect = copynode(n->ncmd.redirect);
8406 new->ncmd.args = copynode(n->ncmd.args);
8407 new->ncmd.assign = copynode(n->ncmd.assign);
8408 break;
8409 case NPIPE:
8410 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00008411 new->npipe.pipe_backgnd = n->npipe.pipe_backgnd;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008412 break;
8413 case NREDIR:
8414 case NBACKGND:
8415 case NSUBSHELL:
8416 new->nredir.redirect = copynode(n->nredir.redirect);
8417 new->nredir.n = copynode(n->nredir.n);
8418 break;
8419 case NAND:
8420 case NOR:
8421 case NSEMI:
8422 case NWHILE:
8423 case NUNTIL:
8424 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8425 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8426 break;
8427 case NIF:
8428 new->nif.elsepart = copynode(n->nif.elsepart);
8429 new->nif.ifpart = copynode(n->nif.ifpart);
8430 new->nif.test = copynode(n->nif.test);
8431 break;
8432 case NFOR:
8433 new->nfor.var = nodeckstrdup(n->nfor.var);
8434 new->nfor.body = copynode(n->nfor.body);
8435 new->nfor.args = copynode(n->nfor.args);
8436 break;
8437 case NCASE:
8438 new->ncase.cases = copynode(n->ncase.cases);
8439 new->ncase.expr = copynode(n->ncase.expr);
8440 break;
8441 case NCLIST:
8442 new->nclist.body = copynode(n->nclist.body);
8443 new->nclist.pattern = copynode(n->nclist.pattern);
8444 new->nclist.next = copynode(n->nclist.next);
8445 break;
8446 case NDEFUN:
8447 case NARG:
8448 new->narg.backquote = copynodelist(n->narg.backquote);
8449 new->narg.text = nodeckstrdup(n->narg.text);
8450 new->narg.next = copynode(n->narg.next);
8451 break;
8452 case NTO:
Denis Vlasenko559691a2008-10-05 18:39:31 +00008453#if ENABLE_ASH_BASH_COMPAT
8454 case NTO2:
8455#endif
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008456 case NCLOBBER:
8457 case NFROM:
8458 case NFROMTO:
8459 case NAPPEND:
8460 new->nfile.fname = copynode(n->nfile.fname);
8461 new->nfile.fd = n->nfile.fd;
8462 new->nfile.next = copynode(n->nfile.next);
8463 break;
8464 case NTOFD:
8465 case NFROMFD:
8466 new->ndup.vname = copynode(n->ndup.vname);
8467 new->ndup.dupfd = n->ndup.dupfd;
8468 new->ndup.fd = n->ndup.fd;
8469 new->ndup.next = copynode(n->ndup.next);
8470 break;
8471 case NHERE:
8472 case NXHERE:
8473 new->nhere.doc = copynode(n->nhere.doc);
8474 new->nhere.fd = n->nhere.fd;
8475 new->nhere.next = copynode(n->nhere.next);
8476 break;
8477 case NNOT:
8478 new->nnot.com = copynode(n->nnot.com);
8479 break;
8480 };
8481 new->type = n->type;
8482 return new;
8483}
8484
8485/*
8486 * Make a copy of a parse tree.
8487 */
8488static struct funcnode *
8489copyfunc(union node *n)
8490{
8491 struct funcnode *f;
8492 size_t blocksize;
8493
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008494 /*funcstringsize = 0;*/
8495 blocksize = offsetof(struct funcnode, n) + calcsize(0, n);
8496 f = ckzalloc(blocksize /* + funcstringsize */);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008497 funcblock = (char *) f + offsetof(struct funcnode, n);
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008498 funcstring_end = (char *) f + blocksize;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008499 copynode(n);
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008500 /* f->count = 0; - ckzalloc did it */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008501 return f;
8502}
8503
8504/*
8505 * Define a shell function.
8506 */
8507static void
Denys Vlasenko7aec8682016-10-25 20:26:02 +02008508defun(union node *func)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008509{
8510 struct cmdentry entry;
8511
8512 INT_OFF;
8513 entry.cmdtype = CMDFUNCTION;
8514 entry.u.func = copyfunc(func);
Denys Vlasenko7aec8682016-10-25 20:26:02 +02008515 addcmdentry(func->narg.text, &entry);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008516 INT_ON;
8517}
8518
Denis Vlasenko4b875702009-03-19 13:30:04 +00008519/* Reasons for skipping commands (see comment on breakcmd routine) */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008520#define SKIPBREAK (1 << 0)
8521#define SKIPCONT (1 << 1)
8522#define SKIPFUNC (1 << 2)
Denis Vlasenko4b875702009-03-19 13:30:04 +00008523static smallint evalskip; /* set to SKIPxxx if we are skipping commands */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008524static int skipcount; /* number of levels to skip */
8525static int funcnest; /* depth of function calls */
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +00008526static int loopnest; /* current loop nesting level */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008527
Denis Vlasenko4b875702009-03-19 13:30:04 +00008528/* Forward decl way out to parsing code - dotrap needs it */
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02008529static int evalstring(char *s, int flags);
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008530
Denis Vlasenko4b875702009-03-19 13:30:04 +00008531/* Called to execute a trap.
8532 * Single callsite - at the end of evaltree().
Denys Vlasenkob563f622010-09-25 17:15:13 +02008533 * If we return non-zero, evaltree raises EXEXIT exception.
Denis Vlasenko4b875702009-03-19 13:30:04 +00008534 *
8535 * Perhaps we should avoid entering new trap handlers
8536 * while we are executing a trap handler. [is it a TODO?]
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008537 */
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008538static void
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008539dotrap(void)
8540{
Denis Vlasenko4b875702009-03-19 13:30:04 +00008541 uint8_t *g;
8542 int sig;
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008543 uint8_t last_status;
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008544
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008545 if (!pending_sig)
8546 return;
8547
8548 last_status = exitstatus;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02008549 pending_sig = 0;
Denys Vlasenkode892052016-10-02 01:49:13 +02008550 barrier();
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008551
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008552 TRACE(("dotrap entered\n"));
Denis Vlasenko4b875702009-03-19 13:30:04 +00008553 for (sig = 1, g = gotsig; sig < NSIG; sig++, g++) {
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008554 char *p;
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008555
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008556 if (!*g)
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008557 continue;
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008558
8559 if (evalskip) {
8560 pending_sig = sig;
8561 break;
8562 }
8563
8564 p = trap[sig];
Denis Vlasenko4b875702009-03-19 13:30:04 +00008565 /* non-trapped SIGINT is handled separately by raise_interrupt,
8566 * don't upset it by resetting gotsig[SIGINT-1] */
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008567 if (sig == SIGINT && !p)
Denis Vlasenko4b875702009-03-19 13:30:04 +00008568 continue;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008569
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008570 TRACE(("sig %d is active, will run handler '%s'\n", sig, p));
Denis Vlasenko4b875702009-03-19 13:30:04 +00008571 *g = 0;
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008572 if (!p)
Denis Vlasenko4b875702009-03-19 13:30:04 +00008573 continue;
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008574 evalstring(p, 0);
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008575 }
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008576 exitstatus = last_status;
8577 TRACE(("dotrap returns\n"));
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008578}
8579
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00008580/* forward declarations - evaluation is fairly recursive business... */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008581static int evalloop(union node *, int);
8582static int evalfor(union node *, int);
8583static int evalcase(union node *, int);
8584static int evalsubshell(union node *, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008585static void expredir(union node *);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008586static int evalpipe(union node *, int);
8587static int evalcommand(union node *, int);
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02008588static int evalbltin(const struct builtincmd *, int, char **, int);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008589static void prehash(union node *);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008590
Eric Andersen62483552001-07-10 06:09:16 +00008591/*
Eric Andersenc470f442003-07-28 09:56:35 +00008592 * Evaluate a parse tree. The value is left in the global variable
8593 * exitstatus.
Eric Andersen62483552001-07-10 06:09:16 +00008594 */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008595static int
Eric Andersenc470f442003-07-28 09:56:35 +00008596evaltree(union node *n, int flags)
Eric Andersen62483552001-07-10 06:09:16 +00008597{
Eric Andersenc470f442003-07-28 09:56:35 +00008598 int checkexit = 0;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008599 int (*evalfn)(union node *, int);
8600 int status = 0;
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008601
Eric Andersenc470f442003-07-28 09:56:35 +00008602 if (n == NULL) {
8603 TRACE(("evaltree(NULL) called\n"));
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02008604 goto out;
Eric Andersen62483552001-07-10 06:09:16 +00008605 }
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008606 TRACE(("evaltree(%p: %d, %d) called\n", n, n->type, flags));
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008607
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008608 dotrap();
8609
Eric Andersenc470f442003-07-28 09:56:35 +00008610 switch (n->type) {
8611 default:
Denis Vlasenkoa7189f02006-11-17 20:29:00 +00008612#if DEBUG
Eric Andersenc470f442003-07-28 09:56:35 +00008613 out1fmt("Node type = %d\n", n->type);
Denys Vlasenko8131eea2009-11-02 14:19:51 +01008614 fflush_all();
Eric Andersenc470f442003-07-28 09:56:35 +00008615 break;
8616#endif
8617 case NNOT:
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008618 status = !evaltree(n->nnot.com, EV_TESTED);
Eric Andersenc470f442003-07-28 09:56:35 +00008619 goto setstatus;
8620 case NREDIR:
8621 expredir(n->nredir.redirect);
8622 status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
8623 if (!status) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008624 status = evaltree(n->nredir.n, flags & EV_TESTED);
Eric Andersenc470f442003-07-28 09:56:35 +00008625 }
Denys Vlasenkoeaf94362016-10-25 21:46:03 +02008626 if (n->nredir.redirect)
8627 popredir(/*drop:*/ 0, /*restore:*/ 0 /* not sure */);
Eric Andersenc470f442003-07-28 09:56:35 +00008628 goto setstatus;
8629 case NCMD:
8630 evalfn = evalcommand;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008631 checkexit:
Eric Andersenc470f442003-07-28 09:56:35 +00008632 if (eflag && !(flags & EV_TESTED))
8633 checkexit = ~0;
8634 goto calleval;
8635 case NFOR:
8636 evalfn = evalfor;
8637 goto calleval;
8638 case NWHILE:
8639 case NUNTIL:
8640 evalfn = evalloop;
8641 goto calleval;
8642 case NSUBSHELL:
8643 case NBACKGND:
8644 evalfn = evalsubshell;
Denys Vlasenkocf98b0c2016-10-25 18:19:39 +02008645 goto checkexit;
Eric Andersenc470f442003-07-28 09:56:35 +00008646 case NPIPE:
8647 evalfn = evalpipe;
8648 goto checkexit;
8649 case NCASE:
8650 evalfn = evalcase;
8651 goto calleval;
8652 case NAND:
8653 case NOR:
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008654 case NSEMI: {
8655
Eric Andersenc470f442003-07-28 09:56:35 +00008656#if NAND + 1 != NOR
8657#error NAND + 1 != NOR
8658#endif
8659#if NOR + 1 != NSEMI
8660#error NOR + 1 != NSEMI
8661#endif
Denis Vlasenko87d5fd92008-07-26 13:48:35 +00008662 unsigned is_or = n->type - NAND;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008663 status = evaltree(
Eric Andersenc470f442003-07-28 09:56:35 +00008664 n->nbinary.ch1,
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008665 (flags | ((is_or >> 1) - 1)) & EV_TESTED
Eric Andersenc470f442003-07-28 09:56:35 +00008666 );
Denys Vlasenkobc1a0082016-10-02 15:31:33 +02008667 if ((!status) == is_or || evalskip)
Eric Andersenc470f442003-07-28 09:56:35 +00008668 break;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008669 n = n->nbinary.ch2;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008670 evaln:
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008671 evalfn = evaltree;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008672 calleval:
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008673 status = evalfn(n, flags);
8674 goto setstatus;
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008675 }
Eric Andersenc470f442003-07-28 09:56:35 +00008676 case NIF:
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008677 status = evaltree(n->nif.test, EV_TESTED);
Eric Andersenc470f442003-07-28 09:56:35 +00008678 if (evalskip)
8679 break;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008680 if (!status) {
Eric Andersenc470f442003-07-28 09:56:35 +00008681 n = n->nif.ifpart;
8682 goto evaln;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008683 }
8684 if (n->nif.elsepart) {
Eric Andersenc470f442003-07-28 09:56:35 +00008685 n = n->nif.elsepart;
8686 goto evaln;
8687 }
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008688 status = 0;
8689 goto setstatus;
Eric Andersenc470f442003-07-28 09:56:35 +00008690 case NDEFUN:
Denys Vlasenko7aec8682016-10-25 20:26:02 +02008691 defun(n);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008692 /* Not necessary. To test it:
8693 * "false; f() { qwerty; }; echo $?" should print 0.
8694 */
8695 /* status = 0; */
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008696 setstatus:
Eric Andersenc470f442003-07-28 09:56:35 +00008697 exitstatus = status;
8698 break;
8699 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008700 out:
Denys Vlasenkob563f622010-09-25 17:15:13 +02008701 /* Order of checks below is important:
8702 * signal handlers trigger before exit caused by "set -e".
8703 */
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008704 dotrap();
8705
8706 if (checkexit & status)
Denis Vlasenkob012b102007-02-19 22:43:01 +00008707 raise_exception(EXEXIT);
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008708 if (flags & EV_EXIT)
8709 raise_exception(EXEXIT);
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008710
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008711 TRACE(("leaving evaltree (no interrupts)\n"));
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008712 return exitstatus;
Eric Andersen62483552001-07-10 06:09:16 +00008713}
8714
Eric Andersenc470f442003-07-28 09:56:35 +00008715#if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3)
8716static
8717#endif
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008718int evaltreenr(union node *, int) __attribute__ ((alias("evaltree"),__noreturn__));
Eric Andersenc470f442003-07-28 09:56:35 +00008719
Denys Vlasenko37dc08b2016-10-02 04:38:07 +02008720static int
8721skiploop(void)
Denys Vlasenko35ec8182016-10-01 19:56:52 +02008722{
8723 int skip = evalskip;
8724
8725 switch (skip) {
8726 case 0:
8727 break;
8728 case SKIPBREAK:
8729 case SKIPCONT:
8730 if (--skipcount <= 0) {
8731 evalskip = 0;
8732 break;
8733 }
8734 skip = SKIPBREAK;
8735 break;
8736 }
8737 return skip;
8738}
8739
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008740static int
Eric Andersenc470f442003-07-28 09:56:35 +00008741evalloop(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00008742{
Denys Vlasenko35ec8182016-10-01 19:56:52 +02008743 int skip;
Eric Andersencb57d552001-06-28 07:25:16 +00008744 int status;
8745
8746 loopnest++;
8747 status = 0;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008748 flags &= EV_TESTED;
Denys Vlasenko35ec8182016-10-01 19:56:52 +02008749 do {
Eric Andersenc470f442003-07-28 09:56:35 +00008750 int i;
8751
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008752 i = evaltree(n->nbinary.ch1, EV_TESTED);
Denys Vlasenko35ec8182016-10-01 19:56:52 +02008753 skip = skiploop();
8754 if (skip == SKIPFUNC)
8755 status = i;
8756 if (skip)
8757 continue;
Eric Andersenc470f442003-07-28 09:56:35 +00008758 if (n->type != NWHILE)
8759 i = !i;
8760 if (i != 0)
8761 break;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008762 status = evaltree(n->nbinary.ch2, flags);
Denys Vlasenko35ec8182016-10-01 19:56:52 +02008763 skip = skiploop();
8764 } while (!(skip & ~SKIPCONT));
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008765 loopnest--;
8766
8767 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00008768}
8769
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008770static int
Eric Andersenc470f442003-07-28 09:56:35 +00008771evalfor(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00008772{
8773 struct arglist arglist;
8774 union node *argp;
8775 struct strlist *sp;
8776 struct stackmark smark;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008777 int status = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00008778
8779 setstackmark(&smark);
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00008780 arglist.list = NULL;
Eric Andersencb57d552001-06-28 07:25:16 +00008781 arglist.lastp = &arglist.list;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008782 for (argp = n->nfor.args; argp; argp = argp->narg.next) {
Ron Yorston549deab2015-05-18 09:57:51 +02008783 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
Eric Andersencb57d552001-06-28 07:25:16 +00008784 }
8785 *arglist.lastp = NULL;
8786
Eric Andersencb57d552001-06-28 07:25:16 +00008787 loopnest++;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008788 flags &= EV_TESTED;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008789 for (sp = arglist.list; sp; sp = sp->next) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02008790 setvar0(n->nfor.var, sp->text);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008791 status = evaltree(n->nfor.body, flags);
Denys Vlasenko35ec8182016-10-01 19:56:52 +02008792 if (skiploop() & ~SKIPCONT)
Eric Andersencb57d552001-06-28 07:25:16 +00008793 break;
Eric Andersencb57d552001-06-28 07:25:16 +00008794 }
8795 loopnest--;
Eric Andersencb57d552001-06-28 07:25:16 +00008796 popstackmark(&smark);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008797
8798 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00008799}
8800
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008801static int
Eric Andersenc470f442003-07-28 09:56:35 +00008802evalcase(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00008803{
8804 union node *cp;
8805 union node *patp;
8806 struct arglist arglist;
8807 struct stackmark smark;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008808 int status = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00008809
8810 setstackmark(&smark);
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00008811 arglist.list = NULL;
Eric Andersencb57d552001-06-28 07:25:16 +00008812 arglist.lastp = &arglist.list;
Eric Andersencb57d552001-06-28 07:25:16 +00008813 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008814 for (cp = n->ncase.cases; cp && evalskip == 0; cp = cp->nclist.next) {
8815 for (patp = cp->nclist.pattern; patp; patp = patp->narg.next) {
Eric Andersencb57d552001-06-28 07:25:16 +00008816 if (casematch(patp, arglist.list->text)) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008817 /* Ensure body is non-empty as otherwise
8818 * EV_EXIT may prevent us from setting the
8819 * exit status.
8820 */
8821 if (evalskip == 0 && cp->nclist.body) {
8822 status = evaltree(cp->nclist.body, flags);
Eric Andersencb57d552001-06-28 07:25:16 +00008823 }
8824 goto out;
8825 }
8826 }
8827 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008828 out:
Eric Andersencb57d552001-06-28 07:25:16 +00008829 popstackmark(&smark);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008830
8831 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00008832}
8833
Eric Andersenc470f442003-07-28 09:56:35 +00008834/*
8835 * Kick off a subshell to evaluate a tree.
8836 */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008837static int
Eric Andersenc470f442003-07-28 09:56:35 +00008838evalsubshell(union node *n, int flags)
8839{
8840 struct job *jp;
8841 int backgnd = (n->type == NBACKGND);
8842 int status;
8843
8844 expredir(n->nredir.redirect);
Denys Vlasenko238bf182010-05-18 15:49:07 +02008845 if (!backgnd && (flags & EV_EXIT) && !may_have_traps)
Eric Andersenc470f442003-07-28 09:56:35 +00008846 goto nofork;
Denis Vlasenkob012b102007-02-19 22:43:01 +00008847 INT_OFF;
Denis Vlasenko68404f12008-03-17 09:00:54 +00008848 jp = makejob(/*n,*/ 1);
Eric Andersenc470f442003-07-28 09:56:35 +00008849 if (forkshell(jp, n, backgnd) == 0) {
Denys Vlasenko238bf182010-05-18 15:49:07 +02008850 /* child */
Denis Vlasenkob012b102007-02-19 22:43:01 +00008851 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +00008852 flags |= EV_EXIT;
8853 if (backgnd)
Denys Vlasenko238bf182010-05-18 15:49:07 +02008854 flags &= ~EV_TESTED;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00008855 nofork:
Eric Andersenc470f442003-07-28 09:56:35 +00008856 redirect(n->nredir.redirect, 0);
8857 evaltreenr(n->nredir.n, flags);
8858 /* never returns */
8859 }
Denys Vlasenko70392332016-10-27 02:31:55 +02008860 /* parent */
Eric Andersenc470f442003-07-28 09:56:35 +00008861 status = 0;
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00008862 if (!backgnd)
Eric Andersenc470f442003-07-28 09:56:35 +00008863 status = waitforjob(jp);
Denis Vlasenkob012b102007-02-19 22:43:01 +00008864 INT_ON;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008865 return status;
Eric Andersenc470f442003-07-28 09:56:35 +00008866}
8867
Eric Andersenc470f442003-07-28 09:56:35 +00008868/*
8869 * Compute the names of the files in a redirection list.
8870 */
Denis Vlasenko99eb8502007-02-23 21:09:49 +00008871static void fixredir(union node *, const char *, int);
Eric Andersenc470f442003-07-28 09:56:35 +00008872static void
8873expredir(union node *n)
8874{
8875 union node *redir;
8876
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008877 for (redir = n; redir; redir = redir->nfile.next) {
Eric Andersenc470f442003-07-28 09:56:35 +00008878 struct arglist fn;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008879
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00008880 fn.list = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00008881 fn.lastp = &fn.list;
8882 switch (redir->type) {
8883 case NFROMTO:
8884 case NFROM:
8885 case NTO:
Denis Vlasenko559691a2008-10-05 18:39:31 +00008886#if ENABLE_ASH_BASH_COMPAT
8887 case NTO2:
8888#endif
Eric Andersenc470f442003-07-28 09:56:35 +00008889 case NCLOBBER:
8890 case NAPPEND:
8891 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02008892 TRACE(("expredir expanded to '%s'\n", fn.list->text));
Denis Vlasenko559691a2008-10-05 18:39:31 +00008893#if ENABLE_ASH_BASH_COMPAT
8894 store_expfname:
8895#endif
Denys Vlasenko7c4b13e2013-01-17 13:02:27 +01008896#if 0
8897// By the design of stack allocator, the loop of this kind:
8898// while true; do while true; do break; done </dev/null; done
8899// will look like a memory leak: ash plans to free expfname's
8900// of "/dev/null" as soon as it finishes running the loop
8901// (in this case, never).
8902// This "fix" is wrong:
Jon Tollefson4ba6c5d2012-11-13 19:26:53 +01008903 if (redir->nfile.expfname)
8904 stunalloc(redir->nfile.expfname);
Denys Vlasenko7c4b13e2013-01-17 13:02:27 +01008905// It results in corrupted state of stacked allocations.
8906#endif
Eric Andersenc470f442003-07-28 09:56:35 +00008907 redir->nfile.expfname = fn.list->text;
8908 break;
8909 case NFROMFD:
Denis Vlasenko559691a2008-10-05 18:39:31 +00008910 case NTOFD: /* >& */
Eric Andersenc470f442003-07-28 09:56:35 +00008911 if (redir->ndup.vname) {
8912 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008913 if (fn.list == NULL)
Denis Vlasenkob012b102007-02-19 22:43:01 +00008914 ash_msg_and_raise_error("redir error");
Denis Vlasenko559691a2008-10-05 18:39:31 +00008915#if ENABLE_ASH_BASH_COMPAT
8916//FIXME: we used expandarg with different args!
8917 if (!isdigit_str9(fn.list->text)) {
8918 /* >&file, not >&fd */
8919 if (redir->nfile.fd != 1) /* 123>&file - BAD */
8920 ash_msg_and_raise_error("redir error");
8921 redir->type = NTO2;
8922 goto store_expfname;
8923 }
8924#endif
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008925 fixredir(redir, fn.list->text, 1);
Eric Andersenc470f442003-07-28 09:56:35 +00008926 }
8927 break;
8928 }
8929 }
8930}
8931
Eric Andersencb57d552001-06-28 07:25:16 +00008932/*
Eric Andersencb57d552001-06-28 07:25:16 +00008933 * Evaluate a pipeline. All the processes in the pipeline are children
8934 * of the process creating the pipeline. (This differs from some versions
8935 * of the shell, which make the last process in a pipeline the parent
8936 * of all the rest.)
8937 */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008938static int
Eric Andersenc470f442003-07-28 09:56:35 +00008939evalpipe(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00008940{
8941 struct job *jp;
8942 struct nodelist *lp;
8943 int pipelen;
8944 int prevfd;
8945 int pip[2];
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008946 int status = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00008947
Eric Andersenc470f442003-07-28 09:56:35 +00008948 TRACE(("evalpipe(0x%lx) called\n", (long)n));
Eric Andersencb57d552001-06-28 07:25:16 +00008949 pipelen = 0;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008950 for (lp = n->npipe.cmdlist; lp; lp = lp->next)
Eric Andersencb57d552001-06-28 07:25:16 +00008951 pipelen++;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008952 flags |= EV_EXIT;
Denis Vlasenkob012b102007-02-19 22:43:01 +00008953 INT_OFF;
Denis Vlasenko68404f12008-03-17 09:00:54 +00008954 jp = makejob(/*n,*/ pipelen);
Eric Andersencb57d552001-06-28 07:25:16 +00008955 prevfd = -1;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008956 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008957 prehash(lp->n);
Eric Andersencb57d552001-06-28 07:25:16 +00008958 pip[1] = -1;
8959 if (lp->next) {
8960 if (pipe(pip) < 0) {
8961 close(prevfd);
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00008962 ash_msg_and_raise_error("pipe call failed");
Eric Andersencb57d552001-06-28 07:25:16 +00008963 }
8964 }
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00008965 if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) {
Denys Vlasenko70392332016-10-27 02:31:55 +02008966 /* child */
Denis Vlasenkob012b102007-02-19 22:43:01 +00008967 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +00008968 if (pip[1] >= 0) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008969 close(pip[0]);
Eric Andersencb57d552001-06-28 07:25:16 +00008970 }
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008971 if (prevfd > 0) {
8972 dup2(prevfd, 0);
8973 close(prevfd);
8974 }
8975 if (pip[1] > 1) {
8976 dup2(pip[1], 1);
8977 close(pip[1]);
8978 }
Eric Andersenc470f442003-07-28 09:56:35 +00008979 evaltreenr(lp->n, flags);
8980 /* never returns */
Eric Andersencb57d552001-06-28 07:25:16 +00008981 }
Denys Vlasenko70392332016-10-27 02:31:55 +02008982 /* parent */
Eric Andersencb57d552001-06-28 07:25:16 +00008983 if (prevfd >= 0)
8984 close(prevfd);
8985 prevfd = pip[0];
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +00008986 /* Don't want to trigger debugging */
8987 if (pip[1] != -1)
8988 close(pip[1]);
Eric Andersencb57d552001-06-28 07:25:16 +00008989 }
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00008990 if (n->npipe.pipe_backgnd == 0) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008991 status = waitforjob(jp);
8992 TRACE(("evalpipe: job done exit status %d\n", status));
Eric Andersencb57d552001-06-28 07:25:16 +00008993 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00008994 INT_ON;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008995
8996 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00008997}
8998
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00008999/*
9000 * Controls whether the shell is interactive or not.
9001 */
9002static void
9003setinteractive(int on)
9004{
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009005 static smallint is_interactive;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009006
9007 if (++on == is_interactive)
9008 return;
9009 is_interactive = on;
9010 setsignal(SIGINT);
9011 setsignal(SIGQUIT);
9012 setsignal(SIGTERM);
9013#if !ENABLE_FEATURE_SH_EXTRA_QUIET
9014 if (is_interactive > 1) {
9015 /* Looks like they want an interactive shell */
Denis Vlasenkoca525b42007-06-13 12:27:17 +00009016 static smallint did_banner;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009017
Denis Vlasenkoca525b42007-06-13 12:27:17 +00009018 if (!did_banner) {
Denys Vlasenkoc34c0332009-09-29 12:25:30 +02009019 /* note: ash and hush share this string */
9020 out1fmt("\n\n%s %s\n"
Denys Vlasenko2ec34962014-09-08 16:52:39 +02009021 IF_ASH_HELP("Enter 'help' for a list of built-in commands.\n")
9022 "\n",
Denys Vlasenkoc34c0332009-09-29 12:25:30 +02009023 bb_banner,
9024 "built-in shell (ash)"
9025 );
Denis Vlasenkoca525b42007-06-13 12:27:17 +00009026 did_banner = 1;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009027 }
9028 }
9029#endif
9030}
9031
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009032static void
9033optschanged(void)
9034{
9035#if DEBUG
9036 opentrace();
9037#endif
9038 setinteractive(iflag);
9039 setjobctl(mflag);
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009040#if ENABLE_FEATURE_EDITING_VI
9041 if (viflag)
9042 line_input_state->flags |= VI_MODE;
9043 else
9044 line_input_state->flags &= ~VI_MODE;
9045#else
9046 viflag = 0; /* forcibly keep the option off */
9047#endif
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009048}
9049
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009050static struct localvar *localvars;
9051
9052/*
9053 * Called after a function returns.
9054 * Interrupts must be off.
9055 */
9056static void
9057poplocalvars(void)
9058{
9059 struct localvar *lvp;
9060 struct var *vp;
9061
9062 while ((lvp = localvars) != NULL) {
9063 localvars = lvp->next;
9064 vp = lvp->vp;
Denys Vlasenkob563f622010-09-25 17:15:13 +02009065 TRACE(("poplocalvar %s\n", vp ? vp->var_text : "-"));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009066 if (vp == NULL) { /* $- saved */
9067 memcpy(optlist, lvp->text, sizeof(optlist));
9068 free((char*)lvp->text);
9069 optschanged();
9070 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009071 unsetvar(vp->var_text);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009072 } else {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009073 if (vp->var_func)
9074 vp->var_func(var_end(lvp->text));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009075 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009076 free((char*)vp->var_text);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009077 vp->flags = lvp->flags;
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009078 vp->var_text = lvp->text;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009079 }
9080 free(lvp);
9081 }
9082}
9083
9084static int
9085evalfun(struct funcnode *func, int argc, char **argv, int flags)
9086{
9087 volatile struct shparam saveparam;
9088 struct localvar *volatile savelocalvars;
9089 struct jmploc *volatile savehandler;
9090 struct jmploc jmploc;
9091 int e;
9092
9093 saveparam = shellparam;
9094 savelocalvars = localvars;
Denys Vlasenkoa2d121c2016-09-30 11:30:11 +02009095 savehandler = exception_handler;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009096 e = setjmp(jmploc.loc);
9097 if (e) {
9098 goto funcdone;
9099 }
9100 INT_OFF;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009101 exception_handler = &jmploc;
9102 localvars = NULL;
Denis Vlasenko01631112007-12-16 17:20:38 +00009103 shellparam.malloced = 0;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009104 func->count++;
9105 funcnest++;
9106 INT_ON;
9107 shellparam.nparam = argc - 1;
9108 shellparam.p = argv + 1;
9109#if ENABLE_ASH_GETOPTS
9110 shellparam.optind = 1;
9111 shellparam.optoff = -1;
9112#endif
Denys Vlasenko7aec8682016-10-25 20:26:02 +02009113 evaltree(func->n.narg.next, flags & EV_TESTED);
Denis Vlasenko01631112007-12-16 17:20:38 +00009114 funcdone:
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009115 INT_OFF;
9116 funcnest--;
9117 freefunc(func);
9118 poplocalvars();
9119 localvars = savelocalvars;
9120 freeparam(&shellparam);
9121 shellparam = saveparam;
9122 exception_handler = savehandler;
9123 INT_ON;
9124 evalskip &= ~SKIPFUNC;
9125 return e;
9126}
9127
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009128/*
9129 * Make a variable a local variable. When a variable is made local, it's
9130 * value and flags are saved in a localvar structure. The saved values
9131 * will be restored when the shell function returns. We handle the name
Denys Vlasenkoe0a4e102015-05-13 02:20:14 +02009132 * "-" as a special case: it makes changes to "set +-options" local
9133 * (options will be restored on return from the function).
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009134 */
9135static void
9136mklocal(char *name)
9137{
9138 struct localvar *lvp;
9139 struct var **vpp;
9140 struct var *vp;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009141 char *eq = strchr(name, '=');
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009142
9143 INT_OFF;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009144 /* Cater for duplicate "local". Examples:
9145 * x=0; f() { local x=1; echo $x; local x; echo $x; }; f; echo $x
9146 * x=0; f() { local x=1; echo $x; local x=2; echo $x; }; f; echo $x
9147 */
9148 lvp = localvars;
9149 while (lvp) {
Eugene Rudoy1285aa62015-04-26 23:32:00 +02009150 if (lvp->vp && varcmp(lvp->vp->var_text, name) == 0) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009151 if (eq)
9152 setvareq(name, 0);
9153 /* else:
9154 * it's a duplicate "local VAR" declaration, do nothing
9155 */
Denys Vlasenko06b11492016-11-04 16:43:18 +01009156 goto ret;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009157 }
9158 lvp = lvp->next;
9159 }
9160
9161 lvp = ckzalloc(sizeof(*lvp));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009162 if (LONE_DASH(name)) {
9163 char *p;
9164 p = ckmalloc(sizeof(optlist));
9165 lvp->text = memcpy(p, optlist, sizeof(optlist));
9166 vp = NULL;
9167 } else {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009168 vpp = hashvar(name);
9169 vp = *findvar(vpp, name);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009170 if (vp == NULL) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009171 /* variable did not exist yet */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009172 if (eq)
9173 setvareq(name, VSTRFIXED);
9174 else
9175 setvar(name, NULL, VSTRFIXED);
9176 vp = *vpp; /* the new variable */
9177 lvp->flags = VUNSET;
9178 } else {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009179 lvp->text = vp->var_text;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009180 lvp->flags = vp->flags;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009181 /* make sure neither "struct var" nor string gets freed
9182 * during (un)setting:
9183 */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009184 vp->flags |= VSTRFIXED|VTEXTFIXED;
9185 if (eq)
9186 setvareq(name, 0);
Denys Vlasenko109ee5d2014-03-16 18:41:11 +01009187 else
9188 /* "local VAR" unsets VAR: */
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009189 setvar0(name, NULL);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009190 }
9191 }
9192 lvp->vp = vp;
9193 lvp->next = localvars;
9194 localvars = lvp;
Denys Vlasenko06b11492016-11-04 16:43:18 +01009195 ret:
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009196 INT_ON;
9197}
9198
9199/*
9200 * The "local" command.
9201 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009202static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009203localcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009204{
9205 char *name;
9206
Ron Yorstonef2386b2015-10-29 16:19:14 +00009207 if (!funcnest)
9208 ash_msg_and_raise_error("not in a function");
9209
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009210 argv = argptr;
9211 while ((name = *argv++) != NULL) {
9212 mklocal(name);
9213 }
9214 return 0;
9215}
9216
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009217static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009218falsecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009219{
9220 return 1;
9221}
9222
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009223static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009224truecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009225{
9226 return 0;
9227}
9228
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009229static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009230execcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009231{
Denis Vlasenko68404f12008-03-17 09:00:54 +00009232 if (argv[1]) {
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009233 iflag = 0; /* exit on error */
9234 mflag = 0;
9235 optschanged();
Denys Vlasenkoe5814a52016-07-16 18:33:55 +02009236 /* We should set up signals for "exec CMD"
9237 * the same way as for "CMD" without "exec".
9238 * But optschanged->setinteractive->setsignal
9239 * still thought we are a root shell. Therefore, for example,
9240 * SIGQUIT is still set to IGN. Fix it:
9241 */
9242 shlvl++;
9243 setsignal(SIGQUIT);
9244 /*setsignal(SIGTERM); - unnecessary because of iflag=0 */
9245 /*setsignal(SIGTSTP); - unnecessary because of mflag=0 */
9246 /*setsignal(SIGTTOU); - unnecessary because of mflag=0 */
9247
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009248 shellexec(argv + 1, pathval(), 0);
Denys Vlasenkoe5814a52016-07-16 18:33:55 +02009249 /* NOTREACHED */
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009250 }
9251 return 0;
9252}
9253
9254/*
9255 * The return command.
9256 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009257static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009258returncmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009259{
9260 /*
9261 * If called outside a function, do what ksh does;
9262 * skip the rest of the file.
9263 */
Denys Vlasenko6a0710e2016-09-30 14:18:34 +02009264 evalskip = SKIPFUNC;
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009265 return argv[1] ? number(argv[1]) : exitstatus;
9266}
9267
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009268/* Forward declarations for builtintab[] */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009269static int breakcmd(int, char **) FAST_FUNC;
9270static int dotcmd(int, char **) FAST_FUNC;
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009271static int evalcmd(int, char **, int) FAST_FUNC;
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009272static int exitcmd(int, char **) FAST_FUNC;
9273static int exportcmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009274#if ENABLE_ASH_GETOPTS
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009275static int getoptscmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009276#endif
Denys Vlasenko2ec34962014-09-08 16:52:39 +02009277#if ENABLE_ASH_HELP
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009278static int helpcmd(int, char **) FAST_FUNC;
Denis Vlasenko52764022007-02-24 13:42:56 +00009279#endif
Flemming Madsend96ffda2013-04-07 18:47:24 +02009280#if MAX_HISTORY
9281static int historycmd(int, char **) FAST_FUNC;
9282#endif
Denys Vlasenko0b883582016-12-23 16:49:07 +01009283#if ENABLE_FEATURE_SH_MATH
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009284static int letcmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009285#endif
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009286static int readcmd(int, char **) FAST_FUNC;
9287static int setcmd(int, char **) FAST_FUNC;
9288static int shiftcmd(int, char **) FAST_FUNC;
9289static int timescmd(int, char **) FAST_FUNC;
9290static int trapcmd(int, char **) FAST_FUNC;
9291static int umaskcmd(int, char **) FAST_FUNC;
9292static int unsetcmd(int, char **) FAST_FUNC;
9293static int ulimitcmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009294
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009295#define BUILTIN_NOSPEC "0"
9296#define BUILTIN_SPECIAL "1"
9297#define BUILTIN_REGULAR "2"
9298#define BUILTIN_SPEC_REG "3"
9299#define BUILTIN_ASSIGN "4"
9300#define BUILTIN_SPEC_ASSG "5"
9301#define BUILTIN_REG_ASSG "6"
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009302#define BUILTIN_SPEC_REG_ASSG "7"
9303
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009304/* Stubs for calling non-FAST_FUNC's */
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009305#if ENABLE_ASH_BUILTIN_ECHO
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009306static int FAST_FUNC echocmd(int argc, char **argv) { return echo_main(argc, argv); }
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009307#endif
9308#if ENABLE_ASH_BUILTIN_PRINTF
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009309static int FAST_FUNC printfcmd(int argc, char **argv) { return printf_main(argc, argv); }
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009310#endif
9311#if ENABLE_ASH_BUILTIN_TEST
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009312static int FAST_FUNC testcmd(int argc, char **argv) { return test_main(argc, argv); }
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009313#endif
Denis Vlasenko468aea22008-04-01 14:47:57 +00009314
Denis Vlasenkof7d56652008-03-25 05:51:41 +00009315/* Keep these in proper order since it is searched via bsearch() */
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009316static const struct builtincmd builtintab[] = {
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009317 { BUILTIN_SPEC_REG "." , dotcmd },
9318 { BUILTIN_SPEC_REG ":" , truecmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009319#if ENABLE_ASH_BUILTIN_TEST
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009320 { BUILTIN_REGULAR "[" , testcmd },
Denys Vlasenko15fb91c2016-11-23 18:31:48 +01009321# if ENABLE_ASH_BASH_COMPAT
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009322 { BUILTIN_REGULAR "[[" , testcmd },
Denys Vlasenko15fb91c2016-11-23 18:31:48 +01009323# endif
Denis Vlasenko80591b02008-03-25 07:49:43 +00009324#endif
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009325#if ENABLE_ASH_ALIAS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009326 { BUILTIN_REG_ASSG "alias" , aliascmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009327#endif
9328#if JOBS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009329 { BUILTIN_REGULAR "bg" , fg_bgcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009330#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009331 { BUILTIN_SPEC_REG "break" , breakcmd },
9332 { BUILTIN_REGULAR "cd" , cdcmd },
9333 { BUILTIN_NOSPEC "chdir" , cdcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009334#if ENABLE_ASH_CMDCMD
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009335 { BUILTIN_REGULAR "command" , commandcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009336#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009337 { BUILTIN_SPEC_REG "continue", breakcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009338#if ENABLE_ASH_BUILTIN_ECHO
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009339 { BUILTIN_REGULAR "echo" , echocmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009340#endif
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009341 { BUILTIN_SPEC_REG "eval" , NULL }, /*evalcmd() has a differing prototype*/
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009342 { BUILTIN_SPEC_REG "exec" , execcmd },
9343 { BUILTIN_SPEC_REG "exit" , exitcmd },
9344 { BUILTIN_SPEC_REG_ASSG "export" , exportcmd },
9345 { BUILTIN_REGULAR "false" , falsecmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009346#if JOBS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009347 { BUILTIN_REGULAR "fg" , fg_bgcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009348#endif
9349#if ENABLE_ASH_GETOPTS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009350 { BUILTIN_REGULAR "getopts" , getoptscmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009351#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009352 { BUILTIN_NOSPEC "hash" , hashcmd },
Denys Vlasenko2ec34962014-09-08 16:52:39 +02009353#if ENABLE_ASH_HELP
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009354 { BUILTIN_NOSPEC "help" , helpcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009355#endif
Flemming Madsend96ffda2013-04-07 18:47:24 +02009356#if MAX_HISTORY
9357 { BUILTIN_NOSPEC "history" , historycmd },
9358#endif
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009359#if JOBS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009360 { BUILTIN_REGULAR "jobs" , jobscmd },
9361 { BUILTIN_REGULAR "kill" , killcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009362#endif
Denys Vlasenko0b883582016-12-23 16:49:07 +01009363#if ENABLE_FEATURE_SH_MATH
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009364 { BUILTIN_NOSPEC "let" , letcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009365#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009366 { BUILTIN_ASSIGN "local" , localcmd },
Denis Vlasenkocd2663f2008-06-01 22:36:39 +00009367#if ENABLE_ASH_BUILTIN_PRINTF
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009368 { BUILTIN_REGULAR "printf" , printfcmd },
Denis Vlasenkocd2663f2008-06-01 22:36:39 +00009369#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009370 { BUILTIN_NOSPEC "pwd" , pwdcmd },
9371 { BUILTIN_REGULAR "read" , readcmd },
9372 { BUILTIN_SPEC_REG_ASSG "readonly", exportcmd },
9373 { BUILTIN_SPEC_REG "return" , returncmd },
9374 { BUILTIN_SPEC_REG "set" , setcmd },
9375 { BUILTIN_SPEC_REG "shift" , shiftcmd },
Denys Vlasenko82731b42010-05-17 17:49:52 +02009376#if ENABLE_ASH_BASH_COMPAT
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009377 { BUILTIN_SPEC_REG "source" , dotcmd },
Denys Vlasenko82731b42010-05-17 17:49:52 +02009378#endif
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009379#if ENABLE_ASH_BUILTIN_TEST
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009380 { BUILTIN_REGULAR "test" , testcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009381#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009382 { BUILTIN_SPEC_REG "times" , timescmd },
9383 { BUILTIN_SPEC_REG "trap" , trapcmd },
9384 { BUILTIN_REGULAR "true" , truecmd },
9385 { BUILTIN_NOSPEC "type" , typecmd },
9386 { BUILTIN_NOSPEC "ulimit" , ulimitcmd },
9387 { BUILTIN_REGULAR "umask" , umaskcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009388#if ENABLE_ASH_ALIAS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009389 { BUILTIN_REGULAR "unalias" , unaliascmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009390#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009391 { BUILTIN_SPEC_REG "unset" , unsetcmd },
9392 { BUILTIN_REGULAR "wait" , waitcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009393};
9394
Denis Vlasenko80591b02008-03-25 07:49:43 +00009395/* Should match the above table! */
9396#define COMMANDCMD (builtintab + \
Denys Vlasenko928e2a72016-09-29 00:30:31 +02009397 /* . : */ 2 + \
9398 /* [ */ 1 * ENABLE_ASH_BUILTIN_TEST + \
9399 /* [[ */ 1 * ENABLE_ASH_BUILTIN_TEST * ENABLE_ASH_BASH_COMPAT + \
9400 /* alias */ 1 * ENABLE_ASH_ALIAS + \
9401 /* bg */ 1 * ENABLE_ASH_JOB_CONTROL + \
9402 /* break cd cddir */ 3)
9403#define EVALCMD (COMMANDCMD + \
9404 /* command */ 1 * ENABLE_ASH_CMDCMD + \
9405 /* continue */ 1 + \
9406 /* echo */ 1 * ENABLE_ASH_BUILTIN_ECHO + \
9407 0)
9408#define EXECCMD (EVALCMD + \
9409 /* eval */ 1)
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009410
9411/*
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009412 * Search the table of builtin commands.
9413 */
Denys Vlasenko888527c2016-10-02 16:54:17 +02009414static int
9415pstrcmp1(const void *a, const void *b)
9416{
9417 return strcmp((char*)a, *(char**)b + 1);
9418}
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009419static struct builtincmd *
9420find_builtin(const char *name)
9421{
9422 struct builtincmd *bp;
9423
9424 bp = bsearch(
Denis Vlasenko80b8b392007-06-25 10:55:35 +00009425 name, builtintab, ARRAY_SIZE(builtintab), sizeof(builtintab[0]),
Denys Vlasenko888527c2016-10-02 16:54:17 +02009426 pstrcmp1
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009427 );
9428 return bp;
9429}
9430
9431/*
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009432 * Execute a simple command.
9433 */
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009434static int
9435isassignment(const char *p)
Paul Foxc3850c82005-07-20 18:23:39 +00009436{
9437 const char *q = endofname(p);
9438 if (p == q)
9439 return 0;
9440 return *q == '=';
9441}
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009442static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009443bltincmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009444{
9445 /* Preserve exitstatus of a previous possible redirection
9446 * as POSIX mandates */
9447 return back_exitstatus;
9448}
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009449static int
Eric Andersenc470f442003-07-28 09:56:35 +00009450evalcommand(union node *cmd, int flags)
9451{
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00009452 static const struct builtincmd null_bltin = {
9453 "\0\0", bltincmd /* why three NULs? */
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009454 };
Eric Andersenc470f442003-07-28 09:56:35 +00009455 struct stackmark smark;
9456 union node *argp;
9457 struct arglist arglist;
9458 struct arglist varlist;
9459 char **argv;
9460 int argc;
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009461 const struct strlist *sp;
Eric Andersenc470f442003-07-28 09:56:35 +00009462 struct cmdentry cmdentry;
9463 struct job *jp;
9464 char *lastarg;
9465 const char *path;
9466 int spclbltin;
Eric Andersenc470f442003-07-28 09:56:35 +00009467 int status;
9468 char **nargv;
Paul Foxc3850c82005-07-20 18:23:39 +00009469 struct builtincmd *bcmd;
Denis Vlasenko34c73c42008-08-16 11:48:02 +00009470 smallint cmd_is_exec;
9471 smallint pseudovarflag = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00009472
9473 /* First expand the arguments. */
9474 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
9475 setstackmark(&smark);
9476 back_exitstatus = 0;
9477
9478 cmdentry.cmdtype = CMDBUILTIN;
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00009479 cmdentry.u.cmd = &null_bltin;
Eric Andersenc470f442003-07-28 09:56:35 +00009480 varlist.lastp = &varlist.list;
9481 *varlist.lastp = NULL;
9482 arglist.lastp = &arglist.list;
9483 *arglist.lastp = NULL;
9484
9485 argc = 0;
Denis Vlasenkob012b102007-02-19 22:43:01 +00009486 if (cmd->ncmd.args) {
Paul Foxc3850c82005-07-20 18:23:39 +00009487 bcmd = find_builtin(cmd->ncmd.args->narg.text);
9488 pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd);
9489 }
9490
Eric Andersenc470f442003-07-28 09:56:35 +00009491 for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) {
9492 struct strlist **spp;
9493
9494 spp = arglist.lastp;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00009495 if (pseudovarflag && isassignment(argp->narg.text))
Paul Foxc3850c82005-07-20 18:23:39 +00009496 expandarg(argp, &arglist, EXP_VARTILDE);
9497 else
9498 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
9499
Eric Andersenc470f442003-07-28 09:56:35 +00009500 for (sp = *spp; sp; sp = sp->next)
9501 argc++;
9502 }
9503
Denys Vlasenko65a8b852016-10-26 22:29:11 +02009504 /* Reserve one extra spot at the front for shellexec. */
9505 nargv = stalloc(sizeof(char *) * (argc + 2));
9506 argv = ++nargv;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009507 for (sp = arglist.list; sp; sp = sp->next) {
Eric Andersenc470f442003-07-28 09:56:35 +00009508 TRACE(("evalcommand arg: %s\n", sp->text));
9509 *nargv++ = sp->text;
9510 }
9511 *nargv = NULL;
9512
9513 lastarg = NULL;
9514 if (iflag && funcnest == 0 && argc > 0)
9515 lastarg = nargv[-1];
9516
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009517 preverrout_fd = 2;
Eric Andersenc470f442003-07-28 09:56:35 +00009518 expredir(cmd->ncmd.redirect);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009519 status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH | REDIR_SAVEFD2);
Eric Andersenc470f442003-07-28 09:56:35 +00009520
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009521 path = vpath.var_text;
Eric Andersenc470f442003-07-28 09:56:35 +00009522 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
9523 struct strlist **spp;
9524 char *p;
9525
9526 spp = varlist.lastp;
9527 expandarg(argp, &varlist, EXP_VARTILDE);
9528
9529 /*
9530 * Modify the command lookup path, if a PATH= assignment
9531 * is present
9532 */
9533 p = (*spp)->text;
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009534 if (varcmp(p, path) == 0)
Eric Andersenc470f442003-07-28 09:56:35 +00009535 path = p;
9536 }
9537
9538 /* Print the command if xflag is set. */
9539 if (xflag) {
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009540 int n;
Denys Vlasenkofd33e172010-06-26 22:55:44 +02009541 const char *p = " %s" + 1;
Eric Andersenc470f442003-07-28 09:56:35 +00009542
Denis Vlasenko0de37e12007-10-17 11:08:53 +00009543 fdprintf(preverrout_fd, p, expandstr(ps4val()));
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009544 sp = varlist.list;
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +00009545 for (n = 0; n < 2; n++) {
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009546 while (sp) {
Denis Vlasenko0de37e12007-10-17 11:08:53 +00009547 fdprintf(preverrout_fd, p, sp->text);
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009548 sp = sp->next;
Denys Vlasenkofd33e172010-06-26 22:55:44 +02009549 p = " %s";
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009550 }
9551 sp = arglist.list;
9552 }
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00009553 safe_write(preverrout_fd, "\n", 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009554 }
9555
9556 cmd_is_exec = 0;
9557 spclbltin = -1;
9558
9559 /* Now locate the command. */
9560 if (argc) {
Eric Andersenc470f442003-07-28 09:56:35 +00009561 int cmd_flag = DO_ERR;
Denys Vlasenko0b4980c2012-09-25 12:49:29 +02009562#if ENABLE_ASH_CMDCMD
9563 const char *oldpath = path + 5;
9564#endif
Eric Andersenc470f442003-07-28 09:56:35 +00009565 path += 5;
Eric Andersenc470f442003-07-28 09:56:35 +00009566 for (;;) {
9567 find_command(argv[0], &cmdentry, cmd_flag, path);
9568 if (cmdentry.cmdtype == CMDUNKNOWN) {
Denys Vlasenko8131eea2009-11-02 14:19:51 +01009569 flush_stdout_stderr();
Denis Vlasenko6514c5e2008-07-24 13:41:37 +00009570 status = 127;
Eric Andersenc470f442003-07-28 09:56:35 +00009571 goto bail;
9572 }
9573
9574 /* implement bltin and command here */
9575 if (cmdentry.cmdtype != CMDBUILTIN)
9576 break;
9577 if (spclbltin < 0)
9578 spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd);
9579 if (cmdentry.u.cmd == EXECCMD)
Denis Vlasenko34c73c42008-08-16 11:48:02 +00009580 cmd_is_exec = 1;
Denis Vlasenko131ae172007-02-18 13:00:19 +00009581#if ENABLE_ASH_CMDCMD
Eric Andersenc470f442003-07-28 09:56:35 +00009582 if (cmdentry.u.cmd == COMMANDCMD) {
Eric Andersenc470f442003-07-28 09:56:35 +00009583 path = oldpath;
9584 nargv = parse_command_args(argv, &path);
9585 if (!nargv)
9586 break;
Denys Vlasenkocac4d002016-10-01 03:02:25 +02009587 /* It's "command [-p] PROG ARGS" (that is, no -Vv).
9588 * nargv => "PROG". path is updated if -p.
9589 */
Eric Andersenc470f442003-07-28 09:56:35 +00009590 argc -= nargv - argv;
9591 argv = nargv;
9592 cmd_flag |= DO_NOFUNC;
9593 } else
9594#endif
9595 break;
9596 }
9597 }
9598
9599 if (status) {
Ron Yorstonea7d2f62017-01-03 11:18:23 +01009600 bail:
9601 exitstatus = status;
9602
Eric Andersenc470f442003-07-28 09:56:35 +00009603 /* We have a redirection error. */
9604 if (spclbltin > 0)
Denis Vlasenkob012b102007-02-19 22:43:01 +00009605 raise_exception(EXERROR);
Ron Yorstonea7d2f62017-01-03 11:18:23 +01009606
Eric Andersenc470f442003-07-28 09:56:35 +00009607 goto out;
9608 }
9609
9610 /* Execute the command. */
9611 switch (cmdentry.cmdtype) {
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009612 default: {
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +00009613
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009614#if ENABLE_FEATURE_SH_NOFORK
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009615/* (1) BUG: if variables are set, we need to fork, or save/restore them
9616 * around run_nofork_applet() call.
9617 * (2) Should this check also be done in forkshell()?
9618 * (perhaps it should, so that "VAR=VAL nofork" at least avoids exec...)
9619 */
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00009620 /* find_command() encodes applet_no as (-2 - applet_no) */
9621 int applet_no = (- cmdentry.u.index - 2);
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009622 if (applet_no >= 0 && APPLET_IS_NOFORK(applet_no)) {
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009623 listsetvar(varlist.list, VEXPORT|VSTACK);
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00009624 /* run <applet>_main() */
Ron Yorston5ccb0e92016-10-20 12:24:02 +01009625 status = run_nofork_applet(applet_no, argv);
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009626 break;
9627 }
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009628#endif
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009629 /* Can we avoid forking off? For example, very last command
9630 * in a script or a subshell does not need forking,
9631 * we can just exec it.
9632 */
Denys Vlasenko238bf182010-05-18 15:49:07 +02009633 if (!(flags & EV_EXIT) || may_have_traps) {
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009634 /* No, forking off a child is necessary */
Denis Vlasenkob012b102007-02-19 22:43:01 +00009635 INT_OFF;
Denis Vlasenko68404f12008-03-17 09:00:54 +00009636 jp = makejob(/*cmd,*/ 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009637 if (forkshell(jp, cmd, FORK_FG) != 0) {
Denys Vlasenko238bf182010-05-18 15:49:07 +02009638 /* parent */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009639 status = waitforjob(jp);
Denis Vlasenkob012b102007-02-19 22:43:01 +00009640 INT_ON;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009641 TRACE(("forked child exited with %d\n", status));
Eric Andersenc470f442003-07-28 09:56:35 +00009642 break;
9643 }
Denys Vlasenko238bf182010-05-18 15:49:07 +02009644 /* child */
Denis Vlasenkob012b102007-02-19 22:43:01 +00009645 FORCE_INT_ON;
Denys Vlasenkoc7f95d22010-05-18 15:52:23 +02009646 /* fall through to exec'ing external program */
Eric Andersenc470f442003-07-28 09:56:35 +00009647 }
9648 listsetvar(varlist.list, VEXPORT|VSTACK);
9649 shellexec(argv, path, cmdentry.u.index);
9650 /* NOTREACHED */
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009651 } /* default */
Eric Andersenc470f442003-07-28 09:56:35 +00009652 case CMDBUILTIN:
9653 cmdenviron = varlist.list;
9654 if (cmdenviron) {
9655 struct strlist *list = cmdenviron;
9656 int i = VNOSET;
9657 if (spclbltin > 0 || argc == 0) {
9658 i = 0;
9659 if (cmd_is_exec && argc > 1)
9660 i = VEXPORT;
9661 }
9662 listsetvar(list, i);
9663 }
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +00009664 /* Tight loop with builtins only:
9665 * "while kill -0 $child; do true; done"
9666 * will never exit even if $child died, unless we do this
9667 * to reap the zombie and make kill detect that it's gone: */
9668 dowait(DOWAIT_NONBLOCK, NULL);
9669
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009670 if (evalbltin(cmdentry.u.cmd, argc, argv, flags)) {
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02009671 if (exception_type == EXERROR && spclbltin <= 0) {
9672 FORCE_INT_ON;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +02009673 goto readstatus;
Eric Andersenc470f442003-07-28 09:56:35 +00009674 }
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02009675 raise:
9676 longjmp(exception_handler->loc, 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009677 }
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009678 goto readstatus;
Eric Andersenc470f442003-07-28 09:56:35 +00009679
9680 case CMDFUNCTION:
9681 listsetvar(varlist.list, 0);
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +00009682 /* See above for the rationale */
9683 dowait(DOWAIT_NONBLOCK, NULL);
Eric Andersenc470f442003-07-28 09:56:35 +00009684 if (evalfun(cmdentry.u.func, argc, argv, flags))
9685 goto raise;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009686 readstatus:
9687 status = exitstatus;
Eric Andersenc470f442003-07-28 09:56:35 +00009688 break;
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009689 } /* switch */
Eric Andersenc470f442003-07-28 09:56:35 +00009690
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009691 out:
Denys Vlasenkoeaf94362016-10-25 21:46:03 +02009692 if (cmd->ncmd.redirect)
9693 popredir(/*drop:*/ cmd_is_exec, /*restore:*/ cmd_is_exec);
Denis Vlasenko6514c5e2008-07-24 13:41:37 +00009694 if (lastarg) {
Eric Andersenc470f442003-07-28 09:56:35 +00009695 /* dsl: I think this is intended to be used to support
9696 * '_' in 'vi' command mode during line editing...
9697 * However I implemented that within libedit itself.
9698 */
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009699 setvar0("_", lastarg);
Denis Vlasenko6514c5e2008-07-24 13:41:37 +00009700 }
Eric Andersenc470f442003-07-28 09:56:35 +00009701 popstackmark(&smark);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009702
9703 return status;
Eric Andersenc470f442003-07-28 09:56:35 +00009704}
9705
9706static int
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009707evalbltin(const struct builtincmd *cmd, int argc, char **argv, int flags)
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009708{
Eric Andersenc470f442003-07-28 09:56:35 +00009709 char *volatile savecmdname;
9710 struct jmploc *volatile savehandler;
9711 struct jmploc jmploc;
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009712 int status;
Eric Andersenc470f442003-07-28 09:56:35 +00009713 int i;
9714
9715 savecmdname = commandname;
Denys Vlasenkoa2d121c2016-09-30 11:30:11 +02009716 savehandler = exception_handler;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009717 i = setjmp(jmploc.loc);
9718 if (i)
Eric Andersenc470f442003-07-28 09:56:35 +00009719 goto cmddone;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009720 exception_handler = &jmploc;
Eric Andersenc470f442003-07-28 09:56:35 +00009721 commandname = argv[0];
9722 argptr = argv + 1;
9723 optptr = NULL; /* initialize nextopt */
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009724 if (cmd == EVALCMD)
9725 status = evalcmd(argc, argv, flags);
9726 else
9727 status = (*cmd->builtin)(argc, argv);
Denis Vlasenkob012b102007-02-19 22:43:01 +00009728 flush_stdout_stderr();
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009729 status |= ferror(stdout);
9730 exitstatus = status;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009731 cmddone:
Rob Landleyf296f0b2006-07-06 01:09:21 +00009732 clearerr(stdout);
Eric Andersenc470f442003-07-28 09:56:35 +00009733 commandname = savecmdname;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009734 exception_handler = savehandler;
Eric Andersenc470f442003-07-28 09:56:35 +00009735
9736 return i;
9737}
9738
Denis Vlasenkoaa744452007-02-23 01:04:22 +00009739static int
9740goodname(const char *p)
Glenn L McGrath16e45d72004-02-04 08:24:39 +00009741{
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02009742 return endofname(p)[0] == '\0';
Glenn L McGrath16e45d72004-02-04 08:24:39 +00009743}
9744
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009745
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009746/*
9747 * Search for a command. This is called before we fork so that the
9748 * location of the command will be available in the parent as well as
Glenn L McGrath16e45d72004-02-04 08:24:39 +00009749 * the child. The check for "goodname" is an overly conservative
9750 * check that the name will not be subject to expansion.
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009751 */
Eric Andersenc470f442003-07-28 09:56:35 +00009752static void
9753prehash(union node *n)
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009754{
9755 struct cmdentry entry;
9756
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +00009757 if (n->type == NCMD && n->ncmd.args && goodname(n->ncmd.args->narg.text))
9758 find_command(n->ncmd.args->narg.text, &entry, 0, pathval());
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009759}
9760
Eric Andersencb57d552001-06-28 07:25:16 +00009761
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009762/* ============ Builtin commands
9763 *
9764 * Builtin commands whose functions are closely tied to evaluation
9765 * are implemented here.
Eric Andersencb57d552001-06-28 07:25:16 +00009766 */
9767
9768/*
Eric Andersencb57d552001-06-28 07:25:16 +00009769 * Handle break and continue commands. Break, continue, and return are
9770 * all handled by setting the evalskip flag. The evaluation routines
9771 * above all check this flag, and if it is set they start skipping
9772 * commands rather than executing them. The variable skipcount is
9773 * the number of loops to break/continue, or the number of function
9774 * levels to return. (The latter is always 1.) It should probably
9775 * be an error to break out of more loops than exist, but it isn't
9776 * in the standard shell so we don't make it one here.
9777 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009778static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009779breakcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00009780{
Denis Vlasenko68404f12008-03-17 09:00:54 +00009781 int n = argv[1] ? number(argv[1]) : 1;
Eric Andersencb57d552001-06-28 07:25:16 +00009782
Aaron Lehmann2aef3a62001-12-31 06:03:12 +00009783 if (n <= 0)
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02009784 ash_msg_and_raise_error(msg_illnum, argv[1]);
Eric Andersencb57d552001-06-28 07:25:16 +00009785 if (n > loopnest)
9786 n = loopnest;
9787 if (n > 0) {
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009788 evalskip = (**argv == 'c') ? SKIPCONT : SKIPBREAK;
Eric Andersencb57d552001-06-28 07:25:16 +00009789 skipcount = n;
9790 }
9791 return 0;
9792}
9793
Eric Andersenc470f442003-07-28 09:56:35 +00009794
Denys Vlasenko70392332016-10-27 02:31:55 +02009795/*
Eric Andersen90898442003-08-06 11:20:52 +00009796 * This implements the input routines used by the parser.
Eric Andersencb57d552001-06-28 07:25:16 +00009797 */
Denis Vlasenko99eb8502007-02-23 21:09:49 +00009798
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009799enum {
9800 INPUT_PUSH_FILE = 1,
9801 INPUT_NOFILE_OK = 2,
9802};
Eric Andersencb57d552001-06-28 07:25:16 +00009803
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009804static smallint checkkwd;
Denis Vlasenko99eb8502007-02-23 21:09:49 +00009805/* values of checkkwd variable */
9806#define CHKALIAS 0x1
9807#define CHKKWD 0x2
9808#define CHKNL 0x4
9809
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009810/*
9811 * Push a string back onto the input at this current parsefile level.
9812 * We handle aliases this way.
9813 */
9814#if !ENABLE_ASH_ALIAS
9815#define pushstring(s, ap) pushstring(s)
9816#endif
9817static void
9818pushstring(char *s, struct alias *ap)
9819{
9820 struct strpush *sp;
9821 int len;
9822
9823 len = strlen(s);
9824 INT_OFF;
9825 if (g_parsefile->strpush) {
9826 sp = ckzalloc(sizeof(*sp));
9827 sp->prev = g_parsefile->strpush;
9828 } else {
9829 sp = &(g_parsefile->basestrpush);
9830 }
9831 g_parsefile->strpush = sp;
9832 sp->prev_string = g_parsefile->next_to_pgetc;
9833 sp->prev_left_in_line = g_parsefile->left_in_line;
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02009834 sp->unget = g_parsefile->unget;
9835 memcpy(sp->lastc, g_parsefile->lastc, sizeof(sp->lastc));
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009836#if ENABLE_ASH_ALIAS
9837 sp->ap = ap;
9838 if (ap) {
9839 ap->flag |= ALIASINUSE;
9840 sp->string = s;
9841 }
9842#endif
9843 g_parsefile->next_to_pgetc = s;
9844 g_parsefile->left_in_line = len;
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02009845 g_parsefile->unget = 0;
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009846 INT_ON;
9847}
9848
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009849static void
9850popstring(void)
Eric Andersenc470f442003-07-28 09:56:35 +00009851{
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009852 struct strpush *sp = g_parsefile->strpush;
Eric Andersenc470f442003-07-28 09:56:35 +00009853
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009854 INT_OFF;
Denis Vlasenko131ae172007-02-18 13:00:19 +00009855#if ENABLE_ASH_ALIAS
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009856 if (sp->ap) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009857 if (g_parsefile->next_to_pgetc[-1] == ' '
9858 || g_parsefile->next_to_pgetc[-1] == '\t'
9859 ) {
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009860 checkkwd |= CHKALIAS;
Glenn L McGrath28939ad2004-07-21 10:20:19 +00009861 }
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009862 if (sp->string != sp->ap->val) {
9863 free(sp->string);
9864 }
9865 sp->ap->flag &= ~ALIASINUSE;
9866 if (sp->ap->flag & ALIASDEAD) {
9867 unalias(sp->ap->name);
9868 }
Glenn L McGrath28939ad2004-07-21 10:20:19 +00009869 }
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00009870#endif
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009871 g_parsefile->next_to_pgetc = sp->prev_string;
9872 g_parsefile->left_in_line = sp->prev_left_in_line;
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02009873 g_parsefile->unget = sp->unget;
9874 memcpy(g_parsefile->lastc, sp->lastc, sizeof(sp->lastc));
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009875 g_parsefile->strpush = sp->prev;
9876 if (sp != &(g_parsefile->basestrpush))
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009877 free(sp);
9878 INT_ON;
9879}
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00009880
Denis Vlasenkoaa744452007-02-23 01:04:22 +00009881static int
9882preadfd(void)
Eric Andersencb57d552001-06-28 07:25:16 +00009883{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009884 int nr;
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00009885 char *buf = g_parsefile->buf;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009886
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009887 g_parsefile->next_to_pgetc = buf;
Denis Vlasenko38f63192007-01-22 09:03:07 +00009888#if ENABLE_FEATURE_EDITING
Denis Vlasenko85c24712008-03-17 09:04:04 +00009889 retry:
Denys Vlasenko79b3d422010-06-03 04:29:08 +02009890 if (!iflag || g_parsefile->pf_fd != STDIN_FILENO)
Ron Yorston61d6ae22015-04-19 10:50:25 +01009891 nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009892 else {
Denys Vlasenko66c5b122011-02-08 05:07:02 +01009893 int timeout = -1;
9894# if ENABLE_ASH_IDLE_TIMEOUT
9895 if (iflag) {
9896 const char *tmout_var = lookupvar("TMOUT");
9897 if (tmout_var) {
9898 timeout = atoi(tmout_var) * 1000;
9899 if (timeout <= 0)
9900 timeout = -1;
9901 }
9902 }
9903# endif
Denys Vlasenko8c52f802011-02-04 17:36:21 +01009904# if ENABLE_FEATURE_TAB_COMPLETION
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00009905 line_input_state->path_lookup = pathval();
Denys Vlasenko8c52f802011-02-04 17:36:21 +01009906# endif
Denys Vlasenkoe9ab07c2014-08-13 18:00:08 +02009907 reinit_unicode_for_ash();
Denys Vlasenko66c5b122011-02-08 05:07:02 +01009908 nr = read_line_input(line_input_state, cmdedit_prompt, buf, IBUFSIZ, timeout);
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00009909 if (nr == 0) {
Denys Vlasenko4b89d512016-11-25 03:41:03 +01009910 /* ^C pressed, "convert" to SIGINT */
9911 write(STDOUT_FILENO, "^C", 2);
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00009912 if (trap[SIGINT]) {
Glenn L McGrath16e45d72004-02-04 08:24:39 +00009913 buf[0] = '\n';
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00009914 buf[1] = '\0';
Glenn L McGrath16e45d72004-02-04 08:24:39 +00009915 raise(SIGINT);
9916 return 1;
9917 }
Denys Vlasenko8660aeb2016-11-24 17:44:02 +01009918 exitstatus = 128 + SIGINT;
Denys Vlasenko4b89d512016-11-25 03:41:03 +01009919 bb_putchar('\n');
Eric Andersenc470f442003-07-28 09:56:35 +00009920 goto retry;
9921 }
Denys Vlasenko66c5b122011-02-08 05:07:02 +01009922 if (nr < 0) {
9923 if (errno == 0) {
9924 /* Ctrl+D pressed */
9925 nr = 0;
9926 }
9927# if ENABLE_ASH_IDLE_TIMEOUT
9928 else if (errno == EAGAIN && timeout > 0) {
Denys Vlasenkod60752f2015-10-07 22:42:45 +02009929 puts("\007timed out waiting for input: auto-logout");
Denys Vlasenko66c5b122011-02-08 05:07:02 +01009930 exitshell();
9931 }
9932# endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009933 }
Eric Andersencb57d552001-06-28 07:25:16 +00009934 }
9935#else
Ron Yorston61d6ae22015-04-19 10:50:25 +01009936 nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1);
Eric Andersencb57d552001-06-28 07:25:16 +00009937#endif
9938
Denys Vlasenko80c5b682011-05-08 21:21:10 +02009939#if 0 /* disabled: nonblock_immune_read() handles this problem */
Eric Andersencb57d552001-06-28 07:25:16 +00009940 if (nr < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00009941 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
Denis Vlasenkod37f2222007-08-19 13:42:08 +00009942 int flags = fcntl(0, F_GETFL);
Denis Vlasenko9cb220b2007-12-09 10:03:28 +00009943 if (flags >= 0 && (flags & O_NONBLOCK)) {
9944 flags &= ~O_NONBLOCK;
Eric Andersencb57d552001-06-28 07:25:16 +00009945 if (fcntl(0, F_SETFL, flags) >= 0) {
9946 out2str("sh: turning off NDELAY mode\n");
9947 goto retry;
9948 }
9949 }
9950 }
9951 }
Denis Vlasenkoe376d452008-02-20 22:23:24 +00009952#endif
Eric Andersencb57d552001-06-28 07:25:16 +00009953 return nr;
9954}
9955
9956/*
9957 * Refill the input buffer and return the next input character:
9958 *
9959 * 1) If a string was pushed back on the input, pop it;
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009960 * 2) If an EOF was pushed back (g_parsefile->left_in_line < -BIGNUM)
9961 * or we are reading from a string so we can't refill the buffer,
9962 * return EOF.
Denys Vlasenko883cea42009-07-11 15:31:59 +02009963 * 3) If there is more stuff in this buffer, use it else call read to fill it.
Eric Andersencb57d552001-06-28 07:25:16 +00009964 * 4) Process input up to the next newline, deleting nul characters.
9965 */
Denis Vlasenko727752d2008-11-28 03:41:47 +00009966//#define pgetc_debug(...) bb_error_msg(__VA_ARGS__)
9967#define pgetc_debug(...) ((void)0)
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02009968static int pgetc(void);
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009969static int
Eric Andersenc470f442003-07-28 09:56:35 +00009970preadbuffer(void)
Eric Andersencb57d552001-06-28 07:25:16 +00009971{
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009972 char *q;
Eric Andersencb57d552001-06-28 07:25:16 +00009973 int more;
Eric Andersencb57d552001-06-28 07:25:16 +00009974
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02009975 if (g_parsefile->strpush) {
Denis Vlasenko131ae172007-02-18 13:00:19 +00009976#if ENABLE_ASH_ALIAS
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009977 if (g_parsefile->left_in_line == -1
9978 && g_parsefile->strpush->ap
9979 && g_parsefile->next_to_pgetc[-1] != ' '
9980 && g_parsefile->next_to_pgetc[-1] != '\t'
Denis Vlasenko16898402008-11-25 01:34:52 +00009981 ) {
Denis Vlasenko727752d2008-11-28 03:41:47 +00009982 pgetc_debug("preadbuffer PEOA");
Eric Andersencb57d552001-06-28 07:25:16 +00009983 return PEOA;
9984 }
Eric Andersen2870d962001-07-02 17:27:21 +00009985#endif
Eric Andersencb57d552001-06-28 07:25:16 +00009986 popstring();
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02009987 return pgetc();
Eric Andersencb57d552001-06-28 07:25:16 +00009988 }
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009989 /* on both branches above g_parsefile->left_in_line < 0.
Denis Vlasenko727752d2008-11-28 03:41:47 +00009990 * "pgetc" needs refilling.
9991 */
9992
Denis Vlasenkoe27dafd2008-11-28 04:01:03 +00009993 /* -90 is our -BIGNUM. Below we use -99 to mark "EOF on read",
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009994 * pungetc() may increment it a few times.
Denis Vlasenkoe27dafd2008-11-28 04:01:03 +00009995 * Assuming it won't increment it to less than -90.
Denis Vlasenko727752d2008-11-28 03:41:47 +00009996 */
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009997 if (g_parsefile->left_in_line < -90 || g_parsefile->buf == NULL) {
Denis Vlasenko727752d2008-11-28 03:41:47 +00009998 pgetc_debug("preadbuffer PEOF1");
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009999 /* even in failure keep left_in_line and next_to_pgetc
10000 * in lock step, for correct multi-layer pungetc.
10001 * left_in_line was decremented before preadbuffer(),
10002 * must inc next_to_pgetc: */
10003 g_parsefile->next_to_pgetc++;
Eric Andersencb57d552001-06-28 07:25:16 +000010004 return PEOF;
Denis Vlasenko727752d2008-11-28 03:41:47 +000010005 }
Eric Andersencb57d552001-06-28 07:25:16 +000010006
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010007 more = g_parsefile->left_in_buffer;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010008 if (more <= 0) {
Denis Vlasenko727752d2008-11-28 03:41:47 +000010009 flush_stdout_stderr();
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010010 again:
10011 more = preadfd();
10012 if (more <= 0) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010013 /* don't try reading again */
10014 g_parsefile->left_in_line = -99;
Denis Vlasenko727752d2008-11-28 03:41:47 +000010015 pgetc_debug("preadbuffer PEOF2");
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010016 g_parsefile->next_to_pgetc++;
Eric Andersencb57d552001-06-28 07:25:16 +000010017 return PEOF;
10018 }
10019 }
10020
Denis Vlasenko727752d2008-11-28 03:41:47 +000010021 /* Find out where's the end of line.
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010022 * Set g_parsefile->left_in_line
10023 * and g_parsefile->left_in_buffer acordingly.
Denis Vlasenko727752d2008-11-28 03:41:47 +000010024 * NUL chars are deleted.
10025 */
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010026 q = g_parsefile->next_to_pgetc;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010027 for (;;) {
Denis Vlasenko727752d2008-11-28 03:41:47 +000010028 char c;
Eric Andersencb57d552001-06-28 07:25:16 +000010029
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010030 more--;
Eric Andersenc470f442003-07-28 09:56:35 +000010031
Denis Vlasenko727752d2008-11-28 03:41:47 +000010032 c = *q;
10033 if (c == '\0') {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010034 memmove(q, q + 1, more);
Denis Vlasenko727752d2008-11-28 03:41:47 +000010035 } else {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010036 q++;
10037 if (c == '\n') {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010038 g_parsefile->left_in_line = q - g_parsefile->next_to_pgetc - 1;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010039 break;
10040 }
Eric Andersencb57d552001-06-28 07:25:16 +000010041 }
10042
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010043 if (more <= 0) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010044 g_parsefile->left_in_line = q - g_parsefile->next_to_pgetc - 1;
10045 if (g_parsefile->left_in_line < 0)
Eric Andersencb57d552001-06-28 07:25:16 +000010046 goto again;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010047 break;
Eric Andersencb57d552001-06-28 07:25:16 +000010048 }
10049 }
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010050 g_parsefile->left_in_buffer = more;
Eric Andersencb57d552001-06-28 07:25:16 +000010051
Eric Andersencb57d552001-06-28 07:25:16 +000010052 if (vflag) {
Denis Vlasenko727752d2008-11-28 03:41:47 +000010053 char save = *q;
10054 *q = '\0';
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010055 out2str(g_parsefile->next_to_pgetc);
Denis Vlasenko727752d2008-11-28 03:41:47 +000010056 *q = save;
Eric Andersencb57d552001-06-28 07:25:16 +000010057 }
10058
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010059 pgetc_debug("preadbuffer at %d:%p'%s'",
10060 g_parsefile->left_in_line,
10061 g_parsefile->next_to_pgetc,
10062 g_parsefile->next_to_pgetc);
Denys Vlasenkocd716832009-11-28 22:14:02 +010010063 return (unsigned char)*g_parsefile->next_to_pgetc++;
Eric Andersencb57d552001-06-28 07:25:16 +000010064}
10065
Denys Vlasenkoce332a22016-10-02 23:47:34 +020010066static void
10067nlprompt(void)
10068{
10069 g_parsefile->linno++;
10070 setprompt_if(doprompt, 2);
10071}
10072static void
10073nlnoprompt(void)
10074{
10075 g_parsefile->linno++;
10076 needprompt = doprompt;
10077}
10078
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010079static int
10080pgetc(void)
10081{
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010082 int c;
10083
10084 pgetc_debug("pgetc at %d:%p'%s'",
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010085 g_parsefile->left_in_line,
10086 g_parsefile->next_to_pgetc,
10087 g_parsefile->next_to_pgetc);
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010088 if (g_parsefile->unget)
10089 return g_parsefile->lastc[--g_parsefile->unget];
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010090
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010091 if (--g_parsefile->left_in_line >= 0)
Denys Vlasenko2fe66b12016-12-12 17:39:12 +010010092 c = (unsigned char)*g_parsefile->next_to_pgetc++;
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010093 else
10094 c = preadbuffer();
10095
10096 g_parsefile->lastc[1] = g_parsefile->lastc[0];
10097 g_parsefile->lastc[0] = c;
10098
10099 return c;
10100}
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010101
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010102#if ENABLE_ASH_ALIAS
10103static int
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010010104pgetc_without_PEOA(void)
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010105{
10106 int c;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010107 do {
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010108 pgetc_debug("pgetc at %d:%p'%s'",
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010109 g_parsefile->left_in_line,
10110 g_parsefile->next_to_pgetc,
10111 g_parsefile->next_to_pgetc);
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010112 c = pgetc();
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010113 } while (c == PEOA);
10114 return c;
10115}
10116#else
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010010117# define pgetc_without_PEOA() pgetc()
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010118#endif
10119
10120/*
10121 * Read a line from the script.
10122 */
10123static char *
10124pfgets(char *line, int len)
10125{
10126 char *p = line;
10127 int nleft = len;
10128 int c;
10129
10130 while (--nleft > 0) {
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010010131 c = pgetc_without_PEOA();
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010132 if (c == PEOF) {
10133 if (p == line)
10134 return NULL;
10135 break;
10136 }
10137 *p++ = c;
10138 if (c == '\n')
10139 break;
10140 }
10141 *p = '\0';
10142 return line;
10143}
10144
Eric Andersenc470f442003-07-28 09:56:35 +000010145/*
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010146 * Undo a call to pgetc. Only two characters may be pushed back.
Eric Andersenc470f442003-07-28 09:56:35 +000010147 * PEOF may be pushed back.
10148 */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010149static void
Eric Andersenc470f442003-07-28 09:56:35 +000010150pungetc(void)
10151{
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010152 g_parsefile->unget++;
Eric Andersencb57d552001-06-28 07:25:16 +000010153}
10154
Denys Vlasenko73c3e072016-09-29 17:17:04 +020010155/* This one eats backslash+newline */
10156static int
10157pgetc_eatbnl(void)
10158{
10159 int c;
10160
10161 while ((c = pgetc()) == '\\') {
10162 if (pgetc() != '\n') {
10163 pungetc();
10164 break;
10165 }
10166
Denys Vlasenkoce332a22016-10-02 23:47:34 +020010167 nlprompt();
Denys Vlasenko73c3e072016-09-29 17:17:04 +020010168 }
10169
10170 return c;
10171}
10172
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010173/*
10174 * To handle the "." command, a stack of input files is used. Pushfile
10175 * adds a new entry to the stack and popfile restores the previous level.
10176 */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010177static void
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010178pushfile(void)
Eric Andersenc470f442003-07-28 09:56:35 +000010179{
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010180 struct parsefile *pf;
10181
Denis Vlasenko597906c2008-02-20 16:38:54 +000010182 pf = ckzalloc(sizeof(*pf));
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010183 pf->prev = g_parsefile;
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010184 pf->pf_fd = -1;
Denis Vlasenko597906c2008-02-20 16:38:54 +000010185 /*pf->strpush = NULL; - ckzalloc did it */
10186 /*pf->basestrpush.prev = NULL;*/
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010187 /*pf->unget = 0;*/
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010188 g_parsefile = pf;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010189}
10190
10191static void
10192popfile(void)
10193{
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010194 struct parsefile *pf = g_parsefile;
Eric Andersenc470f442003-07-28 09:56:35 +000010195
Denys Vlasenko493b9ca2016-10-30 18:27:14 +010010196 if (pf == &basepf)
10197 return;
10198
Denis Vlasenkob012b102007-02-19 22:43:01 +000010199 INT_OFF;
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010200 if (pf->pf_fd >= 0)
10201 close(pf->pf_fd);
Denis Vlasenko60818682007-09-28 22:07:23 +000010202 free(pf->buf);
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010203 while (pf->strpush)
10204 popstring();
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010205 g_parsefile = pf->prev;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010206 free(pf);
Denis Vlasenkob012b102007-02-19 22:43:01 +000010207 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +000010208}
10209
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010210/*
10211 * Return to top level.
10212 */
10213static void
10214popallfiles(void)
10215{
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010216 while (g_parsefile != &basepf)
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010217 popfile();
10218}
10219
10220/*
10221 * Close the file(s) that the shell is reading commands from. Called
10222 * after a fork is done.
10223 */
10224static void
10225closescript(void)
10226{
10227 popallfiles();
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010228 if (g_parsefile->pf_fd > 0) {
10229 close(g_parsefile->pf_fd);
10230 g_parsefile->pf_fd = 0;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010231 }
10232}
10233
10234/*
10235 * Like setinputfile, but takes an open file descriptor. Call this with
10236 * interrupts off.
10237 */
10238static void
10239setinputfd(int fd, int push)
10240{
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010241 if (push) {
10242 pushfile();
Denis Vlasenko727752d2008-11-28 03:41:47 +000010243 g_parsefile->buf = NULL;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010244 }
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010245 g_parsefile->pf_fd = fd;
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010246 if (g_parsefile->buf == NULL)
10247 g_parsefile->buf = ckmalloc(IBUFSIZ);
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010248 g_parsefile->left_in_buffer = 0;
10249 g_parsefile->left_in_line = 0;
10250 g_parsefile->linno = 1;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010251}
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010252
Eric Andersenc470f442003-07-28 09:56:35 +000010253/*
10254 * Set the input to take input from a file. If push is set, push the
10255 * old input onto the stack first.
10256 */
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010257static int
10258setinputfile(const char *fname, int flags)
Eric Andersenc470f442003-07-28 09:56:35 +000010259{
10260 int fd;
Eric Andersenc470f442003-07-28 09:56:35 +000010261
Denis Vlasenkob012b102007-02-19 22:43:01 +000010262 INT_OFF;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010263 fd = open(fname, O_RDONLY);
10264 if (fd < 0) {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010265 if (flags & INPUT_NOFILE_OK)
10266 goto out;
Denys Vlasenkob7adf7a2016-10-25 17:00:13 +020010267 exitstatus = 127;
Denis Vlasenko9604e1b2009-03-03 18:47:56 +000010268 ash_msg_and_raise_error("can't open '%s'", fname);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010269 }
Denys Vlasenko64774602016-10-26 15:24:30 +020010270 if (fd < 10)
10271 fd = savefd(fd);
Denys Vlasenkoe19923f2016-10-26 15:38:44 +020010272 else
10273 close_on_exec_on(fd);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010274 setinputfd(fd, flags & INPUT_PUSH_FILE);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010275 out:
Denis Vlasenkob012b102007-02-19 22:43:01 +000010276 INT_ON;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010277 return fd;
Eric Andersenc470f442003-07-28 09:56:35 +000010278}
10279
Eric Andersencb57d552001-06-28 07:25:16 +000010280/*
10281 * Like setinputfile, but takes input from a string.
10282 */
Eric Andersenc470f442003-07-28 09:56:35 +000010283static void
10284setinputstring(char *string)
Eric Andersen62483552001-07-10 06:09:16 +000010285{
Denis Vlasenkob012b102007-02-19 22:43:01 +000010286 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +000010287 pushfile();
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010288 g_parsefile->next_to_pgetc = string;
10289 g_parsefile->left_in_line = strlen(string);
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010290 g_parsefile->buf = NULL;
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010291 g_parsefile->linno = 1;
Denis Vlasenkob012b102007-02-19 22:43:01 +000010292 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +000010293}
10294
10295
Denys Vlasenko70392332016-10-27 02:31:55 +020010296/*
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010297 * Routines to check for mail.
Eric Andersencb57d552001-06-28 07:25:16 +000010298 */
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010299
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010300#if ENABLE_ASH_MAIL
Eric Andersencb57d552001-06-28 07:25:16 +000010301
Denys Vlasenko23841622015-10-09 15:52:03 +020010302/* Hash of mtimes of mailboxes */
10303static unsigned mailtime_hash;
Eric Andersenc470f442003-07-28 09:56:35 +000010304/* Set if MAIL or MAILPATH is changed. */
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010305static smallint mail_var_path_changed;
Eric Andersencb57d552001-06-28 07:25:16 +000010306
Eric Andersencb57d552001-06-28 07:25:16 +000010307/*
Eric Andersenc470f442003-07-28 09:56:35 +000010308 * Print appropriate message(s) if mail has arrived.
10309 * If mail_var_path_changed is set,
10310 * then the value of MAIL has mail_var_path_changed,
10311 * so we just update the values.
Eric Andersencb57d552001-06-28 07:25:16 +000010312 */
Eric Andersenc470f442003-07-28 09:56:35 +000010313static void
10314chkmail(void)
Eric Andersencb57d552001-06-28 07:25:16 +000010315{
Eric Andersencb57d552001-06-28 07:25:16 +000010316 const char *mpath;
10317 char *p;
10318 char *q;
Denys Vlasenko23841622015-10-09 15:52:03 +020010319 unsigned new_hash;
Eric Andersencb57d552001-06-28 07:25:16 +000010320 struct stackmark smark;
10321 struct stat statb;
10322
Eric Andersencb57d552001-06-28 07:25:16 +000010323 setstackmark(&smark);
Eric Andersenc470f442003-07-28 09:56:35 +000010324 mpath = mpathset() ? mpathval() : mailval();
Denys Vlasenko23841622015-10-09 15:52:03 +020010325 new_hash = 0;
10326 for (;;) {
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020010327 p = path_advance(&mpath, nullstr);
Eric Andersencb57d552001-06-28 07:25:16 +000010328 if (p == NULL)
10329 break;
10330 if (*p == '\0')
10331 continue;
Denis Vlasenkof7d56652008-03-25 05:51:41 +000010332 for (q = p; *q; q++)
10333 continue;
Denis Vlasenkoa7189f02006-11-17 20:29:00 +000010334#if DEBUG
Eric Andersencb57d552001-06-28 07:25:16 +000010335 if (q[-1] != '/')
10336 abort();
10337#endif
Eric Andersenc470f442003-07-28 09:56:35 +000010338 q[-1] = '\0'; /* delete trailing '/' */
10339 if (stat(p, &statb) < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +000010340 continue;
Eric Andersencb57d552001-06-28 07:25:16 +000010341 }
Denys Vlasenko23841622015-10-09 15:52:03 +020010342 /* Very simplistic "hash": just a sum of all mtimes */
10343 new_hash += (unsigned)statb.st_mtime;
10344 }
10345 if (!mail_var_path_changed && mailtime_hash != new_hash) {
Denys Vlasenko4cd99e72015-10-09 16:02:53 +020010346 if (mailtime_hash != 0)
10347 out2str("you have mail\n");
Denys Vlasenko23841622015-10-09 15:52:03 +020010348 mailtime_hash = new_hash;
Eric Andersencb57d552001-06-28 07:25:16 +000010349 }
Eric Andersenc470f442003-07-28 09:56:35 +000010350 mail_var_path_changed = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010351 popstackmark(&smark);
10352}
Eric Andersencb57d552001-06-28 07:25:16 +000010353
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010354static void FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010355changemail(const char *val UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000010356{
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010357 mail_var_path_changed = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000010358}
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010359
Denis Vlasenko131ae172007-02-18 13:00:19 +000010360#endif /* ASH_MAIL */
Eric Andersenc470f442003-07-28 09:56:35 +000010361
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010362
10363/* ============ ??? */
10364
Eric Andersencb57d552001-06-28 07:25:16 +000010365/*
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010366 * Set the shell parameters.
Eric Andersencb57d552001-06-28 07:25:16 +000010367 */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010368static void
10369setparam(char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000010370{
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010371 char **newparam;
10372 char **ap;
10373 int nparam;
Eric Andersencb57d552001-06-28 07:25:16 +000010374
Denis Vlasenkof7d56652008-03-25 05:51:41 +000010375 for (nparam = 0; argv[nparam]; nparam++)
10376 continue;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010377 ap = newparam = ckmalloc((nparam + 1) * sizeof(*ap));
10378 while (*argv) {
10379 *ap++ = ckstrdup(*argv++);
Eric Andersencb57d552001-06-28 07:25:16 +000010380 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010381 *ap = NULL;
10382 freeparam(&shellparam);
Denis Vlasenko01631112007-12-16 17:20:38 +000010383 shellparam.malloced = 1;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010384 shellparam.nparam = nparam;
10385 shellparam.p = newparam;
10386#if ENABLE_ASH_GETOPTS
10387 shellparam.optind = 1;
10388 shellparam.optoff = -1;
10389#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010390}
10391
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010392/*
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010393 * Process shell options. The global variable argptr contains a pointer
10394 * to the argument list; we advance it past the options.
Denis Vlasenko94e87bc2008-02-14 16:51:58 +000010395 *
10396 * SUSv3 section 2.8.1 "Consequences of Shell Errors" says:
10397 * For a non-interactive shell, an error condition encountered
10398 * by a special built-in ... shall cause the shell to write a diagnostic message
10399 * to standard error and exit as shown in the following table:
Denis Vlasenko56244732008-02-17 15:14:04 +000010400 * Error Special Built-In
Denis Vlasenko94e87bc2008-02-14 16:51:58 +000010401 * ...
10402 * Utility syntax error (option or operand error) Shall exit
10403 * ...
10404 * However, in bug 1142 (http://busybox.net/bugs/view.php?id=1142)
10405 * we see that bash does not do that (set "finishes" with error code 1 instead,
10406 * and shell continues), and people rely on this behavior!
10407 * Testcase:
10408 * set -o barfoo 2>/dev/null
10409 * echo $?
10410 *
10411 * Oh well. Let's mimic that.
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010412 */
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010413static int
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010414plus_minus_o(char *name, int val)
Eric Andersen62483552001-07-10 06:09:16 +000010415{
10416 int i;
10417
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010418 if (name) {
10419 for (i = 0; i < NOPTS; i++) {
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000010420 if (strcmp(name, optnames(i)) == 0) {
Eric Andersenc470f442003-07-28 09:56:35 +000010421 optlist[i] = val;
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010422 return 0;
Eric Andersen62483552001-07-10 06:09:16 +000010423 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010424 }
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010425 ash_msg("illegal option %co %s", val ? '-' : '+', name);
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010426 return 1;
Eric Andersen62483552001-07-10 06:09:16 +000010427 }
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000010428 for (i = 0; i < NOPTS; i++) {
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010429 if (val) {
10430 out1fmt("%-16s%s\n", optnames(i), optlist[i] ? "on" : "off");
10431 } else {
10432 out1fmt("set %co %s\n", optlist[i] ? '-' : '+', optnames(i));
10433 }
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000010434 }
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010435 return 0;
Eric Andersen62483552001-07-10 06:09:16 +000010436}
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010437static void
10438setoption(int flag, int val)
10439{
10440 int i;
10441
10442 for (i = 0; i < NOPTS; i++) {
10443 if (optletters(i) == flag) {
10444 optlist[i] = val;
10445 return;
10446 }
10447 }
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010448 ash_msg_and_raise_error("illegal option %c%c", val ? '-' : '+', flag);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010449 /* NOTREACHED */
10450}
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010451static int
Eric Andersenc470f442003-07-28 09:56:35 +000010452options(int cmdline)
Eric Andersencb57d552001-06-28 07:25:16 +000010453{
10454 char *p;
10455 int val;
10456 int c;
10457
10458 if (cmdline)
10459 minusc = NULL;
10460 while ((p = *argptr) != NULL) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010461 c = *p++;
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010462 if (c != '-' && c != '+')
10463 break;
10464 argptr++;
10465 val = 0; /* val = 0 if c == '+' */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010466 if (c == '-') {
Eric Andersencb57d552001-06-28 07:25:16 +000010467 val = 1;
Denis Vlasenko9f739442006-12-16 23:49:13 +000010468 if (p[0] == '\0' || LONE_DASH(p)) {
Eric Andersen2870d962001-07-02 17:27:21 +000010469 if (!cmdline) {
10470 /* "-" means turn off -x and -v */
10471 if (p[0] == '\0')
10472 xflag = vflag = 0;
10473 /* "--" means reset params */
10474 else if (*argptr == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +000010475 setparam(argptr);
Eric Andersen2870d962001-07-02 17:27:21 +000010476 }
Denys Vlasenkob0b83432011-03-07 12:34:59 +010010477 break; /* "-" or "--" terminates options */
Eric Andersencb57d552001-06-28 07:25:16 +000010478 }
Eric Andersencb57d552001-06-28 07:25:16 +000010479 }
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010480 /* first char was + or - */
Eric Andersencb57d552001-06-28 07:25:16 +000010481 while ((c = *p++) != '\0') {
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010482 /* bash 3.2 indeed handles -c CMD and +c CMD the same */
Eric Andersencb57d552001-06-28 07:25:16 +000010483 if (c == 'c' && cmdline) {
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010484 minusc = p; /* command is after shell args */
Eric Andersencb57d552001-06-28 07:25:16 +000010485 } else if (c == 'o') {
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010486 if (plus_minus_o(*argptr, val)) {
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010487 /* it already printed err message */
10488 return 1; /* error */
10489 }
Eric Andersencb57d552001-06-28 07:25:16 +000010490 if (*argptr)
10491 argptr++;
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010492 } else if (cmdline && (c == 'l')) { /* -l or +l == --login */
10493 isloginsh = 1;
10494 /* bash does not accept +-login, we also won't */
10495 } else if (cmdline && val && (c == '-')) { /* long options */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010496 if (strcmp(p, "login") == 0)
Robert Griebl64f70cc2002-05-14 23:22:06 +000010497 isloginsh = 1;
10498 break;
Eric Andersencb57d552001-06-28 07:25:16 +000010499 } else {
10500 setoption(c, val);
10501 }
10502 }
10503 }
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010504 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010505}
10506
Eric Andersencb57d552001-06-28 07:25:16 +000010507/*
Eric Andersencb57d552001-06-28 07:25:16 +000010508 * The shift builtin command.
10509 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010510static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010511shiftcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000010512{
10513 int n;
10514 char **ap1, **ap2;
10515
10516 n = 1;
Denis Vlasenko68404f12008-03-17 09:00:54 +000010517 if (argv[1])
Eric Andersencb57d552001-06-28 07:25:16 +000010518 n = number(argv[1]);
10519 if (n > shellparam.nparam)
Denis Vlasenkoc90e1be2008-07-30 15:35:05 +000010520 n = 0; /* bash compat, was = shellparam.nparam; */
Denis Vlasenkob012b102007-02-19 22:43:01 +000010521 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +000010522 shellparam.nparam -= n;
Denis Vlasenko2da584f2007-02-19 22:44:05 +000010523 for (ap1 = shellparam.p; --n >= 0; ap1++) {
Denis Vlasenko01631112007-12-16 17:20:38 +000010524 if (shellparam.malloced)
Denis Vlasenkob012b102007-02-19 22:43:01 +000010525 free(*ap1);
Eric Andersencb57d552001-06-28 07:25:16 +000010526 }
10527 ap2 = shellparam.p;
Denis Vlasenkof7d56652008-03-25 05:51:41 +000010528 while ((*ap2++ = *ap1++) != NULL)
10529 continue;
Denis Vlasenko131ae172007-02-18 13:00:19 +000010530#if ENABLE_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +000010531 shellparam.optind = 1;
10532 shellparam.optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +000010533#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +000010534 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +000010535 return 0;
10536}
10537
Eric Andersencb57d552001-06-28 07:25:16 +000010538/*
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010539 * POSIX requires that 'set' (but not export or readonly) output the
10540 * variables in lexicographic order - by the locale's collating order (sigh).
10541 * Maybe we could keep them in an ordered balanced binary tree
10542 * instead of hashed lists.
10543 * For now just roll 'em through qsort for printing...
10544 */
10545static int
10546showvars(const char *sep_prefix, int on, int off)
10547{
10548 const char *sep;
10549 char **ep, **epend;
10550
10551 ep = listvars(on, off, &epend);
10552 qsort(ep, epend - ep, sizeof(char *), vpcmp);
10553
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010554 sep = *sep_prefix ? " " : sep_prefix;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010555
10556 for (; ep < epend; ep++) {
10557 const char *p;
10558 const char *q;
10559
10560 p = strchrnul(*ep, '=');
10561 q = nullstr;
10562 if (*p)
10563 q = single_quote(++p);
10564 out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
10565 }
10566 return 0;
10567}
10568
10569/*
Eric Andersencb57d552001-06-28 07:25:16 +000010570 * The set command builtin.
10571 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010572static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010573setcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +000010574{
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010575 int retval;
10576
Denis Vlasenko68404f12008-03-17 09:00:54 +000010577 if (!argv[1])
Eric Andersenc470f442003-07-28 09:56:35 +000010578 return showvars(nullstr, 0, VUNSET);
Denys Vlasenkob0b83432011-03-07 12:34:59 +010010579
Denis Vlasenkob012b102007-02-19 22:43:01 +000010580 INT_OFF;
Denys Vlasenkob0b83432011-03-07 12:34:59 +010010581 retval = options(/*cmdline:*/ 0);
10582 if (retval == 0) { /* if no parse error... */
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010583 optschanged();
10584 if (*argptr != NULL) {
10585 setparam(argptr);
10586 }
Eric Andersencb57d552001-06-28 07:25:16 +000010587 }
Denis Vlasenkob012b102007-02-19 22:43:01 +000010588 INT_ON;
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010589 return retval;
Eric Andersencb57d552001-06-28 07:25:16 +000010590}
10591
Denis Vlasenko131ae172007-02-18 13:00:19 +000010592#if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010593static void FAST_FUNC
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000010594change_random(const char *value)
Eric Andersenef02f822004-03-11 13:34:24 +000010595{
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020010596 uint32_t t;
10597
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000010598 if (value == NULL) {
Eric Andersen16767e22004-03-16 05:14:10 +000010599 /* "get", generate */
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020010600 t = next_random(&random_gen);
Eric Andersen16767e22004-03-16 05:14:10 +000010601 /* set without recursion */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +020010602 setvar(vrandom.var_text, utoa(t), VNOFUNC);
Eric Andersen16767e22004-03-16 05:14:10 +000010603 vrandom.flags &= ~VNOFUNC;
10604 } else {
10605 /* set/reset */
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020010606 t = strtoul(value, NULL, 10);
10607 INIT_RANDOM_T(&random_gen, (t ? t : 1), t);
Eric Andersen16767e22004-03-16 05:14:10 +000010608 }
Eric Andersenef02f822004-03-11 13:34:24 +000010609}
Eric Andersen16767e22004-03-16 05:14:10 +000010610#endif
10611
Denis Vlasenko131ae172007-02-18 13:00:19 +000010612#if ENABLE_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +000010613static int
Denys Vlasenko35c2a132016-10-26 17:34:26 +020010614getopts(char *optstr, char *optvar, char **optfirst)
Eric Andersencb57d552001-06-28 07:25:16 +000010615{
10616 char *p, *q;
10617 char c = '?';
10618 int done = 0;
Denys Vlasenko9c541002015-10-07 15:44:36 +020010619 char sbuf[2];
Eric Andersena48b0a32003-10-22 10:56:47 +000010620 char **optnext;
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010621 int ind = shellparam.optind;
10622 int off = shellparam.optoff;
Eric Andersencb57d552001-06-28 07:25:16 +000010623
Denys Vlasenko9c541002015-10-07 15:44:36 +020010624 sbuf[1] = '\0';
10625
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010626 shellparam.optind = -1;
10627 optnext = optfirst + ind - 1;
Eric Andersena48b0a32003-10-22 10:56:47 +000010628
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010629 if (ind <= 1 || off < 0 || (int)strlen(optnext[-1]) < off)
Eric Andersencb57d552001-06-28 07:25:16 +000010630 p = NULL;
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010631 else
10632 p = optnext[-1] + off;
Eric Andersencb57d552001-06-28 07:25:16 +000010633 if (p == NULL || *p == '\0') {
10634 /* Current word is done, advance */
Eric Andersencb57d552001-06-28 07:25:16 +000010635 p = *optnext;
10636 if (p == NULL || *p != '-' || *++p == '\0') {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010637 atend:
Eric Andersencb57d552001-06-28 07:25:16 +000010638 p = NULL;
10639 done = 1;
10640 goto out;
10641 }
10642 optnext++;
Denis Vlasenko9f739442006-12-16 23:49:13 +000010643 if (LONE_DASH(p)) /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +000010644 goto atend;
10645 }
10646
10647 c = *p++;
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +000010648 for (q = optstr; *q != c;) {
Eric Andersencb57d552001-06-28 07:25:16 +000010649 if (*q == '\0') {
10650 if (optstr[0] == ':') {
Denys Vlasenko9c541002015-10-07 15:44:36 +020010651 sbuf[0] = c;
10652 /*sbuf[1] = '\0'; - already is */
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010653 setvar0("OPTARG", sbuf);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010654 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010655 fprintf(stderr, "Illegal option -%c\n", c);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010656 unsetvar("OPTARG");
Eric Andersencb57d552001-06-28 07:25:16 +000010657 }
10658 c = '?';
Eric Andersenc470f442003-07-28 09:56:35 +000010659 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +000010660 }
10661 if (*++q == ':')
10662 q++;
10663 }
10664
10665 if (*++q == ':') {
10666 if (*p == '\0' && (p = *optnext) == NULL) {
10667 if (optstr[0] == ':') {
Denys Vlasenko9c541002015-10-07 15:44:36 +020010668 sbuf[0] = c;
10669 /*sbuf[1] = '\0'; - already is */
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010670 setvar0("OPTARG", sbuf);
Eric Andersencb57d552001-06-28 07:25:16 +000010671 c = ':';
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010672 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010673 fprintf(stderr, "No arg for -%c option\n", c);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010674 unsetvar("OPTARG");
Eric Andersencb57d552001-06-28 07:25:16 +000010675 c = '?';
10676 }
Eric Andersenc470f442003-07-28 09:56:35 +000010677 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +000010678 }
10679
10680 if (p == *optnext)
10681 optnext++;
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010682 setvar0("OPTARG", p);
Eric Andersencb57d552001-06-28 07:25:16 +000010683 p = NULL;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010684 } else
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010685 setvar0("OPTARG", nullstr);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010686 out:
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010687 ind = optnext - optfirst + 1;
10688 setvar("OPTIND", itoa(ind), VNOFUNC);
Denys Vlasenko9c541002015-10-07 15:44:36 +020010689 sbuf[0] = c;
10690 /*sbuf[1] = '\0'; - already is */
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010691 setvar0(optvar, sbuf);
10692
10693 shellparam.optoff = p ? p - *(optnext - 1) : -1;
10694 shellparam.optind = ind;
10695
Eric Andersencb57d552001-06-28 07:25:16 +000010696 return done;
10697}
Eric Andersenc470f442003-07-28 09:56:35 +000010698
10699/*
10700 * The getopts builtin. Shellparam.optnext points to the next argument
10701 * to be processed. Shellparam.optptr points to the next character to
10702 * be processed in the current argument. If shellparam.optnext is NULL,
10703 * then it's the first time getopts has been called.
10704 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010705static int FAST_FUNC
Eric Andersenc470f442003-07-28 09:56:35 +000010706getoptscmd(int argc, char **argv)
10707{
10708 char **optbase;
10709
10710 if (argc < 3)
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +000010711 ash_msg_and_raise_error("usage: getopts optstring var [arg]");
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010712 if (argc == 3) {
Eric Andersenc470f442003-07-28 09:56:35 +000010713 optbase = shellparam.p;
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010714 if ((unsigned)shellparam.optind > shellparam.nparam + 1) {
Eric Andersenc470f442003-07-28 09:56:35 +000010715 shellparam.optind = 1;
10716 shellparam.optoff = -1;
10717 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010718 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010719 optbase = &argv[3];
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010720 if ((unsigned)shellparam.optind > argc - 2) {
Eric Andersenc470f442003-07-28 09:56:35 +000010721 shellparam.optind = 1;
10722 shellparam.optoff = -1;
10723 }
10724 }
10725
Denys Vlasenko35c2a132016-10-26 17:34:26 +020010726 return getopts(argv[1], argv[2], optbase);
Eric Andersenc470f442003-07-28 09:56:35 +000010727}
Denis Vlasenko131ae172007-02-18 13:00:19 +000010728#endif /* ASH_GETOPTS */
Eric Andersencb57d552001-06-28 07:25:16 +000010729
Eric Andersencb57d552001-06-28 07:25:16 +000010730
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010731/* ============ Shell parser */
Eric Andersencb57d552001-06-28 07:25:16 +000010732
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010733struct heredoc {
10734 struct heredoc *next; /* next here document in list */
10735 union node *here; /* redirection node */
10736 char *eofmark; /* string indicating end of input */
10737 smallint striptabs; /* if set, strip leading tabs */
10738};
10739
10740static smallint tokpushback; /* last token pushed back */
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010741static smallint quoteflag; /* set if (part of) last token was quoted */
10742static token_id_t lasttoken; /* last token read (integer id Txxx) */
10743static struct heredoc *heredoclist; /* list of here documents to read */
10744static char *wordtext; /* text of last word returned by readtoken */
10745static struct nodelist *backquotelist;
10746static union node *redirnode;
10747static struct heredoc *heredoc;
Denis Vlasenko99eb8502007-02-23 21:09:49 +000010748
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010749static const char *
10750tokname(char *buf, int tok)
10751{
10752 if (tok < TSEMI)
Denys Vlasenko888527c2016-10-02 16:54:17 +020010753 return tokname_array[tok];
10754 sprintf(buf, "\"%s\"", tokname_array[tok]);
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010755 return buf;
10756}
10757
10758/* raise_error_unexpected_syntax:
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010759 * Called when an unexpected token is read during the parse. The argument
10760 * is the token that is expected, or -1 if more than one type of token can
10761 * occur at this point.
10762 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010763static void raise_error_unexpected_syntax(int) NORETURN;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010764static void
10765raise_error_unexpected_syntax(int token)
10766{
10767 char msg[64];
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010768 char buf[16];
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010769 int l;
10770
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010771 l = sprintf(msg, "unexpected %s", tokname(buf, lasttoken));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010772 if (token >= 0)
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010773 sprintf(msg + l, " (expecting %s)", tokname(buf, token));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010774 raise_error_syntax(msg);
10775 /* NOTREACHED */
10776}
Eric Andersencb57d552001-06-28 07:25:16 +000010777
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010778#define EOFMARKLEN 79
Eric Andersencb57d552001-06-28 07:25:16 +000010779
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010780/* parsing is heavily cross-recursive, need these forward decls */
10781static union node *andor(void);
10782static union node *pipeline(void);
10783static union node *parse_command(void);
10784static void parseheredoc(void);
Ron Yorstonc0e00762015-10-29 11:30:55 +000010785static int peektoken(void);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010786static int readtoken(void);
Eric Andersencb57d552001-06-28 07:25:16 +000010787
Eric Andersenc470f442003-07-28 09:56:35 +000010788static union node *
10789list(int nlflag)
Eric Andersencb57d552001-06-28 07:25:16 +000010790{
10791 union node *n1, *n2, *n3;
10792 int tok;
10793
Eric Andersencb57d552001-06-28 07:25:16 +000010794 n1 = NULL;
10795 for (;;) {
Ron Yorstonc0e00762015-10-29 11:30:55 +000010796 switch (peektoken()) {
10797 case TNL:
10798 if (!(nlflag & 1))
10799 break;
10800 parseheredoc();
10801 return n1;
10802
10803 case TEOF:
10804 if (!n1 && (nlflag & 1))
10805 n1 = NODE_EOF;
10806 parseheredoc();
10807 return n1;
10808 }
10809
10810 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Denys Vlasenko888527c2016-10-02 16:54:17 +020010811 if (nlflag == 2 && ((1 << peektoken()) & tokendlist))
Ron Yorstonc0e00762015-10-29 11:30:55 +000010812 return n1;
10813 nlflag |= 2;
10814
Eric Andersencb57d552001-06-28 07:25:16 +000010815 n2 = andor();
10816 tok = readtoken();
10817 if (tok == TBACKGND) {
Eric Andersenc470f442003-07-28 09:56:35 +000010818 if (n2->type == NPIPE) {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +000010819 n2->npipe.pipe_backgnd = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010820 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010821 if (n2->type != NREDIR) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000010822 n3 = stzalloc(sizeof(struct nredir));
Eric Andersenc470f442003-07-28 09:56:35 +000010823 n3->nredir.n = n2;
Denis Vlasenko597906c2008-02-20 16:38:54 +000010824 /*n3->nredir.redirect = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000010825 n2 = n3;
10826 }
10827 n2->type = NBACKGND;
Eric Andersencb57d552001-06-28 07:25:16 +000010828 }
10829 }
10830 if (n1 == NULL) {
10831 n1 = n2;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010832 } else {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010833 n3 = stzalloc(sizeof(struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +000010834 n3->type = NSEMI;
10835 n3->nbinary.ch1 = n1;
10836 n3->nbinary.ch2 = n2;
10837 n1 = n3;
10838 }
10839 switch (tok) {
Ron Yorstonc0e00762015-10-29 11:30:55 +000010840 case TNL:
10841 case TEOF:
10842 tokpushback = 1;
10843 /* fall through */
Eric Andersencb57d552001-06-28 07:25:16 +000010844 case TBACKGND:
10845 case TSEMI:
Eric Andersencb57d552001-06-28 07:25:16 +000010846 break;
Eric Andersencb57d552001-06-28 07:25:16 +000010847 default:
Ron Yorstonc0e00762015-10-29 11:30:55 +000010848 if ((nlflag & 1))
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010849 raise_error_unexpected_syntax(-1);
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010850 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010851 return n1;
10852 }
10853 }
10854}
10855
Eric Andersenc470f442003-07-28 09:56:35 +000010856static union node *
10857andor(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010858{
Eric Andersencb57d552001-06-28 07:25:16 +000010859 union node *n1, *n2, *n3;
10860 int t;
10861
Eric Andersencb57d552001-06-28 07:25:16 +000010862 n1 = pipeline();
10863 for (;;) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010864 t = readtoken();
10865 if (t == TAND) {
Eric Andersencb57d552001-06-28 07:25:16 +000010866 t = NAND;
10867 } else if (t == TOR) {
10868 t = NOR;
10869 } else {
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010870 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010871 return n1;
10872 }
Eric Andersenc470f442003-07-28 09:56:35 +000010873 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000010874 n2 = pipeline();
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010875 n3 = stzalloc(sizeof(struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +000010876 n3->type = t;
10877 n3->nbinary.ch1 = n1;
10878 n3->nbinary.ch2 = n2;
10879 n1 = n3;
10880 }
10881}
10882
Eric Andersenc470f442003-07-28 09:56:35 +000010883static union node *
10884pipeline(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010885{
Eric Andersencb57d552001-06-28 07:25:16 +000010886 union node *n1, *n2, *pipenode;
10887 struct nodelist *lp, *prev;
10888 int negate;
10889
10890 negate = 0;
10891 TRACE(("pipeline: entered\n"));
10892 if (readtoken() == TNOT) {
10893 negate = !negate;
Eric Andersenc470f442003-07-28 09:56:35 +000010894 checkkwd = CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000010895 } else
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010896 tokpushback = 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010897 n1 = parse_command();
Eric Andersencb57d552001-06-28 07:25:16 +000010898 if (readtoken() == TPIPE) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000010899 pipenode = stzalloc(sizeof(struct npipe));
Eric Andersencb57d552001-06-28 07:25:16 +000010900 pipenode->type = NPIPE;
Denis Vlasenko2dc240c2008-07-24 06:07:50 +000010901 /*pipenode->npipe.pipe_backgnd = 0; - stzalloc did it */
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010902 lp = stzalloc(sizeof(struct nodelist));
Eric Andersencb57d552001-06-28 07:25:16 +000010903 pipenode->npipe.cmdlist = lp;
10904 lp->n = n1;
10905 do {
10906 prev = lp;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010907 lp = stzalloc(sizeof(struct nodelist));
Eric Andersenc470f442003-07-28 09:56:35 +000010908 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010909 lp->n = parse_command();
Eric Andersencb57d552001-06-28 07:25:16 +000010910 prev->next = lp;
10911 } while (readtoken() == TPIPE);
10912 lp->next = NULL;
10913 n1 = pipenode;
10914 }
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010915 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010916 if (negate) {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010917 n2 = stzalloc(sizeof(struct nnot));
Eric Andersencb57d552001-06-28 07:25:16 +000010918 n2->type = NNOT;
10919 n2->nnot.com = n1;
10920 return n2;
Denis Vlasenko2da584f2007-02-19 22:44:05 +000010921 }
10922 return n1;
Eric Andersencb57d552001-06-28 07:25:16 +000010923}
10924
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010925static union node *
10926makename(void)
10927{
10928 union node *n;
10929
Denis Vlasenko597906c2008-02-20 16:38:54 +000010930 n = stzalloc(sizeof(struct narg));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010931 n->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000010932 /*n->narg.next = NULL; - stzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010933 n->narg.text = wordtext;
10934 n->narg.backquote = backquotelist;
10935 return n;
10936}
10937
10938static void
10939fixredir(union node *n, const char *text, int err)
10940{
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000010941 int fd;
10942
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010943 TRACE(("Fix redir %s %d\n", text, err));
10944 if (!err)
10945 n->ndup.vname = NULL;
10946
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000010947 fd = bb_strtou(text, NULL, 10);
10948 if (!errno && fd >= 0)
10949 n->ndup.dupfd = fd;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010950 else if (LONE_DASH(text))
10951 n->ndup.dupfd = -1;
10952 else {
10953 if (err)
Denis Vlasenko559691a2008-10-05 18:39:31 +000010954 raise_error_syntax("bad fd number");
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010955 n->ndup.vname = makename();
10956 }
10957}
10958
10959/*
10960 * Returns true if the text contains nothing to expand (no dollar signs
10961 * or backquotes).
10962 */
10963static int
Denis Vlasenko68819d12008-12-15 11:26:36 +000010964noexpand(const char *text)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010965{
Denys Vlasenkocd716832009-11-28 22:14:02 +010010966 unsigned char c;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010967
Denys Vlasenkocd716832009-11-28 22:14:02 +010010968 while ((c = *text++) != '\0') {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010969 if (c == CTLQUOTEMARK)
10970 continue;
10971 if (c == CTLESC)
Denys Vlasenkocd716832009-11-28 22:14:02 +010010972 text++;
Denys Vlasenko76bc2d62009-11-29 01:37:46 +010010973 else if (SIT(c, BASESYNTAX) == CCTL)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010974 return 0;
10975 }
10976 return 1;
10977}
10978
10979static void
10980parsefname(void)
10981{
10982 union node *n = redirnode;
10983
10984 if (readtoken() != TWORD)
10985 raise_error_unexpected_syntax(-1);
10986 if (n->type == NHERE) {
10987 struct heredoc *here = heredoc;
10988 struct heredoc *p;
10989 int i;
10990
10991 if (quoteflag == 0)
10992 n->type = NXHERE;
10993 TRACE(("Here document %d\n", n->type));
10994 if (!noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
Denis Vlasenko559691a2008-10-05 18:39:31 +000010995 raise_error_syntax("illegal eof marker for << redirection");
Denys Vlasenkob6c84342009-08-29 20:23:20 +020010996 rmescapes(wordtext, 0);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010997 here->eofmark = wordtext;
10998 here->next = NULL;
10999 if (heredoclist == NULL)
11000 heredoclist = here;
11001 else {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011002 for (p = heredoclist; p->next; p = p->next)
11003 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011004 p->next = here;
11005 }
11006 } else if (n->type == NTOFD || n->type == NFROMFD) {
11007 fixredir(n, wordtext, 0);
11008 } else {
11009 n->nfile.fname = makename();
11010 }
11011}
Eric Andersencb57d552001-06-28 07:25:16 +000011012
Eric Andersenc470f442003-07-28 09:56:35 +000011013static union node *
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011014simplecmd(void)
11015{
11016 union node *args, **app;
11017 union node *n = NULL;
11018 union node *vars, **vpp;
11019 union node **rpp, *redir;
11020 int savecheckkwd;
Denis Vlasenko80591b02008-03-25 07:49:43 +000011021#if ENABLE_ASH_BASH_COMPAT
11022 smallint double_brackets_flag = 0;
Ron Yorston95ebcf72015-11-03 09:42:23 +000011023 smallint function_flag = 0;
Denis Vlasenko80591b02008-03-25 07:49:43 +000011024#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011025
11026 args = NULL;
11027 app = &args;
11028 vars = NULL;
11029 vpp = &vars;
11030 redir = NULL;
11031 rpp = &redir;
11032
11033 savecheckkwd = CHKALIAS;
11034 for (;;) {
Denis Vlasenko80591b02008-03-25 07:49:43 +000011035 int t;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011036 checkkwd = savecheckkwd;
Denis Vlasenko80591b02008-03-25 07:49:43 +000011037 t = readtoken();
11038 switch (t) {
11039#if ENABLE_ASH_BASH_COMPAT
Ron Yorston95ebcf72015-11-03 09:42:23 +000011040 case TFUNCTION:
11041 if (peektoken() != TWORD)
11042 raise_error_unexpected_syntax(TWORD);
11043 function_flag = 1;
11044 break;
Denis Vlasenko80591b02008-03-25 07:49:43 +000011045 case TAND: /* "&&" */
11046 case TOR: /* "||" */
11047 if (!double_brackets_flag) {
11048 tokpushback = 1;
11049 goto out;
11050 }
11051 wordtext = (char *) (t == TAND ? "-a" : "-o");
11052#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011053 case TWORD:
Denis Vlasenko597906c2008-02-20 16:38:54 +000011054 n = stzalloc(sizeof(struct narg));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011055 n->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011056 /*n->narg.next = NULL; - stzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011057 n->narg.text = wordtext;
Denis Vlasenko80591b02008-03-25 07:49:43 +000011058#if ENABLE_ASH_BASH_COMPAT
11059 if (strcmp("[[", wordtext) == 0)
11060 double_brackets_flag = 1;
11061 else if (strcmp("]]", wordtext) == 0)
11062 double_brackets_flag = 0;
11063#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011064 n->narg.backquote = backquotelist;
11065 if (savecheckkwd && isassignment(wordtext)) {
11066 *vpp = n;
11067 vpp = &n->narg.next;
11068 } else {
11069 *app = n;
11070 app = &n->narg.next;
11071 savecheckkwd = 0;
11072 }
Ron Yorston95ebcf72015-11-03 09:42:23 +000011073#if ENABLE_ASH_BASH_COMPAT
11074 if (function_flag) {
11075 checkkwd = CHKNL | CHKKWD;
11076 switch (peektoken()) {
11077 case TBEGIN:
11078 case TIF:
11079 case TCASE:
11080 case TUNTIL:
11081 case TWHILE:
11082 case TFOR:
11083 goto do_func;
11084 case TLP:
11085 function_flag = 0;
11086 break;
11087 case TWORD:
11088 if (strcmp("[[", wordtext) == 0)
11089 goto do_func;
11090 /* fall through */
11091 default:
11092 raise_error_unexpected_syntax(-1);
11093 }
11094 }
11095#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011096 break;
11097 case TREDIR:
11098 *rpp = n = redirnode;
11099 rpp = &n->nfile.next;
11100 parsefname(); /* read name of redirection file */
11101 break;
11102 case TLP:
Ron Yorston95ebcf72015-11-03 09:42:23 +000011103 IF_ASH_BASH_COMPAT(do_func:)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011104 if (args && app == &args->narg.next
11105 && !vars && !redir
11106 ) {
11107 struct builtincmd *bcmd;
11108 const char *name;
11109
11110 /* We have a function */
Ron Yorston95ebcf72015-11-03 09:42:23 +000011111 if (IF_ASH_BASH_COMPAT(!function_flag &&) readtoken() != TRP)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011112 raise_error_unexpected_syntax(TRP);
11113 name = n->narg.text;
11114 if (!goodname(name)
11115 || ((bcmd = find_builtin(name)) && IS_BUILTIN_SPECIAL(bcmd))
11116 ) {
Denis Vlasenko559691a2008-10-05 18:39:31 +000011117 raise_error_syntax("bad function name");
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011118 }
11119 n->type = NDEFUN;
11120 checkkwd = CHKNL | CHKKWD | CHKALIAS;
11121 n->narg.next = parse_command();
11122 return n;
11123 }
Ron Yorston95ebcf72015-11-03 09:42:23 +000011124 IF_ASH_BASH_COMPAT(function_flag = 0;)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011125 /* fall through */
11126 default:
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011127 tokpushback = 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011128 goto out;
11129 }
11130 }
11131 out:
11132 *app = NULL;
11133 *vpp = NULL;
11134 *rpp = NULL;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011135 n = stzalloc(sizeof(struct ncmd));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011136 n->type = NCMD;
11137 n->ncmd.args = args;
11138 n->ncmd.assign = vars;
11139 n->ncmd.redirect = redir;
11140 return n;
11141}
11142
11143static union node *
11144parse_command(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011145{
Eric Andersencb57d552001-06-28 07:25:16 +000011146 union node *n1, *n2;
11147 union node *ap, **app;
11148 union node *cp, **cpp;
11149 union node *redir, **rpp;
Eric Andersenc470f442003-07-28 09:56:35 +000011150 union node **rpp2;
Eric Andersencb57d552001-06-28 07:25:16 +000011151 int t;
11152
11153 redir = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +000011154 rpp2 = &redir;
Eric Andersen88cec252001-09-06 17:35:20 +000011155
Eric Andersencb57d552001-06-28 07:25:16 +000011156 switch (readtoken()) {
Eric Andersenc470f442003-07-28 09:56:35 +000011157 default:
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011158 raise_error_unexpected_syntax(-1);
Eric Andersenc470f442003-07-28 09:56:35 +000011159 /* NOTREACHED */
Eric Andersencb57d552001-06-28 07:25:16 +000011160 case TIF:
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011161 n1 = stzalloc(sizeof(struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +000011162 n1->type = NIF;
11163 n1->nif.test = list(0);
11164 if (readtoken() != TTHEN)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011165 raise_error_unexpected_syntax(TTHEN);
Eric Andersencb57d552001-06-28 07:25:16 +000011166 n1->nif.ifpart = list(0);
11167 n2 = n1;
11168 while (readtoken() == TELIF) {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011169 n2->nif.elsepart = stzalloc(sizeof(struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +000011170 n2 = n2->nif.elsepart;
11171 n2->type = NIF;
11172 n2->nif.test = list(0);
11173 if (readtoken() != TTHEN)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011174 raise_error_unexpected_syntax(TTHEN);
Eric Andersencb57d552001-06-28 07:25:16 +000011175 n2->nif.ifpart = list(0);
11176 }
11177 if (lasttoken == TELSE)
11178 n2->nif.elsepart = list(0);
11179 else {
11180 n2->nif.elsepart = NULL;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011181 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011182 }
Eric Andersenc470f442003-07-28 09:56:35 +000011183 t = TFI;
Eric Andersencb57d552001-06-28 07:25:16 +000011184 break;
11185 case TWHILE:
Eric Andersenc470f442003-07-28 09:56:35 +000011186 case TUNTIL: {
Eric Andersencb57d552001-06-28 07:25:16 +000011187 int got;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011188 n1 = stzalloc(sizeof(struct nbinary));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011189 n1->type = (lasttoken == TWHILE) ? NWHILE : NUNTIL;
Eric Andersencb57d552001-06-28 07:25:16 +000011190 n1->nbinary.ch1 = list(0);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011191 got = readtoken();
11192 if (got != TDO) {
Denys Vlasenko888527c2016-10-02 16:54:17 +020011193 TRACE(("expecting DO got '%s' %s\n", tokname_array[got],
Denis Vlasenko131ae172007-02-18 13:00:19 +000011194 got == TWORD ? wordtext : ""));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011195 raise_error_unexpected_syntax(TDO);
Eric Andersencb57d552001-06-28 07:25:16 +000011196 }
11197 n1->nbinary.ch2 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +000011198 t = TDONE;
Eric Andersencb57d552001-06-28 07:25:16 +000011199 break;
11200 }
11201 case TFOR:
Denis Vlasenko2dc240c2008-07-24 06:07:50 +000011202 if (readtoken() != TWORD || quoteflag || !goodname(wordtext))
Denis Vlasenko559691a2008-10-05 18:39:31 +000011203 raise_error_syntax("bad for loop variable");
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011204 n1 = stzalloc(sizeof(struct nfor));
Eric Andersencb57d552001-06-28 07:25:16 +000011205 n1->type = NFOR;
11206 n1->nfor.var = wordtext;
Ron Yorstonab80e012015-08-03 13:46:00 +010011207 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000011208 if (readtoken() == TIN) {
11209 app = &ap;
11210 while (readtoken() == TWORD) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011211 n2 = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000011212 n2->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011213 /*n2->narg.next = NULL; - stzalloc did it */
Eric Andersencb57d552001-06-28 07:25:16 +000011214 n2->narg.text = wordtext;
11215 n2->narg.backquote = backquotelist;
11216 *app = n2;
11217 app = &n2->narg.next;
11218 }
11219 *app = NULL;
11220 n1->nfor.args = ap;
11221 if (lasttoken != TNL && lasttoken != TSEMI)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011222 raise_error_unexpected_syntax(-1);
Eric Andersencb57d552001-06-28 07:25:16 +000011223 } else {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011224 n2 = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000011225 n2->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011226 /*n2->narg.next = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011227 n2->narg.text = (char *)dolatstr;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011228 /*n2->narg.backquote = NULL;*/
Eric Andersencb57d552001-06-28 07:25:16 +000011229 n1->nfor.args = n2;
11230 /*
11231 * Newline or semicolon here is optional (but note
11232 * that the original Bourne shell only allowed NL).
11233 */
Ron Yorstonab80e012015-08-03 13:46:00 +010011234 if (lasttoken != TSEMI)
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011235 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011236 }
Eric Andersenc470f442003-07-28 09:56:35 +000011237 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000011238 if (readtoken() != TDO)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011239 raise_error_unexpected_syntax(TDO);
Eric Andersencb57d552001-06-28 07:25:16 +000011240 n1->nfor.body = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +000011241 t = TDONE;
Eric Andersencb57d552001-06-28 07:25:16 +000011242 break;
11243 case TCASE:
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011244 n1 = stzalloc(sizeof(struct ncase));
Eric Andersencb57d552001-06-28 07:25:16 +000011245 n1->type = NCASE;
11246 if (readtoken() != TWORD)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011247 raise_error_unexpected_syntax(TWORD);
Denis Vlasenko597906c2008-02-20 16:38:54 +000011248 n1->ncase.expr = n2 = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000011249 n2->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011250 /*n2->narg.next = NULL; - stzalloc did it */
Eric Andersencb57d552001-06-28 07:25:16 +000011251 n2->narg.text = wordtext;
11252 n2->narg.backquote = backquotelist;
Ron Yorston383b8852015-08-03 13:46:25 +010011253 checkkwd = CHKNL | CHKKWD | CHKALIAS;
11254 if (readtoken() != TIN)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011255 raise_error_unexpected_syntax(TIN);
Eric Andersencb57d552001-06-28 07:25:16 +000011256 cpp = &n1->ncase.cases;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011257 next_case:
Eric Andersenc470f442003-07-28 09:56:35 +000011258 checkkwd = CHKNL | CHKKWD;
11259 t = readtoken();
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011260 while (t != TESAC) {
Eric Andersencb57d552001-06-28 07:25:16 +000011261 if (lasttoken == TLP)
11262 readtoken();
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011263 *cpp = cp = stzalloc(sizeof(struct nclist));
Eric Andersencb57d552001-06-28 07:25:16 +000011264 cp->type = NCLIST;
11265 app = &cp->nclist.pattern;
11266 for (;;) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011267 *app = ap = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000011268 ap->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011269 /*ap->narg.next = NULL; - stzalloc did it */
Eric Andersencb57d552001-06-28 07:25:16 +000011270 ap->narg.text = wordtext;
11271 ap->narg.backquote = backquotelist;
Eric Andersenc470f442003-07-28 09:56:35 +000011272 if (readtoken() != TPIPE)
Eric Andersencb57d552001-06-28 07:25:16 +000011273 break;
11274 app = &ap->narg.next;
11275 readtoken();
11276 }
Denis Vlasenko597906c2008-02-20 16:38:54 +000011277 //ap->narg.next = NULL;
Eric Andersencb57d552001-06-28 07:25:16 +000011278 if (lasttoken != TRP)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011279 raise_error_unexpected_syntax(TRP);
Eric Andersenc470f442003-07-28 09:56:35 +000011280 cp->nclist.body = list(2);
Eric Andersencb57d552001-06-28 07:25:16 +000011281
Eric Andersenc470f442003-07-28 09:56:35 +000011282 cpp = &cp->nclist.next;
11283
11284 checkkwd = CHKNL | CHKKWD;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011285 t = readtoken();
11286 if (t != TESAC) {
Eric Andersencb57d552001-06-28 07:25:16 +000011287 if (t != TENDCASE)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011288 raise_error_unexpected_syntax(TENDCASE);
11289 goto next_case;
Eric Andersencb57d552001-06-28 07:25:16 +000011290 }
Eric Andersenc470f442003-07-28 09:56:35 +000011291 }
Eric Andersencb57d552001-06-28 07:25:16 +000011292 *cpp = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +000011293 goto redir;
Eric Andersencb57d552001-06-28 07:25:16 +000011294 case TLP:
Denis Vlasenko597906c2008-02-20 16:38:54 +000011295 n1 = stzalloc(sizeof(struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +000011296 n1->type = NSUBSHELL;
11297 n1->nredir.n = list(0);
Denis Vlasenko597906c2008-02-20 16:38:54 +000011298 /*n1->nredir.redirect = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011299 t = TRP;
Eric Andersencb57d552001-06-28 07:25:16 +000011300 break;
11301 case TBEGIN:
11302 n1 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +000011303 t = TEND;
Eric Andersencb57d552001-06-28 07:25:16 +000011304 break;
Ron Yorston95ebcf72015-11-03 09:42:23 +000011305 IF_ASH_BASH_COMPAT(case TFUNCTION:)
Eric Andersencb57d552001-06-28 07:25:16 +000011306 case TWORD:
Eric Andersenc470f442003-07-28 09:56:35 +000011307 case TREDIR:
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011308 tokpushback = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000011309 return simplecmd();
Eric Andersencb57d552001-06-28 07:25:16 +000011310 }
11311
Eric Andersenc470f442003-07-28 09:56:35 +000011312 if (readtoken() != t)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011313 raise_error_unexpected_syntax(t);
Eric Andersenc470f442003-07-28 09:56:35 +000011314
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011315 redir:
Eric Andersencb57d552001-06-28 07:25:16 +000011316 /* Now check for redirection which may follow command */
Eric Andersenc470f442003-07-28 09:56:35 +000011317 checkkwd = CHKKWD | CHKALIAS;
11318 rpp = rpp2;
Eric Andersencb57d552001-06-28 07:25:16 +000011319 while (readtoken() == TREDIR) {
11320 *rpp = n2 = redirnode;
11321 rpp = &n2->nfile.next;
11322 parsefname();
11323 }
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011324 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011325 *rpp = NULL;
11326 if (redir) {
11327 if (n1->type != NSUBSHELL) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011328 n2 = stzalloc(sizeof(struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +000011329 n2->type = NREDIR;
11330 n2->nredir.n = n1;
11331 n1 = n2;
11332 }
11333 n1->nredir.redirect = redir;
11334 }
Eric Andersencb57d552001-06-28 07:25:16 +000011335 return n1;
11336}
11337
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011338#if ENABLE_ASH_BASH_COMPAT
Denys Vlasenko37dc08b2016-10-02 04:38:07 +020011339static int
11340decode_dollar_squote(void)
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011341{
11342 static const char C_escapes[] ALIGN1 = "nrbtfav""x\\01234567";
11343 int c, cnt;
11344 char *p;
11345 char buf[4];
11346
11347 c = pgetc();
11348 p = strchr(C_escapes, c);
11349 if (p) {
11350 buf[0] = c;
11351 p = buf;
11352 cnt = 3;
11353 if ((unsigned char)(c - '0') <= 7) { /* \ooo */
11354 do {
11355 c = pgetc();
11356 *++p = c;
11357 } while ((unsigned char)(c - '0') <= 7 && --cnt);
11358 pungetc();
11359 } else if (c == 'x') { /* \xHH */
11360 do {
11361 c = pgetc();
11362 *++p = c;
11363 } while (isxdigit(c) && --cnt);
11364 pungetc();
11365 if (cnt == 3) { /* \x but next char is "bad" */
11366 c = 'x';
11367 goto unrecognized;
11368 }
11369 } else { /* simple seq like \\ or \t */
11370 p++;
11371 }
11372 *p = '\0';
11373 p = buf;
11374 c = bb_process_escape_sequence((void*)&p);
11375 } else { /* unrecognized "\z": print both chars unless ' or " */
11376 if (c != '\'' && c != '"') {
11377 unrecognized:
11378 c |= 0x100; /* "please encode \, then me" */
11379 }
11380 }
11381 return c;
11382}
11383#endif
11384
Eric Andersencb57d552001-06-28 07:25:16 +000011385/*
11386 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
11387 * is not NULL, read a here document. In the latter case, eofmark is the
11388 * word which marks the end of the document and striptabs is true if
Denys Vlasenkocd716832009-11-28 22:14:02 +010011389 * leading tabs should be stripped from the document. The argument c
Eric Andersencb57d552001-06-28 07:25:16 +000011390 * is the first character of the input token or document.
11391 *
11392 * Because C does not have internal subroutines, I have simulated them
11393 * using goto's to implement the subroutine linkage. The following macros
11394 * will run code that appears at the end of readtoken1.
11395 */
Eric Andersen2870d962001-07-02 17:27:21 +000011396#define CHECKEND() {goto checkend; checkend_return:;}
11397#define PARSEREDIR() {goto parseredir; parseredir_return:;}
11398#define PARSESUB() {goto parsesub; parsesub_return:;}
11399#define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
11400#define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
11401#define PARSEARITH() {goto parsearith; parsearith_return:;}
Eric Andersencb57d552001-06-28 07:25:16 +000011402static int
Denys Vlasenkocd716832009-11-28 22:14:02 +010011403readtoken1(int c, int syntax, char *eofmark, int striptabs)
Manuel Novoa III 16815d42001-08-10 19:36:07 +000011404{
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011405 /* NB: syntax parameter fits into smallint */
Denys Vlasenkocd716832009-11-28 22:14:02 +010011406 /* c parameter is an unsigned char or PEOF or PEOA */
Eric Andersencb57d552001-06-28 07:25:16 +000011407 char *out;
Denys Vlasenko50e6d422016-09-30 11:35:54 +020011408 size_t len;
Eric Andersencb57d552001-06-28 07:25:16 +000011409 char line[EOFMARKLEN + 1];
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011410 struct nodelist *bqlist;
11411 smallint quotef;
11412 smallint dblquote;
11413 smallint oldstyle;
Denys Vlasenko0b883582016-12-23 16:49:07 +010011414 IF_FEATURE_SH_MATH(smallint prevsyntax;) /* syntax before arithmetic */
Denis Vlasenko46a53062007-09-24 18:30:02 +000011415#if ENABLE_ASH_EXPAND_PRMT
11416 smallint pssyntax; /* we are expanding a prompt string */
11417#endif
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011418 int varnest; /* levels of variables expansion */
Denys Vlasenko0b883582016-12-23 16:49:07 +010011419 IF_FEATURE_SH_MATH(int arinest;) /* levels of arithmetic expansion */
11420 IF_FEATURE_SH_MATH(int parenlevel;) /* levels of parens in arithmetic */
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011421 int dqvarnest; /* levels of variables expansion within double quotes */
11422
Denis Vlasenko5e34ff22009-04-21 11:09:40 +000011423 IF_ASH_BASH_COMPAT(smallint bash_dollar_squote = 0;)
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011424
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011425 startlinno = g_parsefile->linno;
Eric Andersencb57d552001-06-28 07:25:16 +000011426 bqlist = NULL;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011427 quotef = 0;
Denys Vlasenko0b883582016-12-23 16:49:07 +010011428 IF_FEATURE_SH_MATH(prevsyntax = 0;)
Denis Vlasenko46a53062007-09-24 18:30:02 +000011429#if ENABLE_ASH_EXPAND_PRMT
11430 pssyntax = (syntax == PSSYNTAX);
11431 if (pssyntax)
11432 syntax = DQSYNTAX;
11433#endif
11434 dblquote = (syntax == DQSYNTAX);
Eric Andersencb57d552001-06-28 07:25:16 +000011435 varnest = 0;
Denys Vlasenko0b883582016-12-23 16:49:07 +010011436 IF_FEATURE_SH_MATH(arinest = 0;)
11437 IF_FEATURE_SH_MATH(parenlevel = 0;)
Eric Andersencb57d552001-06-28 07:25:16 +000011438 dqvarnest = 0;
11439
11440 STARTSTACKSTR(out);
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011441 loop:
11442 /* For each line, until end of word */
Denys Vlasenko958581a2010-09-12 15:04:27 +020011443 CHECKEND(); /* set c to PEOF if at end of here document */
11444 for (;;) { /* until end of line or end of word */
11445 CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */
11446 switch (SIT(c, syntax)) {
11447 case CNL: /* '\n' */
11448 if (syntax == BASESYNTAX)
11449 goto endword; /* exit outer loop */
11450 USTPUTC(c, out);
Denys Vlasenkoce332a22016-10-02 23:47:34 +020011451 nlprompt();
Denys Vlasenko958581a2010-09-12 15:04:27 +020011452 c = pgetc();
11453 goto loop; /* continue outer loop */
11454 case CWORD:
11455 USTPUTC(c, out);
11456 break;
11457 case CCTL:
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011458#if ENABLE_ASH_BASH_COMPAT
Denys Vlasenko958581a2010-09-12 15:04:27 +020011459 if (c == '\\' && bash_dollar_squote) {
11460 c = decode_dollar_squote();
Denys Vlasenko13f20912016-09-25 20:54:25 +020011461 if (c == '\0') {
11462 /* skip $'\000', $'\x00' (like bash) */
11463 break;
11464 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020011465 if (c & 0x100) {
Denys Vlasenko13f20912016-09-25 20:54:25 +020011466 /* Unknown escape. Encode as '\z' */
Denys Vlasenko958581a2010-09-12 15:04:27 +020011467 c = (unsigned char)c;
Denys Vlasenko13f20912016-09-25 20:54:25 +020011468 if (eofmark == NULL || dblquote)
11469 USTPUTC(CTLESC, out);
11470 USTPUTC('\\', out);
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011471 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020011472 }
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011473#endif
Denys Vlasenko13f20912016-09-25 20:54:25 +020011474 if (eofmark == NULL || dblquote)
11475 USTPUTC(CTLESC, out);
Denys Vlasenko958581a2010-09-12 15:04:27 +020011476 USTPUTC(c, out);
11477 break;
11478 case CBACK: /* backslash */
11479 c = pgetc_without_PEOA();
11480 if (c == PEOF) {
11481 USTPUTC(CTLESC, out);
11482 USTPUTC('\\', out);
11483 pungetc();
11484 } else if (c == '\n') {
Denys Vlasenkoce332a22016-10-02 23:47:34 +020011485 nlprompt();
Denys Vlasenko958581a2010-09-12 15:04:27 +020011486 } else {
11487#if ENABLE_ASH_EXPAND_PRMT
11488 if (c == '$' && pssyntax) {
Eric Andersenc470f442003-07-28 09:56:35 +000011489 USTPUTC(CTLESC, out);
Eric Andersencb57d552001-06-28 07:25:16 +000011490 USTPUTC('\\', out);
Denys Vlasenko958581a2010-09-12 15:04:27 +020011491 }
Denis Vlasenko46a53062007-09-24 18:30:02 +000011492#endif
Denys Vlasenko958581a2010-09-12 15:04:27 +020011493 /* Backslash is retained if we are in "str" and next char isn't special */
11494 if (dblquote
11495 && c != '\\'
11496 && c != '`'
11497 && c != '$'
11498 && (c != '"' || eofmark != NULL)
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011499 ) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020011500 USTPUTC('\\', out);
Eric Andersencb57d552001-06-28 07:25:16 +000011501 }
Ron Yorston549deab2015-05-18 09:57:51 +020011502 USTPUTC(CTLESC, out);
Denys Vlasenko0ff78a02010-08-30 15:20:07 +020011503 USTPUTC(c, out);
Denys Vlasenko958581a2010-09-12 15:04:27 +020011504 quotef = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011505 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020011506 break;
11507 case CSQUOTE:
11508 syntax = SQSYNTAX;
11509 quotemark:
11510 if (eofmark == NULL) {
11511 USTPUTC(CTLQUOTEMARK, out);
11512 }
11513 break;
11514 case CDQUOTE:
11515 syntax = DQSYNTAX;
11516 dblquote = 1;
11517 goto quotemark;
11518 case CENDQUOTE:
11519 IF_ASH_BASH_COMPAT(bash_dollar_squote = 0;)
Ron Yorston7e4ed262015-05-18 09:54:43 +020011520 if (eofmark != NULL && varnest == 0) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020011521 USTPUTC(c, out);
11522 } else {
11523 if (dqvarnest == 0) {
11524 syntax = BASESYNTAX;
11525 dblquote = 0;
11526 }
11527 quotef = 1;
11528 goto quotemark;
11529 }
11530 break;
11531 case CVAR: /* '$' */
11532 PARSESUB(); /* parse substitution */
11533 break;
11534 case CENDVAR: /* '}' */
11535 if (varnest > 0) {
11536 varnest--;
11537 if (dqvarnest > 0) {
11538 dqvarnest--;
11539 }
11540 c = CTLENDVAR;
11541 }
11542 USTPUTC(c, out);
11543 break;
Denys Vlasenko0b883582016-12-23 16:49:07 +010011544#if ENABLE_FEATURE_SH_MATH
Denys Vlasenko958581a2010-09-12 15:04:27 +020011545 case CLP: /* '(' in arithmetic */
11546 parenlevel++;
11547 USTPUTC(c, out);
11548 break;
11549 case CRP: /* ')' in arithmetic */
11550 if (parenlevel > 0) {
11551 parenlevel--;
11552 } else {
Denys Vlasenko459293b2016-09-29 17:58:58 +020011553 if (pgetc_eatbnl() == ')') {
Ron Yorstonad88bde2015-05-18 09:56:16 +020011554 c = CTLENDARI;
Denys Vlasenko958581a2010-09-12 15:04:27 +020011555 if (--arinest == 0) {
11556 syntax = prevsyntax;
Denys Vlasenko958581a2010-09-12 15:04:27 +020011557 }
11558 } else {
11559 /*
11560 * unbalanced parens
11561 * (don't 2nd guess - no error)
11562 */
11563 pungetc();
11564 }
11565 }
11566 USTPUTC(c, out);
11567 break;
11568#endif
11569 case CBQUOTE: /* '`' */
11570 PARSEBACKQOLD();
11571 break;
11572 case CENDFILE:
11573 goto endword; /* exit outer loop */
11574 case CIGN:
11575 break;
11576 default:
11577 if (varnest == 0) {
11578#if ENABLE_ASH_BASH_COMPAT
11579 if (c == '&') {
Denys Vlasenko459293b2016-09-29 17:58:58 +020011580//Can't call pgetc_eatbnl() here, this requires three-deep pungetc()
Denys Vlasenko958581a2010-09-12 15:04:27 +020011581 if (pgetc() == '>')
11582 c = 0x100 + '>'; /* flag &> */
11583 pungetc();
11584 }
11585#endif
11586 goto endword; /* exit outer loop */
11587 }
11588 IF_ASH_ALIAS(if (c != PEOA))
11589 USTPUTC(c, out);
11590 }
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020011591 c = pgetc();
Denys Vlasenko958581a2010-09-12 15:04:27 +020011592 } /* for (;;) */
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011593 endword:
Denys Vlasenko958581a2010-09-12 15:04:27 +020011594
Denys Vlasenko0b883582016-12-23 16:49:07 +010011595#if ENABLE_FEATURE_SH_MATH
Eric Andersencb57d552001-06-28 07:25:16 +000011596 if (syntax == ARISYNTAX)
Denis Vlasenko559691a2008-10-05 18:39:31 +000011597 raise_error_syntax("missing '))'");
Eric Andersenc470f442003-07-28 09:56:35 +000011598#endif
Ron Yorston0e056f72015-07-01 16:45:40 +010011599 if (syntax != BASESYNTAX && eofmark == NULL)
Denis Vlasenko559691a2008-10-05 18:39:31 +000011600 raise_error_syntax("unterminated quoted string");
Eric Andersencb57d552001-06-28 07:25:16 +000011601 if (varnest != 0) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011602 startlinno = g_parsefile->linno;
Eric Andersenc470f442003-07-28 09:56:35 +000011603 /* { */
Denis Vlasenko559691a2008-10-05 18:39:31 +000011604 raise_error_syntax("missing '}'");
Eric Andersencb57d552001-06-28 07:25:16 +000011605 }
11606 USTPUTC('\0', out);
Eric Andersenc470f442003-07-28 09:56:35 +000011607 len = out - (char *)stackblock();
Eric Andersencb57d552001-06-28 07:25:16 +000011608 out = stackblock();
11609 if (eofmark == NULL) {
Denis Vlasenko5e34ff22009-04-21 11:09:40 +000011610 if ((c == '>' || c == '<' IF_ASH_BASH_COMPAT( || c == 0x100 + '>'))
Denis Vlasenko834dee72008-10-07 09:18:30 +000011611 && quotef == 0
11612 ) {
Denis Vlasenko559691a2008-10-05 18:39:31 +000011613 if (isdigit_str9(out)) {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000011614 PARSEREDIR(); /* passed as params: out, c */
11615 lasttoken = TREDIR;
11616 return lasttoken;
11617 }
11618 /* else: non-number X seen, interpret it
11619 * as "NNNX>file" = "NNNX >file" */
Eric Andersencb57d552001-06-28 07:25:16 +000011620 }
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011621 pungetc();
Eric Andersencb57d552001-06-28 07:25:16 +000011622 }
11623 quoteflag = quotef;
11624 backquotelist = bqlist;
11625 grabstackblock(len);
11626 wordtext = out;
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011627 lasttoken = TWORD;
11628 return lasttoken;
Eric Andersencb57d552001-06-28 07:25:16 +000011629/* end of readtoken routine */
11630
Eric Andersencb57d552001-06-28 07:25:16 +000011631/*
11632 * Check to see whether we are at the end of the here document. When this
11633 * is called, c is set to the first character of the next input line. If
11634 * we are at the end of the here document, this routine sets the c to PEOF.
11635 */
Eric Andersenc470f442003-07-28 09:56:35 +000011636checkend: {
11637 if (eofmark) {
Denis Vlasenko131ae172007-02-18 13:00:19 +000011638#if ENABLE_ASH_ALIAS
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010011639 if (c == PEOA)
11640 c = pgetc_without_PEOA();
Eric Andersenc470f442003-07-28 09:56:35 +000011641#endif
11642 if (striptabs) {
11643 while (c == '\t') {
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010011644 c = pgetc_without_PEOA();
Eric Andersencb57d552001-06-28 07:25:16 +000011645 }
Eric Andersenc470f442003-07-28 09:56:35 +000011646 }
11647 if (c == *eofmark) {
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011648 if (pfgets(line, sizeof(line)) != NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +000011649 char *p, *q;
Denys Vlasenko350e6862016-10-26 16:26:45 +020011650 int cc;
Eric Andersencb57d552001-06-28 07:25:16 +000011651
Eric Andersenc470f442003-07-28 09:56:35 +000011652 p = line;
Denys Vlasenko350e6862016-10-26 16:26:45 +020011653 for (q = eofmark + 1;; p++, q++) {
11654 cc = *p;
11655 if (cc == '\n')
11656 cc = 0;
11657 if (!*q || cc != *q)
11658 break;
11659 }
11660 if (cc == *q) {
Eric Andersenc470f442003-07-28 09:56:35 +000011661 c = PEOF;
Denys Vlasenkoce332a22016-10-02 23:47:34 +020011662 nlnoprompt();
Eric Andersenc470f442003-07-28 09:56:35 +000011663 } else {
11664 pushstring(line, NULL);
Eric Andersencb57d552001-06-28 07:25:16 +000011665 }
11666 }
11667 }
11668 }
Eric Andersenc470f442003-07-28 09:56:35 +000011669 goto checkend_return;
11670}
Eric Andersencb57d552001-06-28 07:25:16 +000011671
Eric Andersencb57d552001-06-28 07:25:16 +000011672/*
11673 * Parse a redirection operator. The variable "out" points to a string
11674 * specifying the fd to be redirected. The variable "c" contains the
11675 * first character of the redirection operator.
11676 */
Eric Andersenc470f442003-07-28 09:56:35 +000011677parseredir: {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000011678 /* out is already checked to be a valid number or "" */
11679 int fd = (*out == '\0' ? -1 : atoi(out));
Eric Andersenc470f442003-07-28 09:56:35 +000011680 union node *np;
Eric Andersencb57d552001-06-28 07:25:16 +000011681
Denis Vlasenko597906c2008-02-20 16:38:54 +000011682 np = stzalloc(sizeof(struct nfile));
Eric Andersenc470f442003-07-28 09:56:35 +000011683 if (c == '>') {
11684 np->nfile.fd = 1;
11685 c = pgetc();
11686 if (c == '>')
11687 np->type = NAPPEND;
11688 else if (c == '|')
11689 np->type = NCLOBBER;
11690 else if (c == '&')
11691 np->type = NTOFD;
Denis Vlasenko559691a2008-10-05 18:39:31 +000011692 /* it also can be NTO2 (>&file), but we can't figure it out yet */
Eric Andersenc470f442003-07-28 09:56:35 +000011693 else {
11694 np->type = NTO;
11695 pungetc();
Eric Andersencb57d552001-06-28 07:25:16 +000011696 }
Denis Vlasenko834dee72008-10-07 09:18:30 +000011697 }
11698#if ENABLE_ASH_BASH_COMPAT
11699 else if (c == 0x100 + '>') { /* this flags &> redirection */
11700 np->nfile.fd = 1;
11701 pgetc(); /* this is '>', no need to check */
11702 np->type = NTO2;
11703 }
11704#endif
11705 else { /* c == '<' */
Denis Vlasenko597906c2008-02-20 16:38:54 +000011706 /*np->nfile.fd = 0; - stzalloc did it */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011707 c = pgetc();
11708 switch (c) {
Eric Andersenc470f442003-07-28 09:56:35 +000011709 case '<':
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011710 if (sizeof(struct nfile) != sizeof(struct nhere)) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011711 np = stzalloc(sizeof(struct nhere));
11712 /*np->nfile.fd = 0; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011713 }
11714 np->type = NHERE;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011715 heredoc = stzalloc(sizeof(struct heredoc));
Eric Andersenc470f442003-07-28 09:56:35 +000011716 heredoc->here = np;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011717 c = pgetc();
11718 if (c == '-') {
Eric Andersenc470f442003-07-28 09:56:35 +000011719 heredoc->striptabs = 1;
11720 } else {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011721 /*heredoc->striptabs = 0; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011722 pungetc();
11723 }
11724 break;
11725
11726 case '&':
11727 np->type = NFROMFD;
11728 break;
11729
11730 case '>':
11731 np->type = NFROMTO;
11732 break;
11733
11734 default:
11735 np->type = NFROM;
11736 pungetc();
11737 break;
11738 }
Eric Andersencb57d552001-06-28 07:25:16 +000011739 }
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000011740 if (fd >= 0)
11741 np->nfile.fd = fd;
Eric Andersenc470f442003-07-28 09:56:35 +000011742 redirnode = np;
11743 goto parseredir_return;
11744}
Eric Andersencb57d552001-06-28 07:25:16 +000011745
Eric Andersencb57d552001-06-28 07:25:16 +000011746/*
11747 * Parse a substitution. At this point, we have read the dollar sign
11748 * and nothing else.
11749 */
Denis Vlasenkocc571512007-02-23 21:10:35 +000011750
11751/* is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise
11752 * (assuming ascii char codes, as the original implementation did) */
11753#define is_special(c) \
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011754 (((unsigned)(c) - 33 < 32) \
11755 && ((0xc1ff920dU >> ((unsigned)(c) - 33)) & 1))
Eric Andersenc470f442003-07-28 09:56:35 +000011756parsesub: {
Denys Vlasenkocd716832009-11-28 22:14:02 +010011757 unsigned char subtype;
Eric Andersenc470f442003-07-28 09:56:35 +000011758 int typeloc;
Eric Andersencb57d552001-06-28 07:25:16 +000011759
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011760 c = pgetc_eatbnl();
Denys Vlasenkocd716832009-11-28 22:14:02 +010011761 if (c > 255 /* PEOA or PEOF */
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011762 || (c != '(' && c != '{' && !is_name(c) && !is_special(c))
Eric Andersenc470f442003-07-28 09:56:35 +000011763 ) {
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011764#if ENABLE_ASH_BASH_COMPAT
Ron Yorston84ba50c2016-04-03 22:43:14 +010011765 if (syntax != DQSYNTAX && c == '\'')
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011766 bash_dollar_squote = 1;
11767 else
11768#endif
11769 USTPUTC('$', out);
Eric Andersenc470f442003-07-28 09:56:35 +000011770 pungetc();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011771 } else if (c == '(') {
11772 /* $(command) or $((arith)) */
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011773 if (pgetc_eatbnl() == '(') {
Denys Vlasenko0b883582016-12-23 16:49:07 +010011774#if ENABLE_FEATURE_SH_MATH
Eric Andersenc470f442003-07-28 09:56:35 +000011775 PARSEARITH();
11776#else
Mike Frysinger98a6f562008-06-09 09:38:45 +000011777 raise_error_syntax("you disabled math support for $((arith)) syntax");
Eric Andersenc470f442003-07-28 09:56:35 +000011778#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011779 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000011780 pungetc();
11781 PARSEBACKQNEW();
11782 }
11783 } else {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011784 /* $VAR, $<specialchar>, ${...}, or PEOA/PEOF */
Eric Andersenc470f442003-07-28 09:56:35 +000011785 USTPUTC(CTLVAR, out);
11786 typeloc = out - (char *)stackblock();
Denys Vlasenko3df14102016-10-26 16:41:13 +020011787 STADJUST(1, out);
Eric Andersenc470f442003-07-28 09:56:35 +000011788 subtype = VSNORMAL;
11789 if (c == '{') {
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011790 c = pgetc_eatbnl();
Denys Vlasenkof15aa572016-10-26 15:56:53 +020011791 subtype = 0;
Eric Andersenc470f442003-07-28 09:56:35 +000011792 }
Denys Vlasenkof15aa572016-10-26 15:56:53 +020011793 varname:
Denys Vlasenko3df14102016-10-26 16:41:13 +020011794 if (is_name(c)) {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011795 /* $[{[#]]NAME[}] */
Eric Andersenc470f442003-07-28 09:56:35 +000011796 do {
11797 STPUTC(c, out);
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011798 c = pgetc_eatbnl();
Denys Vlasenko3df14102016-10-26 16:41:13 +020011799 } while (is_in_name(c));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011800 } else if (isdigit(c)) {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011801 /* $[{[#]]NUM[}] */
Eric Andersenc470f442003-07-28 09:56:35 +000011802 do {
11803 STPUTC(c, out);
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011804 c = pgetc_eatbnl();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011805 } while (isdigit(c));
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011806 } else if (is_special(c)) {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011807 /* $[{[#]]<specialchar>[}] */
Denys Vlasenkof15aa572016-10-26 15:56:53 +020011808 int cc = c;
11809
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011810 c = pgetc_eatbnl();
Denys Vlasenkof15aa572016-10-26 15:56:53 +020011811 if (!subtype && cc == '#') {
11812 subtype = VSLENGTH;
11813 if (c == '_' || isalnum(c))
11814 goto varname;
11815 cc = c;
11816 c = pgetc_eatbnl();
11817 if (cc == '}' || c != '}') {
11818 pungetc();
11819 subtype = 0;
11820 c = cc;
11821 cc = '#';
11822 }
11823 }
11824 USTPUTC(cc, out);
Denis Vlasenko559691a2008-10-05 18:39:31 +000011825 } else {
Denys Vlasenko88e15702016-10-26 01:55:56 +020011826 goto badsub;
Denis Vlasenko559691a2008-10-05 18:39:31 +000011827 }
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011828 if (c != '}' && subtype == VSLENGTH) {
11829 /* ${#VAR didn't end with } */
Cristian Ionescu-Idbohrn301f5ec2009-10-05 02:07:23 +020011830 goto badsub;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011831 }
Eric Andersencb57d552001-06-28 07:25:16 +000011832
Eric Andersenc470f442003-07-28 09:56:35 +000011833 if (subtype == 0) {
Denys Vlasenkof8ddbe12016-07-25 03:56:00 +020011834 static const char types[] ALIGN1 = "}-+?=";
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011835 /* ${VAR...} but not $VAR or ${#VAR} */
11836 /* c == first char after VAR */
Eric Andersenc470f442003-07-28 09:56:35 +000011837 switch (c) {
11838 case ':':
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011839 c = pgetc_eatbnl();
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011840#if ENABLE_ASH_BASH_COMPAT
Denys Vlasenkof8ddbe12016-07-25 03:56:00 +020011841 /* This check is only needed to not misinterpret
11842 * ${VAR:-WORD}, ${VAR:+WORD}, ${VAR:=WORD}, ${VAR:?WORD}
11843 * constructs.
11844 */
11845 if (!strchr(types, c)) {
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011846 subtype = VSSUBSTR;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011847 pungetc();
Denys Vlasenko88e15702016-10-26 01:55:56 +020011848 break; /* "goto badsub" is bigger (!) */
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011849 }
11850#endif
Denys Vlasenko3df14102016-10-26 16:41:13 +020011851 subtype = VSNUL;
Eric Andersenc470f442003-07-28 09:56:35 +000011852 /*FALLTHROUGH*/
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011853 default: {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011854 const char *p = strchr(types, c);
Eric Andersenc470f442003-07-28 09:56:35 +000011855 if (p == NULL)
Denys Vlasenko88e15702016-10-26 01:55:56 +020011856 break;
Denys Vlasenko3df14102016-10-26 16:41:13 +020011857 subtype |= p - types + VSNORMAL;
Eric Andersenc470f442003-07-28 09:56:35 +000011858 break;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011859 }
Eric Andersenc470f442003-07-28 09:56:35 +000011860 case '%':
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011861 case '#': {
11862 int cc = c;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011863 subtype = (c == '#' ? VSTRIMLEFT : VSTRIMRIGHT);
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011864 c = pgetc_eatbnl();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011865 if (c != cc)
Denys Vlasenko88e15702016-10-26 01:55:56 +020011866 goto badsub;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011867 subtype++;
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011868 break;
11869 }
11870#if ENABLE_ASH_BASH_COMPAT
11871 case '/':
Denys Vlasenko6040fe82010-09-12 15:03:16 +020011872 /* ${v/[/]pattern/repl} */
11873//TODO: encode pattern and repl separately.
11874// Currently ${v/$var_with_slash/repl} is horribly broken
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011875 subtype = VSREPLACE;
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011876 c = pgetc_eatbnl();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011877 if (c != '/')
Denys Vlasenko88e15702016-10-26 01:55:56 +020011878 goto badsub;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011879 subtype++; /* VSREPLACEALL */
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011880 break;
11881#endif
Eric Andersencb57d552001-06-28 07:25:16 +000011882 }
Eric Andersenc470f442003-07-28 09:56:35 +000011883 } else {
Denys Vlasenko88e15702016-10-26 01:55:56 +020011884 badsub:
Eric Andersenc470f442003-07-28 09:56:35 +000011885 pungetc();
11886 }
Denys Vlasenko3df14102016-10-26 16:41:13 +020011887 ((unsigned char *)stackblock())[typeloc] = subtype;
Eric Andersenc470f442003-07-28 09:56:35 +000011888 if (subtype != VSNORMAL) {
11889 varnest++;
Denys Vlasenko3df14102016-10-26 16:41:13 +020011890 if (dblquote)
Eric Andersenc470f442003-07-28 09:56:35 +000011891 dqvarnest++;
Eric Andersencb57d552001-06-28 07:25:16 +000011892 }
Denys Vlasenko88e15702016-10-26 01:55:56 +020011893 STPUTC('=', out);
Eric Andersencb57d552001-06-28 07:25:16 +000011894 }
Eric Andersenc470f442003-07-28 09:56:35 +000011895 goto parsesub_return;
11896}
Eric Andersencb57d552001-06-28 07:25:16 +000011897
Eric Andersencb57d552001-06-28 07:25:16 +000011898/*
11899 * Called to parse command substitutions. Newstyle is set if the command
11900 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
11901 * list of commands (passed by reference), and savelen is the number of
11902 * characters on the top of the stack which must be preserved.
11903 */
Eric Andersenc470f442003-07-28 09:56:35 +000011904parsebackq: {
11905 struct nodelist **nlpp;
Eric Andersenc470f442003-07-28 09:56:35 +000011906 union node *n;
Ron Yorston072fc602015-07-01 16:46:18 +010011907 char *str;
Eric Andersenc470f442003-07-28 09:56:35 +000011908 size_t savelen;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011909 smallint saveprompt = 0;
11910
Eric Andersenc470f442003-07-28 09:56:35 +000011911 str = NULL;
11912 savelen = out - (char *)stackblock();
11913 if (savelen > 0) {
Denys Vlasenko7bc3d392016-09-17 20:53:47 +020011914 /*
11915 * FIXME: this can allocate very large block on stack and SEGV.
11916 * Example:
11917 * echo "..<100kbytes>..`true` $(true) `true` ..."
Denys Vlasenko73737592016-09-17 20:58:22 +020011918 * allocates 100kb for every command subst. With about
Denys Vlasenko7bc3d392016-09-17 20:53:47 +020011919 * a hundred command substitutions stack overflows.
11920 * With larger prepended string, SEGV happens sooner.
11921 */
Ron Yorston072fc602015-07-01 16:46:18 +010011922 str = alloca(savelen);
Eric Andersenc470f442003-07-28 09:56:35 +000011923 memcpy(str, stackblock(), savelen);
11924 }
Denys Vlasenko7bc3d392016-09-17 20:53:47 +020011925
Eric Andersenc470f442003-07-28 09:56:35 +000011926 if (oldstyle) {
11927 /* We must read until the closing backquote, giving special
Denys Vlasenko60cb48c2013-01-14 15:57:44 +010011928 * treatment to some slashes, and then push the string and
11929 * reread it as input, interpreting it normally.
11930 */
Eric Andersenc470f442003-07-28 09:56:35 +000011931 char *pout;
Eric Andersenc470f442003-07-28 09:56:35 +000011932 size_t psavelen;
11933 char *pstr;
11934
Eric Andersenc470f442003-07-28 09:56:35 +000011935 STARTSTACKSTR(pout);
11936 for (;;) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020011937 int pc;
11938
11939 setprompt_if(needprompt, 2);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011940 pc = pgetc();
11941 switch (pc) {
Eric Andersenc470f442003-07-28 09:56:35 +000011942 case '`':
11943 goto done;
11944
11945 case '\\':
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011946 pc = pgetc();
11947 if (pc == '\n') {
Denys Vlasenkoce332a22016-10-02 23:47:34 +020011948 nlprompt();
Eric Andersenc470f442003-07-28 09:56:35 +000011949 /*
11950 * If eating a newline, avoid putting
11951 * the newline into the new character
11952 * stream (via the STPUTC after the
11953 * switch).
11954 */
11955 continue;
11956 }
11957 if (pc != '\\' && pc != '`' && pc != '$'
Denys Vlasenko76bc2d62009-11-29 01:37:46 +010011958 && (!dblquote || pc != '"')
11959 ) {
Eric Andersenc470f442003-07-28 09:56:35 +000011960 STPUTC('\\', pout);
Denys Vlasenko76bc2d62009-11-29 01:37:46 +010011961 }
Denys Vlasenkocd716832009-11-28 22:14:02 +010011962 if (pc <= 255 /* not PEOA or PEOF */) {
Eric Andersenc470f442003-07-28 09:56:35 +000011963 break;
11964 }
11965 /* fall through */
11966
11967 case PEOF:
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010011968 IF_ASH_ALIAS(case PEOA:)
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011969 startlinno = g_parsefile->linno;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011970 raise_error_syntax("EOF in backquote substitution");
Eric Andersenc470f442003-07-28 09:56:35 +000011971
11972 case '\n':
Denys Vlasenkoce332a22016-10-02 23:47:34 +020011973 nlnoprompt();
Eric Andersenc470f442003-07-28 09:56:35 +000011974 break;
11975
11976 default:
11977 break;
11978 }
11979 STPUTC(pc, pout);
11980 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011981 done:
Eric Andersenc470f442003-07-28 09:56:35 +000011982 STPUTC('\0', pout);
11983 psavelen = pout - (char *)stackblock();
11984 if (psavelen > 0) {
11985 pstr = grabstackstr(pout);
11986 setinputstring(pstr);
11987 }
11988 }
11989 nlpp = &bqlist;
11990 while (*nlpp)
11991 nlpp = &(*nlpp)->next;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011992 *nlpp = stzalloc(sizeof(**nlpp));
11993 /* (*nlpp)->next = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011994
11995 if (oldstyle) {
11996 saveprompt = doprompt;
11997 doprompt = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000011998 }
11999
Eric Andersenc470f442003-07-28 09:56:35 +000012000 n = list(2);
12001
12002 if (oldstyle)
12003 doprompt = saveprompt;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012004 else if (readtoken() != TRP)
12005 raise_error_unexpected_syntax(TRP);
Eric Andersenc470f442003-07-28 09:56:35 +000012006
12007 (*nlpp)->n = n;
12008 if (oldstyle) {
12009 /*
12010 * Start reading from old file again, ignoring any pushed back
12011 * tokens left from the backquote parsing
12012 */
12013 popfile();
12014 tokpushback = 0;
12015 }
12016 while (stackblocksize() <= savelen)
12017 growstackblock();
12018 STARTSTACKSTR(out);
12019 if (str) {
12020 memcpy(out, str, savelen);
12021 STADJUST(savelen, out);
Eric Andersenc470f442003-07-28 09:56:35 +000012022 }
Ron Yorston549deab2015-05-18 09:57:51 +020012023 USTPUTC(CTLBACKQ, out);
Eric Andersenc470f442003-07-28 09:56:35 +000012024 if (oldstyle)
12025 goto parsebackq_oldreturn;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000012026 goto parsebackq_newreturn;
Eric Andersenc470f442003-07-28 09:56:35 +000012027}
12028
Denys Vlasenko0b883582016-12-23 16:49:07 +010012029#if ENABLE_FEATURE_SH_MATH
Eric Andersencb57d552001-06-28 07:25:16 +000012030/*
12031 * Parse an arithmetic expansion (indicate start of one and set state)
12032 */
Eric Andersenc470f442003-07-28 09:56:35 +000012033parsearith: {
Eric Andersenc470f442003-07-28 09:56:35 +000012034 if (++arinest == 1) {
12035 prevsyntax = syntax;
12036 syntax = ARISYNTAX;
Eric Andersencb57d552001-06-28 07:25:16 +000012037 }
Ron Yorstonad88bde2015-05-18 09:56:16 +020012038 USTPUTC(CTLARI, out);
Eric Andersenc470f442003-07-28 09:56:35 +000012039 goto parsearith_return;
12040}
12041#endif
Eric Andersenc470f442003-07-28 09:56:35 +000012042} /* end of readtoken */
12043
Eric Andersencb57d552001-06-28 07:25:16 +000012044/*
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012045 * Read the next input token.
12046 * If the token is a word, we set backquotelist to the list of cmds in
12047 * backquotes. We set quoteflag to true if any part of the word was
12048 * quoted.
12049 * If the token is TREDIR, then we set redirnode to a structure containing
12050 * the redirection.
12051 * In all cases, the variable startlinno is set to the number of the line
12052 * on which the token starts.
12053 *
12054 * [Change comment: here documents and internal procedures]
12055 * [Readtoken shouldn't have any arguments. Perhaps we should make the
12056 * word parsing code into a separate routine. In this case, readtoken
12057 * doesn't need to have any internal procedures, but parseword does.
12058 * We could also make parseoperator in essence the main routine, and
12059 * have parseword (readtoken1?) handle both words and redirection.]
Eric Andersencb57d552001-06-28 07:25:16 +000012060 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012061#define NEW_xxreadtoken
12062#ifdef NEW_xxreadtoken
12063/* singles must be first! */
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000012064static const char xxreadtoken_chars[7] ALIGN1 = {
Denis Vlasenko834dee72008-10-07 09:18:30 +000012065 '\n', '(', ')', /* singles */
12066 '&', '|', ';', /* doubles */
12067 0
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000012068};
Eric Andersencb57d552001-06-28 07:25:16 +000012069
Denis Vlasenko834dee72008-10-07 09:18:30 +000012070#define xxreadtoken_singles 3
12071#define xxreadtoken_doubles 3
12072
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000012073static const char xxreadtoken_tokens[] ALIGN1 = {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012074 TNL, TLP, TRP, /* only single occurrence allowed */
12075 TBACKGND, TPIPE, TSEMI, /* if single occurrence */
12076 TEOF, /* corresponds to trailing nul */
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000012077 TAND, TOR, TENDCASE /* if double occurrence */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012078};
12079
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012080static int
12081xxreadtoken(void)
12082{
12083 int c;
12084
12085 if (tokpushback) {
12086 tokpushback = 0;
12087 return lasttoken;
Eric Andersencb57d552001-06-28 07:25:16 +000012088 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020012089 setprompt_if(needprompt, 2);
Denis Vlasenko41eb3002008-11-28 03:42:31 +000012090 startlinno = g_parsefile->linno;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012091 for (;;) { /* until token or start of word found */
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020012092 c = pgetc();
Denis Vlasenko5e34ff22009-04-21 11:09:40 +000012093 if (c == ' ' || c == '\t' IF_ASH_ALIAS( || c == PEOA))
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012094 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012095
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012096 if (c == '#') {
12097 while ((c = pgetc()) != '\n' && c != PEOF)
12098 continue;
12099 pungetc();
12100 } else if (c == '\\') {
12101 if (pgetc() != '\n') {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012102 pungetc();
Denis Vlasenko834dee72008-10-07 09:18:30 +000012103 break; /* return readtoken1(...) */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012104 }
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012105 nlprompt();
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012106 } else {
12107 const char *p;
12108
12109 p = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
12110 if (c != PEOF) {
12111 if (c == '\n') {
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012112 nlnoprompt();
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012113 }
12114
12115 p = strchr(xxreadtoken_chars, c);
Denis Vlasenko834dee72008-10-07 09:18:30 +000012116 if (p == NULL)
12117 break; /* return readtoken1(...) */
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012118
Denis Vlasenko834dee72008-10-07 09:18:30 +000012119 if ((int)(p - xxreadtoken_chars) >= xxreadtoken_singles) {
12120 int cc = pgetc();
12121 if (cc == c) { /* double occurrence? */
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012122 p += xxreadtoken_doubles + 1;
12123 } else {
12124 pungetc();
Denis Vlasenko834dee72008-10-07 09:18:30 +000012125#if ENABLE_ASH_BASH_COMPAT
12126 if (c == '&' && cc == '>') /* &> */
12127 break; /* return readtoken1(...) */
12128#endif
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012129 }
12130 }
12131 }
12132 lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
12133 return lasttoken;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012134 }
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012135 } /* for (;;) */
Denis Vlasenko834dee72008-10-07 09:18:30 +000012136
12137 return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012138}
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012139#else /* old xxreadtoken */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012140#define RETURN(token) return lasttoken = token
12141static int
12142xxreadtoken(void)
12143{
12144 int c;
12145
12146 if (tokpushback) {
12147 tokpushback = 0;
12148 return lasttoken;
12149 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020012150 setprompt_if(needprompt, 2);
Denis Vlasenko41eb3002008-11-28 03:42:31 +000012151 startlinno = g_parsefile->linno;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012152 for (;;) { /* until token or start of word found */
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020012153 c = pgetc();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012154 switch (c) {
12155 case ' ': case '\t':
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010012156 IF_ASH_ALIAS(case PEOA:)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012157 continue;
12158 case '#':
Denis Vlasenkof7d56652008-03-25 05:51:41 +000012159 while ((c = pgetc()) != '\n' && c != PEOF)
12160 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012161 pungetc();
12162 continue;
12163 case '\\':
12164 if (pgetc() == '\n') {
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012165 nlprompt();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012166 continue;
12167 }
12168 pungetc();
12169 goto breakloop;
12170 case '\n':
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012171 nlnoprompt();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012172 RETURN(TNL);
12173 case PEOF:
12174 RETURN(TEOF);
12175 case '&':
12176 if (pgetc() == '&')
12177 RETURN(TAND);
12178 pungetc();
12179 RETURN(TBACKGND);
12180 case '|':
12181 if (pgetc() == '|')
12182 RETURN(TOR);
12183 pungetc();
12184 RETURN(TPIPE);
12185 case ';':
12186 if (pgetc() == ';')
12187 RETURN(TENDCASE);
12188 pungetc();
12189 RETURN(TSEMI);
12190 case '(':
12191 RETURN(TLP);
12192 case ')':
12193 RETURN(TRP);
12194 default:
12195 goto breakloop;
12196 }
12197 }
12198 breakloop:
12199 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
12200#undef RETURN
12201}
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012202#endif /* old xxreadtoken */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012203
12204static int
12205readtoken(void)
12206{
12207 int t;
Ron Yorston713f07d2015-10-29 16:44:56 +000012208 int kwd = checkkwd;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012209#if DEBUG
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000012210 smallint alreadyseen = tokpushback;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012211#endif
12212
12213#if ENABLE_ASH_ALIAS
12214 top:
12215#endif
12216
12217 t = xxreadtoken();
12218
12219 /*
12220 * eat newlines
12221 */
Ron Yorston713f07d2015-10-29 16:44:56 +000012222 if (kwd & CHKNL) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012223 while (t == TNL) {
12224 parseheredoc();
12225 t = xxreadtoken();
12226 }
12227 }
12228
12229 if (t != TWORD || quoteflag) {
12230 goto out;
12231 }
12232
12233 /*
12234 * check for keywords
12235 */
Ron Yorston713f07d2015-10-29 16:44:56 +000012236 if (kwd & CHKKWD) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012237 const char *const *pp;
12238
12239 pp = findkwd(wordtext);
12240 if (pp) {
12241 lasttoken = t = pp - tokname_array;
Denys Vlasenko888527c2016-10-02 16:54:17 +020012242 TRACE(("keyword '%s' recognized\n", tokname_array[t]));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012243 goto out;
12244 }
12245 }
12246
12247 if (checkkwd & CHKALIAS) {
12248#if ENABLE_ASH_ALIAS
12249 struct alias *ap;
12250 ap = lookupalias(wordtext, 1);
12251 if (ap != NULL) {
12252 if (*ap->val) {
12253 pushstring(ap->val, ap);
12254 }
12255 goto top;
12256 }
12257#endif
12258 }
12259 out:
12260 checkkwd = 0;
12261#if DEBUG
12262 if (!alreadyseen)
Denys Vlasenko888527c2016-10-02 16:54:17 +020012263 TRACE(("token '%s' %s\n", tokname_array[t], t == TWORD ? wordtext : ""));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012264 else
Denys Vlasenko888527c2016-10-02 16:54:17 +020012265 TRACE(("reread token '%s' %s\n", tokname_array[t], t == TWORD ? wordtext : ""));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012266#endif
12267 return t;
Eric Andersencb57d552001-06-28 07:25:16 +000012268}
12269
Ron Yorstonc0e00762015-10-29 11:30:55 +000012270static int
Ron Yorston6bd2fab2015-10-29 11:30:22 +000012271peektoken(void)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012272{
12273 int t;
12274
12275 t = readtoken();
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000012276 tokpushback = 1;
Ron Yorstonc0e00762015-10-29 11:30:55 +000012277 return t;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012278}
Eric Andersencb57d552001-06-28 07:25:16 +000012279
12280/*
Denys Vlasenko86e83ec2009-07-23 22:07:07 +020012281 * Read and parse a command. Returns NODE_EOF on end of file.
12282 * (NULL is a valid parse tree indicating a blank line.)
Eric Andersencb57d552001-06-28 07:25:16 +000012283 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012284static union node *
12285parsecmd(int interact)
Eric Andersen90898442003-08-06 11:20:52 +000012286{
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012287 tokpushback = 0;
Ron Yorstonc0e00762015-10-29 11:30:55 +000012288 checkkwd = 0;
12289 heredoclist = 0;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012290 doprompt = interact;
Denys Vlasenko958581a2010-09-12 15:04:27 +020012291 setprompt_if(doprompt, doprompt);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012292 needprompt = 0;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012293 return list(1);
12294}
12295
12296/*
12297 * Input any here documents.
12298 */
12299static void
12300parseheredoc(void)
12301{
12302 struct heredoc *here;
12303 union node *n;
12304
12305 here = heredoclist;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000012306 heredoclist = NULL;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012307
12308 while (here) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020012309 setprompt_if(needprompt, 2);
12310 readtoken1(pgetc(), here->here->type == NHERE ? SQSYNTAX : DQSYNTAX,
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012311 here->eofmark, here->striptabs);
Denis Vlasenko597906c2008-02-20 16:38:54 +000012312 n = stzalloc(sizeof(struct narg));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012313 n->narg.type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000012314 /*n->narg.next = NULL; - stzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012315 n->narg.text = wordtext;
12316 n->narg.backquote = backquotelist;
12317 here->here->nhere.doc = n;
12318 here = here->next;
Eric Andersencb57d552001-06-28 07:25:16 +000012319 }
Eric Andersencb57d552001-06-28 07:25:16 +000012320}
12321
12322
12323/*
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000012324 * called by editline -- any expansions to the prompt should be added here.
Eric Andersencb57d552001-06-28 07:25:16 +000012325 */
Denis Vlasenko131ae172007-02-18 13:00:19 +000012326#if ENABLE_ASH_EXPAND_PRMT
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012327static const char *
12328expandstr(const char *ps)
12329{
12330 union node n;
Denys Vlasenko2a6d29a2016-10-25 21:17:52 +020012331 int saveprompt;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012332
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000012333 /* XXX Fix (char *) cast. It _is_ a bug. ps is variable's value,
12334 * and token processing _can_ alter it (delete NULs etc). */
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012335 setinputstring((char *)ps);
Denys Vlasenko2a6d29a2016-10-25 21:17:52 +020012336
12337 saveprompt = doprompt;
12338 doprompt = 0;
Denis Vlasenko46a53062007-09-24 18:30:02 +000012339 readtoken1(pgetc(), PSSYNTAX, nullstr, 0);
Denys Vlasenko2a6d29a2016-10-25 21:17:52 +020012340 doprompt = saveprompt;
12341
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012342 popfile();
12343
12344 n.narg.type = NARG;
12345 n.narg.next = NULL;
12346 n.narg.text = wordtext;
12347 n.narg.backquote = backquotelist;
12348
Ron Yorston549deab2015-05-18 09:57:51 +020012349 expandarg(&n, NULL, EXP_QUOTED);
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012350 return stackblock();
12351}
12352#endif
12353
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012354/*
12355 * Execute a command or commands contained in a string.
12356 */
12357static int
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020012358evalstring(char *s, int flags)
Eric Andersenc470f442003-07-28 09:56:35 +000012359{
Denys Vlasenko493b9ca2016-10-30 18:27:14 +010012360 struct jmploc *volatile savehandler;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012361 struct jmploc jmploc;
12362 int ex;
12363
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012364 union node *n;
12365 struct stackmark smark;
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012366 int status;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012367
Denys Vlasenko8e2bc472016-09-28 23:02:57 +020012368 s = sstrdup(s);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012369 setinputstring(s);
12370 setstackmark(&smark);
12371
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012372 status = 0;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012373 /* On exception inside execution loop, we must popfile().
12374 * Try interactively:
12375 * readonly a=a
12376 * command eval "a=b" # throws "is read only" error
12377 * "command BLTIN" is not supposed to abort (even in non-interactive use).
12378 * But if we skip popfile(), we hit EOF in eval's string, and exit.
12379 */
12380 savehandler = exception_handler;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012381 ex = setjmp(jmploc.loc);
12382 if (ex)
12383 goto out;
Denys Vlasenko493b9ca2016-10-30 18:27:14 +010012384 exception_handler = &jmploc;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012385
Denys Vlasenko86e83ec2009-07-23 22:07:07 +020012386 while ((n = parsecmd(0)) != NODE_EOF) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020012387 int i;
12388
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020012389 i = evaltree(n, flags);
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012390 if (n)
12391 status = i;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012392 popstackmark(&smark);
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012393 if (evalskip)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012394 break;
12395 }
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012396 out:
Denys Vlasenko8e2bc472016-09-28 23:02:57 +020012397 popstackmark(&smark);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012398 popfile();
Denys Vlasenko8e2bc472016-09-28 23:02:57 +020012399 stunalloc(s);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012400
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012401 exception_handler = savehandler;
12402 if (ex)
12403 longjmp(exception_handler->loc, ex);
12404
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012405 return status;
Eric Andersenc470f442003-07-28 09:56:35 +000012406}
12407
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012408/*
12409 * The eval command.
12410 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012411static int FAST_FUNC
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020012412evalcmd(int argc UNUSED_PARAM, char **argv, int flags)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012413{
12414 char *p;
12415 char *concat;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012416
Denis Vlasenko68404f12008-03-17 09:00:54 +000012417 if (argv[1]) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012418 p = argv[1];
Denis Vlasenko68404f12008-03-17 09:00:54 +000012419 argv += 2;
12420 if (argv[0]) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012421 STARTSTACKSTR(concat);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012422 for (;;) {
12423 concat = stack_putstr(p, concat);
Denis Vlasenko68404f12008-03-17 09:00:54 +000012424 p = *argv++;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012425 if (p == NULL)
12426 break;
12427 STPUTC(' ', concat);
12428 }
12429 STPUTC('\0', concat);
12430 p = grabstackstr(concat);
12431 }
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020012432 return evalstring(p, flags & EV_TESTED);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012433 }
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012434 return 0;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012435}
12436
12437/*
Denys Vlasenko285ad152009-12-04 23:02:27 +010012438 * Read and execute commands.
12439 * "Top" is nonzero for the top level command loop;
12440 * it turns on prompting if the shell is interactive.
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012441 */
12442static int
12443cmdloop(int top)
12444{
12445 union node *n;
12446 struct stackmark smark;
12447 int inter;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020012448 int status = 0;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012449 int numeof = 0;
12450
12451 TRACE(("cmdloop(%d) called\n", top));
12452 for (;;) {
12453 int skip;
12454
12455 setstackmark(&smark);
12456#if JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +000012457 if (doing_jobctl)
Denys Vlasenko9c541002015-10-07 15:44:36 +020012458 showjobs(SHOW_CHANGED|SHOW_STDERR);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012459#endif
12460 inter = 0;
12461 if (iflag && top) {
12462 inter++;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012463 chkmail();
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012464 }
12465 n = parsecmd(inter);
Denys Vlasenko7cee00e2009-07-24 01:08:03 +020012466#if DEBUG
12467 if (DEBUG > 2 && debug && (n != NODE_EOF))
Denys Vlasenko883cea42009-07-11 15:31:59 +020012468 showtree(n);
Denis Vlasenko135cecb2009-04-12 00:00:57 +000012469#endif
Denys Vlasenko86e83ec2009-07-23 22:07:07 +020012470 if (n == NODE_EOF) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012471 if (!top || numeof >= 50)
12472 break;
12473 if (!stoppedjobs()) {
12474 if (!Iflag)
12475 break;
12476 out2str("\nUse \"exit\" to leave shell.\n");
12477 }
12478 numeof++;
12479 } else if (nflag == 0) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020012480 int i;
12481
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +000012482 /* job_warning can only be 2,1,0. Here 2->1, 1/0->0 */
12483 job_warning >>= 1;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012484 numeof = 0;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020012485 i = evaltree(n, 0);
12486 if (n)
12487 status = i;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012488 }
12489 popstackmark(&smark);
12490 skip = evalskip;
12491
12492 if (skip) {
Denys Vlasenko6a0710e2016-09-30 14:18:34 +020012493 evalskip &= ~SKIPFUNC;
Denys Vlasenko0840c912016-10-01 15:27:44 +020012494 break;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012495 }
12496 }
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020012497 return status;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012498}
12499
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000012500/*
12501 * Take commands from a file. To be compatible we should do a path
12502 * search for the file, which is necessary to find sub-commands.
12503 */
12504static char *
12505find_dot_file(char *name)
12506{
12507 char *fullname;
12508 const char *path = pathval();
12509 struct stat statb;
12510
12511 /* don't try this for absolute or relative paths */
12512 if (strchr(name, '/'))
12513 return name;
12514
Denis Vlasenko8ad78e12009-02-15 12:40:30 +000012515 /* IIRC standards do not say whether . is to be searched.
12516 * And it is even smaller this way, making it unconditional for now:
12517 */
12518 if (1) { /* ENABLE_ASH_BASH_COMPAT */
12519 fullname = name;
12520 goto try_cur_dir;
12521 }
12522
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020012523 while ((fullname = path_advance(&path, name)) != NULL) {
Denis Vlasenko8ad78e12009-02-15 12:40:30 +000012524 try_cur_dir:
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000012525 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
12526 /*
12527 * Don't bother freeing here, since it will
12528 * be freed by the caller.
12529 */
12530 return fullname;
12531 }
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020012532 if (fullname != name)
12533 stunalloc(fullname);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000012534 }
12535
12536 /* not found in the PATH */
12537 ash_msg_and_raise_error("%s: not found", name);
12538 /* NOTREACHED */
12539}
12540
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012541static int FAST_FUNC
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012542dotcmd(int argc_ UNUSED_PARAM, char **argv_ UNUSED_PARAM)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012543{
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012544 /* "false; . empty_file; echo $?" should print 0, not 1: */
12545 int status = 0;
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012546 char *fullname;
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012547 char **argv;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012548 struct strlist *sp;
12549 volatile struct shparam saveparam;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012550
12551 for (sp = cmdenviron; sp; sp = sp->next)
Denis Vlasenko4222ae42007-02-25 02:37:49 +000012552 setvareq(ckstrdup(sp->text), VSTRFIXED | VTEXTFIXED);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012553
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012554 nextopt(nullstr); /* handle possible "--" */
12555 argv = argptr;
12556
12557 if (!argv[0]) {
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012558 /* bash says: "bash: .: filename argument required" */
12559 return 2; /* bash compat */
12560 }
12561
Denys Vlasenko091f8312013-03-17 14:25:22 +010012562 /* This aborts if file isn't found, which is POSIXly correct.
12563 * bash returns exitcode 1 instead.
12564 */
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012565 fullname = find_dot_file(argv[0]);
12566 argv++;
12567 if (argv[0]) { /* . FILE ARGS, ARGS exist */
12568 int argc;
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012569 saveparam = shellparam;
12570 shellparam.malloced = 0;
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012571 argc = 1;
12572 while (argv[argc])
12573 argc++;
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012574 shellparam.nparam = argc;
12575 shellparam.p = argv;
12576 };
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012577
Denys Vlasenko091f8312013-03-17 14:25:22 +010012578 /* This aborts if file can't be opened, which is POSIXly correct.
12579 * bash returns exitcode 1 instead.
12580 */
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012581 setinputfile(fullname, INPUT_PUSH_FILE);
12582 commandname = fullname;
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012583 status = cmdloop(0);
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012584 popfile();
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012585
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012586 if (argv[0]) {
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012587 freeparam(&shellparam);
12588 shellparam = saveparam;
12589 };
12590
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012591 return status;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012592}
12593
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012594static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012595exitcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012596{
12597 if (stoppedjobs())
12598 return 0;
Denis Vlasenko68404f12008-03-17 09:00:54 +000012599 if (argv[1])
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012600 exitstatus = number(argv[1]);
12601 raise_exception(EXEXIT);
12602 /* NOTREACHED */
12603}
12604
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012605/*
12606 * Read a file containing shell functions.
12607 */
12608static void
12609readcmdfile(char *name)
12610{
12611 setinputfile(name, INPUT_PUSH_FILE);
12612 cmdloop(0);
12613 popfile();
12614}
12615
12616
Denis Vlasenkocc571512007-02-23 21:10:35 +000012617/* ============ find_command inplementation */
12618
12619/*
12620 * Resolve a command name. If you change this routine, you may have to
12621 * change the shellexec routine as well.
12622 */
12623static void
12624find_command(char *name, struct cmdentry *entry, int act, const char *path)
12625{
12626 struct tblentry *cmdp;
12627 int idx;
12628 int prev;
12629 char *fullname;
12630 struct stat statb;
12631 int e;
12632 int updatetbl;
12633 struct builtincmd *bcmd;
12634
12635 /* If name contains a slash, don't use PATH or hash table */
12636 if (strchr(name, '/') != NULL) {
12637 entry->u.index = -1;
12638 if (act & DO_ABS) {
12639 while (stat(name, &statb) < 0) {
12640#ifdef SYSV
12641 if (errno == EINTR)
12642 continue;
12643#endif
12644 entry->cmdtype = CMDUNKNOWN;
12645 return;
12646 }
12647 }
12648 entry->cmdtype = CMDNORMAL;
12649 return;
12650 }
12651
Denis Vlasenkof20de5b2007-04-29 23:42:54 +000012652/* #if ENABLE_FEATURE_SH_STANDALONE... moved after builtin check */
Denis Vlasenkocc571512007-02-23 21:10:35 +000012653
12654 updatetbl = (path == pathval());
12655 if (!updatetbl) {
12656 act |= DO_ALTPATH;
12657 if (strstr(path, "%builtin") != NULL)
12658 act |= DO_ALTBLTIN;
12659 }
12660
12661 /* If name is in the table, check answer will be ok */
12662 cmdp = cmdlookup(name, 0);
12663 if (cmdp != NULL) {
12664 int bit;
12665
12666 switch (cmdp->cmdtype) {
12667 default:
12668#if DEBUG
12669 abort();
12670#endif
12671 case CMDNORMAL:
12672 bit = DO_ALTPATH;
12673 break;
12674 case CMDFUNCTION:
12675 bit = DO_NOFUNC;
12676 break;
12677 case CMDBUILTIN:
12678 bit = DO_ALTBLTIN;
12679 break;
12680 }
12681 if (act & bit) {
12682 updatetbl = 0;
12683 cmdp = NULL;
12684 } else if (cmdp->rehash == 0)
12685 /* if not invalidated by cd, we're done */
12686 goto success;
12687 }
12688
12689 /* If %builtin not in path, check for builtin next */
12690 bcmd = find_builtin(name);
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000012691 if (bcmd) {
12692 if (IS_BUILTIN_REGULAR(bcmd))
12693 goto builtin_success;
12694 if (act & DO_ALTPATH) {
12695 if (!(act & DO_ALTBLTIN))
12696 goto builtin_success;
12697 } else if (builtinloc <= 0) {
12698 goto builtin_success;
Denis Vlasenko8e858e22007-03-07 09:35:43 +000012699 }
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000012700 }
Denis Vlasenkocc571512007-02-23 21:10:35 +000012701
Denis Vlasenkof20de5b2007-04-29 23:42:54 +000012702#if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko7465dbc2008-04-13 02:25:53 +000012703 {
12704 int applet_no = find_applet_by_name(name);
12705 if (applet_no >= 0) {
12706 entry->cmdtype = CMDNORMAL;
12707 entry->u.index = -2 - applet_no;
12708 return;
12709 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +000012710 }
12711#endif
12712
Denis Vlasenkocc571512007-02-23 21:10:35 +000012713 /* We have to search path. */
12714 prev = -1; /* where to start */
12715 if (cmdp && cmdp->rehash) { /* doing a rehash */
12716 if (cmdp->cmdtype == CMDBUILTIN)
12717 prev = builtinloc;
12718 else
12719 prev = cmdp->param.index;
12720 }
12721
12722 e = ENOENT;
12723 idx = -1;
12724 loop:
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020012725 while ((fullname = path_advance(&path, name)) != NULL) {
Denis Vlasenkocc571512007-02-23 21:10:35 +000012726 stunalloc(fullname);
Denis Vlasenkodee82b62007-07-29 14:05:27 +000012727 /* NB: code below will still use fullname
12728 * despite it being "unallocated" */
Denis Vlasenkocc571512007-02-23 21:10:35 +000012729 idx++;
12730 if (pathopt) {
12731 if (prefix(pathopt, "builtin")) {
12732 if (bcmd)
12733 goto builtin_success;
12734 continue;
Denis Vlasenko4a9ca132008-04-12 20:07:08 +000012735 }
12736 if ((act & DO_NOFUNC)
12737 || !prefix(pathopt, "func")
Denys Vlasenkoe4dcba12010-10-28 18:57:19 +020012738 ) { /* ignore unimplemented options */
Denis Vlasenkocc571512007-02-23 21:10:35 +000012739 continue;
12740 }
12741 }
12742 /* if rehash, don't redo absolute path names */
12743 if (fullname[0] == '/' && idx <= prev) {
12744 if (idx < prev)
12745 continue;
12746 TRACE(("searchexec \"%s\": no change\n", name));
12747 goto success;
12748 }
12749 while (stat(fullname, &statb) < 0) {
12750#ifdef SYSV
12751 if (errno == EINTR)
12752 continue;
12753#endif
12754 if (errno != ENOENT && errno != ENOTDIR)
12755 e = errno;
12756 goto loop;
12757 }
12758 e = EACCES; /* if we fail, this will be the error */
12759 if (!S_ISREG(statb.st_mode))
12760 continue;
12761 if (pathopt) { /* this is a %func directory */
12762 stalloc(strlen(fullname) + 1);
Denis Vlasenkodee82b62007-07-29 14:05:27 +000012763 /* NB: stalloc will return space pointed by fullname
12764 * (because we don't have any intervening allocations
12765 * between stunalloc above and this stalloc) */
Denis Vlasenkocc571512007-02-23 21:10:35 +000012766 readcmdfile(fullname);
12767 cmdp = cmdlookup(name, 0);
12768 if (cmdp == NULL || cmdp->cmdtype != CMDFUNCTION)
12769 ash_msg_and_raise_error("%s not defined in %s", name, fullname);
12770 stunalloc(fullname);
12771 goto success;
12772 }
12773 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
12774 if (!updatetbl) {
12775 entry->cmdtype = CMDNORMAL;
12776 entry->u.index = idx;
12777 return;
12778 }
12779 INT_OFF;
12780 cmdp = cmdlookup(name, 1);
12781 cmdp->cmdtype = CMDNORMAL;
12782 cmdp->param.index = idx;
12783 INT_ON;
12784 goto success;
12785 }
12786
12787 /* We failed. If there was an entry for this command, delete it */
12788 if (cmdp && updatetbl)
12789 delete_cmd_entry();
12790 if (act & DO_ERR)
12791 ash_msg("%s: %s", name, errmsg(e, "not found"));
12792 entry->cmdtype = CMDUNKNOWN;
12793 return;
12794
12795 builtin_success:
12796 if (!updatetbl) {
12797 entry->cmdtype = CMDBUILTIN;
12798 entry->u.cmd = bcmd;
12799 return;
12800 }
12801 INT_OFF;
12802 cmdp = cmdlookup(name, 1);
12803 cmdp->cmdtype = CMDBUILTIN;
12804 cmdp->param.cmd = bcmd;
12805 INT_ON;
12806 success:
12807 cmdp->rehash = 0;
12808 entry->cmdtype = cmdp->cmdtype;
12809 entry->u = cmdp->param;
12810}
12811
12812
Eric Andersencb57d552001-06-28 07:25:16 +000012813/*
Eric Andersencb57d552001-06-28 07:25:16 +000012814 * The trap builtin.
12815 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012816static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012817trapcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +000012818{
12819 char *action;
12820 char **ap;
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010012821 int signo, exitcode;
Eric Andersencb57d552001-06-28 07:25:16 +000012822
Eric Andersenc470f442003-07-28 09:56:35 +000012823 nextopt(nullstr);
12824 ap = argptr;
12825 if (!*ap) {
Denis Vlasenko2da584f2007-02-19 22:44:05 +000012826 for (signo = 0; signo < NSIG; signo++) {
Denys Vlasenko21d87d42009-09-25 00:06:51 +020012827 char *tr = trap_ptr[signo];
12828 if (tr) {
Denys Vlasenkoe74aaf92009-09-27 02:05:45 +020012829 /* note: bash adds "SIG", but only if invoked
12830 * as "bash". If called as "sh", or if set -o posix,
12831 * then it prints short signal names.
12832 * We are printing short names: */
12833 out1fmt("trap -- %s %s\n",
Denys Vlasenko21d87d42009-09-25 00:06:51 +020012834 single_quote(tr),
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +000012835 get_signame(signo));
Denys Vlasenko726e1a02009-09-25 02:58:20 +020012836 /* trap_ptr != trap only if we are in special-cased `trap` code.
12837 * In this case, we will exit very soon, no need to free(). */
Denys Vlasenkoe74aaf92009-09-27 02:05:45 +020012838 /* if (trap_ptr != trap && tp[0]) */
Denys Vlasenko726e1a02009-09-25 02:58:20 +020012839 /* free(tr); */
Eric Andersencb57d552001-06-28 07:25:16 +000012840 }
12841 }
Denys Vlasenko726e1a02009-09-25 02:58:20 +020012842 /*
Denys Vlasenko21d87d42009-09-25 00:06:51 +020012843 if (trap_ptr != trap) {
12844 free(trap_ptr);
12845 trap_ptr = trap;
12846 }
Denys Vlasenko726e1a02009-09-25 02:58:20 +020012847 */
Eric Andersencb57d552001-06-28 07:25:16 +000012848 return 0;
12849 }
Denys Vlasenko21d87d42009-09-25 00:06:51 +020012850
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +000012851 action = NULL;
12852 if (ap[1])
Eric Andersencb57d552001-06-28 07:25:16 +000012853 action = *ap++;
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010012854 exitcode = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000012855 while (*ap) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000012856 signo = get_signum(*ap);
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010012857 if (signo < 0) {
12858 /* Mimic bash message exactly */
12859 ash_msg("%s: invalid signal specification", *ap);
12860 exitcode = 1;
12861 goto next;
12862 }
Denis Vlasenkob012b102007-02-19 22:43:01 +000012863 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +000012864 if (action) {
Denis Vlasenko9f739442006-12-16 23:49:13 +000012865 if (LONE_DASH(action))
Eric Andersencb57d552001-06-28 07:25:16 +000012866 action = NULL;
Denys Vlasenkob4f51d32016-10-27 12:55:09 +020012867 else {
12868 if (action[0]) /* not NULL and not "" and not "-" */
12869 may_have_traps = 1;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012870 action = ckstrdup(action);
Denys Vlasenkob4f51d32016-10-27 12:55:09 +020012871 }
Eric Andersencb57d552001-06-28 07:25:16 +000012872 }
Denis Vlasenko60818682007-09-28 22:07:23 +000012873 free(trap[signo]);
Eric Andersencb57d552001-06-28 07:25:16 +000012874 trap[signo] = action;
12875 if (signo != 0)
12876 setsignal(signo);
Denis Vlasenkob012b102007-02-19 22:43:01 +000012877 INT_ON;
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010012878 next:
Eric Andersencb57d552001-06-28 07:25:16 +000012879 ap++;
12880 }
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010012881 return exitcode;
Eric Andersencb57d552001-06-28 07:25:16 +000012882}
12883
Eric Andersenc470f442003-07-28 09:56:35 +000012884
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000012885/* ============ Builtins */
Eric Andersenc470f442003-07-28 09:56:35 +000012886
Denys Vlasenko2ec34962014-09-08 16:52:39 +020012887#if ENABLE_ASH_HELP
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012888static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012889helpcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000012890{
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000012891 unsigned col;
12892 unsigned i;
Eric Andersenc470f442003-07-28 09:56:35 +000012893
Denys Vlasenkod6b05eb2009-06-06 20:59:55 +020012894 out1fmt(
Denis Vlasenko34d4d892009-04-04 20:24:37 +000012895 "Built-in commands:\n"
12896 "------------------\n");
Denis Vlasenkob71c6682007-07-21 15:08:09 +000012897 for (col = 0, i = 0; i < ARRAY_SIZE(builtintab); i++) {
Eric Andersenc470f442003-07-28 09:56:35 +000012898 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
Denis Vlasenko52764022007-02-24 13:42:56 +000012899 builtintab[i].name + 1);
Eric Andersenc470f442003-07-28 09:56:35 +000012900 if (col > 60) {
12901 out1fmt("\n");
12902 col = 0;
12903 }
12904 }
Denys Vlasenko2ec34962014-09-08 16:52:39 +020012905# if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko1aa7e472007-11-28 06:49:03 +000012906 {
12907 const char *a = applet_names;
12908 while (*a) {
12909 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), a);
12910 if (col > 60) {
12911 out1fmt("\n");
12912 col = 0;
12913 }
Ron Yorston2b919582016-04-08 11:57:20 +010012914 while (*a++ != '\0')
12915 continue;
Eric Andersenc470f442003-07-28 09:56:35 +000012916 }
12917 }
Denys Vlasenko2ec34962014-09-08 16:52:39 +020012918# endif
Denys Vlasenkoebedb942016-10-02 18:45:09 +020012919 newline_and_flush(stdout);
Eric Andersenc470f442003-07-28 09:56:35 +000012920 return EXIT_SUCCESS;
12921}
Denys Vlasenko2ec34962014-09-08 16:52:39 +020012922#endif
Eric Andersenc470f442003-07-28 09:56:35 +000012923
Flemming Madsend96ffda2013-04-07 18:47:24 +020012924#if MAX_HISTORY
12925static int FAST_FUNC
12926historycmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12927{
12928 show_history(line_input_state);
12929 return EXIT_SUCCESS;
12930}
12931#endif
12932
Eric Andersencb57d552001-06-28 07:25:16 +000012933/*
Eric Andersencb57d552001-06-28 07:25:16 +000012934 * The export and readonly commands.
12935 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012936static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012937exportcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000012938{
12939 struct var *vp;
12940 char *name;
12941 const char *p;
Eric Andersenc470f442003-07-28 09:56:35 +000012942 char **aptr;
Denys Vlasenkod5275882012-10-01 13:41:17 +020012943 char opt;
12944 int flag;
12945 int flag_off;
Eric Andersencb57d552001-06-28 07:25:16 +000012946
Denys Vlasenkod5275882012-10-01 13:41:17 +020012947 /* "readonly" in bash accepts, but ignores -n.
12948 * We do the same: it saves a conditional in nextopt's param.
12949 */
12950 flag_off = 0;
12951 while ((opt = nextopt("np")) != '\0') {
12952 if (opt == 'n')
12953 flag_off = VEXPORT;
12954 }
12955 flag = VEXPORT;
12956 if (argv[0][0] == 'r') {
12957 flag = VREADONLY;
12958 flag_off = 0; /* readonly ignores -n */
12959 }
12960 flag_off = ~flag_off;
12961
12962 /*if (opt_p_not_specified) - bash doesnt check this. Try "export -p NAME" */
12963 {
Denis Vlasenko2da584f2007-02-19 22:44:05 +000012964 aptr = argptr;
12965 name = *aptr;
12966 if (name) {
12967 do {
12968 p = strchr(name, '=');
12969 if (p != NULL) {
12970 p++;
12971 } else {
12972 vp = *findvar(hashvar(name), name);
12973 if (vp) {
Denys Vlasenkod5275882012-10-01 13:41:17 +020012974 vp->flags = ((vp->flags | flag) & flag_off);
Denis Vlasenko2da584f2007-02-19 22:44:05 +000012975 continue;
12976 }
Eric Andersencb57d552001-06-28 07:25:16 +000012977 }
Denys Vlasenkod5275882012-10-01 13:41:17 +020012978 setvar(name, p, (flag & flag_off));
Denis Vlasenko2da584f2007-02-19 22:44:05 +000012979 } while ((name = *++aptr) != NULL);
12980 return 0;
12981 }
Eric Andersencb57d552001-06-28 07:25:16 +000012982 }
Denys Vlasenkod5275882012-10-01 13:41:17 +020012983
12984 /* No arguments. Show the list of exported or readonly vars.
12985 * -n is ignored.
12986 */
Denis Vlasenko2da584f2007-02-19 22:44:05 +000012987 showvars(argv[0], flag, 0);
Eric Andersencb57d552001-06-28 07:25:16 +000012988 return 0;
12989}
12990
Eric Andersencb57d552001-06-28 07:25:16 +000012991/*
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000012992 * Delete a function if it exists.
Eric Andersencb57d552001-06-28 07:25:16 +000012993 */
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +000012994static void
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000012995unsetfunc(const char *name)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012996{
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000012997 struct tblentry *cmdp;
Eric Andersencb57d552001-06-28 07:25:16 +000012998
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000012999 cmdp = cmdlookup(name, 0);
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020013000 if (cmdp != NULL && cmdp->cmdtype == CMDFUNCTION)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000013001 delete_cmd_entry();
Eric Andersenc470f442003-07-28 09:56:35 +000013002}
13003
Eric Andersencb57d552001-06-28 07:25:16 +000013004/*
Eric Andersencb57d552001-06-28 07:25:16 +000013005 * The unset builtin command. We unset the function before we unset the
13006 * variable to allow a function to be unset when there is a readonly variable
13007 * with the same name.
13008 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013009static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013010unsetcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +000013011{
13012 char **ap;
13013 int i;
Eric Andersenc470f442003-07-28 09:56:35 +000013014 int flag = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000013015 int ret = 0;
13016
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020013017 while ((i = nextopt("vf")) != 0) {
Eric Andersenc470f442003-07-28 09:56:35 +000013018 flag = i;
Eric Andersencb57d552001-06-28 07:25:16 +000013019 }
Eric Andersencb57d552001-06-28 07:25:16 +000013020
Denis Vlasenko2da584f2007-02-19 22:44:05 +000013021 for (ap = argptr; *ap; ap++) {
Eric Andersenc470f442003-07-28 09:56:35 +000013022 if (flag != 'f') {
13023 i = unsetvar(*ap);
13024 ret |= i;
13025 if (!(i & 2))
13026 continue;
13027 }
13028 if (flag != 'v')
Eric Andersencb57d552001-06-28 07:25:16 +000013029 unsetfunc(*ap);
Eric Andersencb57d552001-06-28 07:25:16 +000013030 }
Eric Andersenc470f442003-07-28 09:56:35 +000013031 return ret & 1;
Eric Andersencb57d552001-06-28 07:25:16 +000013032}
13033
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000013034static const unsigned char timescmd_str[] ALIGN1 = {
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013035 ' ', offsetof(struct tms, tms_utime),
13036 '\n', offsetof(struct tms, tms_stime),
13037 ' ', offsetof(struct tms, tms_cutime),
13038 '\n', offsetof(struct tms, tms_cstime),
13039 0
13040};
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013041static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013042timescmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013043{
Denys Vlasenko8cd9f342010-06-18 15:36:48 +020013044 unsigned long clk_tck, s, t;
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013045 const unsigned char *p;
13046 struct tms buf;
13047
Bartosz Golaszewski5d2e4092014-06-22 14:01:13 +020013048 clk_tck = bb_clk_tck();
Eric Andersencb57d552001-06-28 07:25:16 +000013049 times(&buf);
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013050
13051 p = timescmd_str;
13052 do {
13053 t = *(clock_t *)(((char *) &buf) + p[1]);
13054 s = t / clk_tck;
Denys Vlasenko8cd9f342010-06-18 15:36:48 +020013055 t = t % clk_tck;
13056 out1fmt("%lum%lu.%03lus%c",
13057 s / 60, s % 60,
13058 (t * 1000) / clk_tck,
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013059 p[0]);
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020013060 p += 2;
13061 } while (*p);
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013062
Eric Andersencb57d552001-06-28 07:25:16 +000013063 return 0;
13064}
13065
Denys Vlasenko0b883582016-12-23 16:49:07 +010013066#if ENABLE_FEATURE_SH_MATH
Eric Andersenc470f442003-07-28 09:56:35 +000013067/*
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020013068 * The let builtin. Partially stolen from GNU Bash, the Bourne Again SHell.
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +000013069 * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
Eric Andersen90898442003-08-06 11:20:52 +000013070 *
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +000013071 * Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
Eric Andersenc470f442003-07-28 09:56:35 +000013072 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013073static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013074letcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersenc470f442003-07-28 09:56:35 +000013075{
Denis Vlasenko68404f12008-03-17 09:00:54 +000013076 arith_t i;
Eric Andersenc470f442003-07-28 09:56:35 +000013077
Denis Vlasenko68404f12008-03-17 09:00:54 +000013078 argv++;
13079 if (!*argv)
Denis Vlasenkob012b102007-02-19 22:43:01 +000013080 ash_msg_and_raise_error("expression expected");
Denis Vlasenko68404f12008-03-17 09:00:54 +000013081 do {
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +000013082 i = ash_arith(*argv);
Denis Vlasenko68404f12008-03-17 09:00:54 +000013083 } while (*++argv);
Eric Andersenc470f442003-07-28 09:56:35 +000013084
Denis Vlasenkod9e15f22006-11-27 16:49:55 +000013085 return !i;
Eric Andersenc470f442003-07-28 09:56:35 +000013086}
Eric Andersenc470f442003-07-28 09:56:35 +000013087#endif
Eric Andersen74bcd162001-07-30 21:41:37 +000013088
Eric Andersenc470f442003-07-28 09:56:35 +000013089/*
Denis Vlasenko59f351c2008-03-25 00:07:12 +000013090 * The read builtin. Options:
13091 * -r Do not interpret '\' specially
13092 * -s Turn off echo (tty only)
13093 * -n NCHARS Read NCHARS max
13094 * -p PROMPT Display PROMPT on stderr (if input is from tty)
13095 * -t SECONDS Timeout after SECONDS (tty or pipe only)
13096 * -u FD Read from given FD instead of fd 0
Eric Andersenc470f442003-07-28 09:56:35 +000013097 * This uses unbuffered input, which may be avoidable in some cases.
Denis Vlasenko59f351c2008-03-25 00:07:12 +000013098 * TODO: bash also has:
13099 * -a ARRAY Read into array[0],[1],etc
13100 * -d DELIM End on DELIM char, not newline
13101 * -e Use line editing (tty only)
Eric Andersenc470f442003-07-28 09:56:35 +000013102 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013103static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013104readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000013105{
Denys Vlasenko73067272010-01-12 22:11:24 +010013106 char *opt_n = NULL;
13107 char *opt_p = NULL;
13108 char *opt_t = NULL;
13109 char *opt_u = NULL;
13110 int read_flags = 0;
13111 const char *r;
Eric Andersenc470f442003-07-28 09:56:35 +000013112 int i;
13113
Denys Vlasenko73067272010-01-12 22:11:24 +010013114 while ((i = nextopt("p:u:rt:n:s")) != '\0') {
Denis Vlasenkobf0a2012006-12-26 10:42:51 +000013115 switch (i) {
Paul Fox02eb9342005-09-07 16:56:02 +000013116 case 'p':
Denys Vlasenko73067272010-01-12 22:11:24 +010013117 opt_p = optionarg;
Paul Fox02eb9342005-09-07 16:56:02 +000013118 break;
Paul Fox02eb9342005-09-07 16:56:02 +000013119 case 'n':
Denys Vlasenko73067272010-01-12 22:11:24 +010013120 opt_n = optionarg;
Paul Fox02eb9342005-09-07 16:56:02 +000013121 break;
13122 case 's':
Denys Vlasenko73067272010-01-12 22:11:24 +010013123 read_flags |= BUILTIN_READ_SILENT;
Paul Fox02eb9342005-09-07 16:56:02 +000013124 break;
Paul Fox02eb9342005-09-07 16:56:02 +000013125 case 't':
Denys Vlasenko73067272010-01-12 22:11:24 +010013126 opt_t = optionarg;
Paul Fox02eb9342005-09-07 16:56:02 +000013127 break;
Paul Fox02eb9342005-09-07 16:56:02 +000013128 case 'r':
Denys Vlasenko73067272010-01-12 22:11:24 +010013129 read_flags |= BUILTIN_READ_RAW;
Paul Fox02eb9342005-09-07 16:56:02 +000013130 break;
Denis Vlasenko59f351c2008-03-25 00:07:12 +000013131 case 'u':
Denys Vlasenko73067272010-01-12 22:11:24 +010013132 opt_u = optionarg;
Denis Vlasenko59f351c2008-03-25 00:07:12 +000013133 break;
Paul Fox02eb9342005-09-07 16:56:02 +000013134 default:
13135 break;
13136 }
Eric Andersenc470f442003-07-28 09:56:35 +000013137 }
Paul Fox02eb9342005-09-07 16:56:02 +000013138
Denys Vlasenko9e71e3c2012-09-06 13:28:10 +020013139 /* "read -s" needs to save/restore termios, can't allow ^C
13140 * to jump out of it.
13141 */
13142 INT_OFF;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020013143 r = shell_builtin_read(setvar0,
Denys Vlasenko73067272010-01-12 22:11:24 +010013144 argptr,
13145 bltinlookup("IFS"), /* can be NULL */
13146 read_flags,
13147 opt_n,
13148 opt_p,
13149 opt_t,
13150 opt_u
13151 );
Denys Vlasenko9e71e3c2012-09-06 13:28:10 +020013152 INT_ON;
Denis Vlasenko46aeab92009-03-31 19:18:17 +000013153
Denys Vlasenko73067272010-01-12 22:11:24 +010013154 if ((uintptr_t)r > 1)
13155 ash_msg_and_raise_error(r);
Denis Vlasenko037576d2007-10-20 18:30:38 +000013156
Denys Vlasenko73067272010-01-12 22:11:24 +010013157 return (uintptr_t)r;
Eric Andersenc470f442003-07-28 09:56:35 +000013158}
13159
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013160static int FAST_FUNC
Denys Vlasenko6283f982015-10-07 16:56:20 +020013161umaskcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000013162{
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013163 static const char permuser[3] ALIGN1 = "ogu";
Eric Andersenc470f442003-07-28 09:56:35 +000013164
Eric Andersenc470f442003-07-28 09:56:35 +000013165 mode_t mask;
Eric Andersenc470f442003-07-28 09:56:35 +000013166 int symbolic_mode = 0;
13167
13168 while (nextopt("S") != '\0') {
13169 symbolic_mode = 1;
13170 }
13171
Denis Vlasenkob012b102007-02-19 22:43:01 +000013172 INT_OFF;
Eric Andersenc470f442003-07-28 09:56:35 +000013173 mask = umask(0);
13174 umask(mask);
Denis Vlasenkob012b102007-02-19 22:43:01 +000013175 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +000013176
Denys Vlasenko6283f982015-10-07 16:56:20 +020013177 if (*argptr == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +000013178 if (symbolic_mode) {
Denys Vlasenko005c4922015-10-10 20:17:12 +020013179 char buf[sizeof(",u=rwx,g=rwx,o=rwx")];
Eric Andersenc470f442003-07-28 09:56:35 +000013180 char *p = buf;
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013181 int i;
Eric Andersenc470f442003-07-28 09:56:35 +000013182
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013183 i = 2;
13184 for (;;) {
Denys Vlasenko005c4922015-10-10 20:17:12 +020013185 *p++ = ',';
Eric Andersenc470f442003-07-28 09:56:35 +000013186 *p++ = permuser[i];
13187 *p++ = '=';
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013188 /* mask is 0..0uuugggooo. i=2 selects uuu bits */
Denys Vlasenko005c4922015-10-10 20:17:12 +020013189 if (!(mask & 0400)) *p++ = 'r';
13190 if (!(mask & 0200)) *p++ = 'w';
13191 if (!(mask & 0100)) *p++ = 'x';
13192 mask <<= 3;
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013193 if (--i < 0)
13194 break;
Eric Andersenc470f442003-07-28 09:56:35 +000013195 }
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013196 *p = '\0';
Denys Vlasenko005c4922015-10-10 20:17:12 +020013197 puts(buf + 1);
Eric Andersenc470f442003-07-28 09:56:35 +000013198 } else {
Denys Vlasenkoec046f72015-10-07 17:57:53 +020013199 out1fmt("%04o\n", mask);
Eric Andersenc470f442003-07-28 09:56:35 +000013200 }
13201 } else {
Denys Vlasenko6283f982015-10-07 16:56:20 +020013202 char *modestr = *argptr;
13203 /* numeric umasks are taken as-is */
13204 /* symbolic umasks are inverted: "umask a=rx" calls umask(222) */
13205 if (!isdigit(modestr[0]))
13206 mask ^= 0777;
Denys Vlasenko5711a2a2015-10-07 17:55:33 +020013207 mask = bb_parse_mode(modestr, mask);
13208 if ((unsigned)mask > 0777) {
Denys Vlasenko6283f982015-10-07 16:56:20 +020013209 ash_msg_and_raise_error("illegal mode: %s", modestr);
Eric Andersenc470f442003-07-28 09:56:35 +000013210 }
Denys Vlasenko6283f982015-10-07 16:56:20 +020013211 if (!isdigit(modestr[0]))
13212 mask ^= 0777;
13213 umask(mask);
Eric Andersenc470f442003-07-28 09:56:35 +000013214 }
13215 return 0;
13216}
13217
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013218static int FAST_FUNC
Denys Vlasenkof3c742f2010-03-06 20:12:00 +010013219ulimitcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersenc470f442003-07-28 09:56:35 +000013220{
Denys Vlasenkof3c742f2010-03-06 20:12:00 +010013221 return shell_builtin_ulimit(argv);
Eric Andersenc470f442003-07-28 09:56:35 +000013222}
13223
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013224/* ============ main() and helpers */
13225
13226/*
13227 * Called to exit the shell.
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013228 */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013229static void
13230exitshell(void)
13231{
13232 struct jmploc loc;
13233 char *p;
13234 int status;
13235
Denys Vlasenkobede2152011-09-04 16:12:33 +020013236#if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT
13237 save_history(line_input_state);
13238#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013239 status = exitstatus;
13240 TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
13241 if (setjmp(loc.loc)) {
Denis Vlasenko7f88e342009-03-19 03:36:18 +000013242 if (exception_type == EXEXIT)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013243 status = exitstatus;
13244 goto out;
13245 }
13246 exception_handler = &loc;
13247 p = trap[0];
13248 if (p) {
13249 trap[0] = NULL;
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020013250 evalskip = 0;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013251 evalstring(p, 0);
Denys Vlasenkof37e1152016-10-07 03:17:28 +020013252 /*free(p); - we'll exit soon */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013253 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013254 out:
Denys Vlasenkof37e1152016-10-07 03:17:28 +020013255 /* dash wraps setjobctl(0) in "if (setjmp(loc.loc) == 0) {...}".
13256 * our setjobctl(0) does not panic if tcsetpgrp fails inside it.
13257 */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013258 setjobctl(0);
Denys Vlasenkocaee80c2016-10-25 20:49:53 +020013259 flush_stdout_stderr();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013260 _exit(status);
13261 /* NOTREACHED */
13262}
13263
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +000013264static void
13265init(void)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013266{
Denys Vlasenko82dd14a2010-05-17 10:10:01 +020013267 /* we will never free this */
13268 basepf.next_to_pgetc = basepf.buf = ckmalloc(IBUFSIZ);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013269
Denys Vlasenko458c1f22016-10-27 23:51:19 +020013270 sigmode[SIGCHLD - 1] = S_DFL;
13271 setsignal(SIGCHLD);
13272
Denys Vlasenko7a7b0342009-12-04 04:18:31 +010013273 /* bash re-enables SIGHUP which is SIG_IGNed on entry.
13274 * Try: "trap '' HUP; bash; echo RET" and type "kill -HUP $$"
13275 */
Denys Vlasenkocacb2cd2010-10-05 00:13:02 +020013276 signal(SIGHUP, SIG_DFL);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013277
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013278 {
13279 char **envp;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013280 const char *p;
13281 struct stat st1, st2;
13282
13283 initvar();
13284 for (envp = environ; envp && *envp; envp++) {
Denys Vlasenkob6838b52016-09-30 11:33:47 +020013285 p = endofname(*envp);
13286 if (p != *envp && *p == '=') {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013287 setvareq(*envp, VEXPORT|VTEXTFIXED);
13288 }
13289 }
13290
Denys Vlasenkoe627ac92016-09-30 14:36:59 +020013291 setvareq((char*)defoptindvar, VTEXTFIXED);
13292
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020013293 setvar0("PPID", utoa(getppid()));
Bernhard Reutner-Fischer80f8cdf2013-11-08 14:25:24 +010013294#if ENABLE_ASH_BASH_COMPAT
13295 p = lookupvar("SHLVL");
Denys Vlasenko5680e982014-01-07 16:12:48 +010013296 setvar("SHLVL", utoa((p ? atoi(p) : 0) + 1), VEXPORT);
Denys Vlasenko3fa97af2014-04-15 11:43:29 +020013297 if (!lookupvar("HOSTNAME")) {
13298 struct utsname uts;
13299 uname(&uts);
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020013300 setvar0("HOSTNAME", uts.nodename);
Denys Vlasenko3fa97af2014-04-15 11:43:29 +020013301 }
Bernhard Reutner-Fischer80f8cdf2013-11-08 14:25:24 +010013302#endif
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013303 p = lookupvar("PWD");
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013304 if (p) {
Denys Vlasenkoef159702016-09-01 11:16:22 +020013305 if (p[0] != '/' || stat(p, &st1) || stat(".", &st2)
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013306 || st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino
13307 ) {
Denys Vlasenkoef159702016-09-01 11:16:22 +020013308 p = NULL;
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013309 }
13310 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013311 setpwd(p, 0);
13312 }
13313}
13314
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013315
13316//usage:#define ash_trivial_usage
Denys Vlasenko6b6af532011-03-08 10:24:17 +010013317//usage: "[-/+OPTIONS] [-/+o OPT]... [-c 'SCRIPT' [ARG0 [ARGS]] / FILE [ARGS]]"
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013318//usage:#define ash_full_usage "\n\n"
13319//usage: "Unix shell interpreter"
13320
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013321/*
13322 * Process the shell command line arguments.
13323 */
13324static void
Denis Vlasenko68404f12008-03-17 09:00:54 +000013325procargs(char **argv)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013326{
13327 int i;
13328 const char *xminusc;
13329 char **xargv;
13330
13331 xargv = argv;
13332 arg0 = xargv[0];
Denis Vlasenko68404f12008-03-17 09:00:54 +000013333 /* if (xargv[0]) - mmm, this is always true! */
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013334 xargv++;
13335 for (i = 0; i < NOPTS; i++)
13336 optlist[i] = 2;
13337 argptr = xargv;
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013338 if (options(/*cmdline:*/ 1)) {
Denis Vlasenko28bf6712008-02-14 15:01:47 +000013339 /* it already printed err message */
13340 raise_exception(EXERROR);
13341 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013342 xargv = argptr;
13343 xminusc = minusc;
13344 if (*xargv == NULL) {
13345 if (xminusc)
13346 ash_msg_and_raise_error(bb_msg_requires_arg, "-c");
13347 sflag = 1;
13348 }
13349 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
13350 iflag = 1;
13351 if (mflag == 2)
13352 mflag = iflag;
13353 for (i = 0; i < NOPTS; i++)
13354 if (optlist[i] == 2)
13355 optlist[i] = 0;
13356#if DEBUG == 2
13357 debug = 1;
13358#endif
13359 /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
13360 if (xminusc) {
13361 minusc = *xargv++;
13362 if (*xargv)
13363 goto setarg0;
13364 } else if (!sflag) {
13365 setinputfile(*xargv, 0);
13366 setarg0:
13367 arg0 = *xargv++;
13368 commandname = arg0;
13369 }
13370
13371 shellparam.p = xargv;
13372#if ENABLE_ASH_GETOPTS
13373 shellparam.optind = 1;
13374 shellparam.optoff = -1;
13375#endif
Denis Vlasenko01631112007-12-16 17:20:38 +000013376 /* assert(shellparam.malloced == 0 && shellparam.nparam == 0); */
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013377 while (*xargv) {
13378 shellparam.nparam++;
13379 xargv++;
13380 }
13381 optschanged();
13382}
13383
13384/*
Denys Vlasenko2eb0a7e2016-10-27 11:28:59 +020013385 * Read /etc/profile, ~/.profile, $ENV.
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013386 */
13387static void
13388read_profile(const char *name)
13389{
Denys Vlasenko2eb0a7e2016-10-27 11:28:59 +020013390 name = expandstr(name);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013391 if (setinputfile(name, INPUT_PUSH_FILE | INPUT_NOFILE_OK) < 0)
13392 return;
Denys Vlasenko0840c912016-10-01 15:27:44 +020013393 cmdloop(0);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013394 popfile();
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013395}
13396
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013397/*
13398 * This routine is called when an error or an interrupt occurs in an
13399 * interactive shell and control is returned to the main command loop.
Denys Vlasenko5ac04f22016-10-27 14:46:50 +020013400 * (In dash, this function is auto-generated by build machinery).
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013401 */
13402static void
13403reset(void)
13404{
13405 /* from eval.c: */
13406 evalskip = 0;
13407 loopnest = 0;
Denys Vlasenko5ac04f22016-10-27 14:46:50 +020013408
13409 /* from expand.c: */
13410 ifsfree();
13411
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013412 /* from input.c: */
Denis Vlasenko41eb3002008-11-28 03:42:31 +000013413 g_parsefile->left_in_buffer = 0;
13414 g_parsefile->left_in_line = 0; /* clear input buffer */
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013415 popallfiles();
Denys Vlasenko5ac04f22016-10-27 14:46:50 +020013416
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013417 /* from redir.c: */
Denys Vlasenkoe19923f2016-10-26 15:38:44 +020013418 while (redirlist)
13419 popredir(/*drop:*/ 0, /*restore:*/ 0);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013420}
13421
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013422#if PROFILE
13423static short profile_buf[16384];
13424extern int etext();
13425#endif
13426
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013427/*
13428 * Main routine. We initialize things, parse the arguments, execute
13429 * profiles if we're a login shell, and then call cmdloop to execute
13430 * commands. The setjmp call sets up the location to jump to when an
13431 * exception occurs. When an exception occurs the variable "state"
13432 * is used to figure out how far we had gotten.
13433 */
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +000013434int ash_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013435int ash_main(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013436{
Denis Vlasenko4e12b1a2008-12-23 23:36:47 +000013437 volatile smallint state;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013438 struct jmploc jmploc;
13439 struct stackmark smark;
13440
Denis Vlasenko01631112007-12-16 17:20:38 +000013441 /* Initialize global data */
13442 INIT_G_misc();
13443 INIT_G_memstack();
13444 INIT_G_var();
Denis Vlasenkoee87ebf2007-12-21 22:18:16 +000013445#if ENABLE_ASH_ALIAS
Denis Vlasenko01631112007-12-16 17:20:38 +000013446 INIT_G_alias();
Denis Vlasenkoee87ebf2007-12-21 22:18:16 +000013447#endif
Denis Vlasenko01631112007-12-16 17:20:38 +000013448 INIT_G_cmdtable();
13449
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013450#if PROFILE
13451 monitor(4, etext, profile_buf, sizeof(profile_buf), 50);
13452#endif
13453
13454#if ENABLE_FEATURE_EDITING
13455 line_input_state = new_line_input_t(FOR_SHELL | WITH_PATH_LOOKUP);
13456#endif
13457 state = 0;
13458 if (setjmp(jmploc.loc)) {
Denis Vlasenko7f88e342009-03-19 03:36:18 +000013459 smallint e;
Denis Vlasenko4e12b1a2008-12-23 23:36:47 +000013460 smallint s;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013461
13462 reset();
13463
Denis Vlasenko7f88e342009-03-19 03:36:18 +000013464 e = exception_type;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013465 s = state;
Denys Vlasenkob563f622010-09-25 17:15:13 +020013466 if (e == EXEXIT || s == 0 || iflag == 0 || shlvl) {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013467 exitshell();
Denys Vlasenkob563f622010-09-25 17:15:13 +020013468 }
13469 if (e == EXINT) {
Denys Vlasenko9c541002015-10-07 15:44:36 +020013470 newline_and_flush(stderr);
Denys Vlasenkob563f622010-09-25 17:15:13 +020013471 }
Denis Vlasenko7f88e342009-03-19 03:36:18 +000013472
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013473 popstackmark(&smark);
13474 FORCE_INT_ON; /* enable interrupts */
13475 if (s == 1)
13476 goto state1;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000013477 if (s == 2)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013478 goto state2;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000013479 if (s == 3)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013480 goto state3;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000013481 goto state4;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013482 }
13483 exception_handler = &jmploc;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013484 rootpid = getpid();
13485
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013486 init();
13487 setstackmark(&smark);
Denis Vlasenko68404f12008-03-17 09:00:54 +000013488 procargs(argv);
Denys Vlasenko474ed062016-10-30 18:30:29 +010013489#if DEBUG
13490 TRACE(("Shell args: "));
13491 trace_puts_args(argv);
13492#endif
Denis Vlasenko68404f12008-03-17 09:00:54 +000013493
Denys Vlasenko6088e132010-12-25 23:58:42 +010013494 if (argv[0] && argv[0][0] == '-')
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013495 isloginsh = 1;
13496 if (isloginsh) {
Stefan Hellermann4ef14392013-03-15 02:45:50 +010013497 const char *hp;
13498
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013499 state = 1;
13500 read_profile("/etc/profile");
13501 state1:
13502 state = 2;
Stefan Hellermann4ef14392013-03-15 02:45:50 +010013503 hp = lookupvar("HOME");
Denys Vlasenko2eb0a7e2016-10-27 11:28:59 +020013504 if (hp)
13505 read_profile("$HOME/.profile");
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013506 }
13507 state2:
13508 state = 3;
13509 if (
13510#ifndef linux
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013511 getuid() == geteuid() && getgid() == getegid() &&
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013512#endif
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013513 iflag
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013514 ) {
Denys Vlasenko2eb0a7e2016-10-27 11:28:59 +020013515 const char *shinit = lookupvar("ENV");
13516 if (shinit != NULL && *shinit != '\0')
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013517 read_profile(shinit);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013518 }
Denys Vlasenko2eb0a7e2016-10-27 11:28:59 +020013519 popstackmark(&smark);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013520 state3:
13521 state = 4;
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000013522 if (minusc) {
13523 /* evalstring pushes parsefile stack.
13524 * Ensure we don't falsely claim that 0 (stdin)
Denis Vlasenko5368ad52009-03-20 10:20:08 +000013525 * is one of stacked source fds.
13526 * Testcase: ash -c 'exec 1>&0' must not complain. */
Denys Vlasenko79b3d422010-06-03 04:29:08 +020013527 // if (!sflag) g_parsefile->pf_fd = -1;
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +020013528 // ^^ not necessary since now we special-case fd 0
13529 // in is_hidden_fd() to not be considered "hidden fd"
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013530 evalstring(minusc, 0);
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000013531 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013532
13533 if (sflag || minusc == NULL) {
Denys Vlasenko4840ae82011-09-04 15:28:03 +020013534#if MAX_HISTORY > 0 && ENABLE_FEATURE_EDITING_SAVEHISTORY
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +000013535 if (iflag) {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013536 const char *hp = lookupvar("HISTFILE");
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010013537 if (!hp) {
13538 hp = lookupvar("HOME");
Stefan Hellermann4ef14392013-03-15 02:45:50 +010013539 if (hp) {
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010013540 hp = concat_path_file(hp, ".ash_history");
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020013541 setvar0("HISTFILE", hp);
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010013542 free((char*)hp);
13543 hp = lookupvar("HISTFILE");
13544 }
13545 }
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000013546 if (hp)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013547 line_input_state->hist_file = hp;
Denys Vlasenko2c4de5b2011-03-31 13:16:52 +020013548# if ENABLE_FEATURE_SH_HISTFILESIZE
13549 hp = lookupvar("HISTFILESIZE");
13550 line_input_state->max_history = size_from_HISTFILESIZE(hp);
13551# endif
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013552 }
13553#endif
13554 state4: /* XXX ??? - why isn't this before the "if" statement */
13555 cmdloop(1);
13556 }
13557#if PROFILE
13558 monitor(0);
13559#endif
13560#ifdef GPROF
13561 {
13562 extern void _mcleanup(void);
13563 _mcleanup();
13564 }
13565#endif
Denys Vlasenkob563f622010-09-25 17:15:13 +020013566 TRACE(("End of main reached\n"));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013567 exitshell();
13568 /* NOTREACHED */
13569}
13570
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013571
Eric Andersendf82f612001-06-28 07:46:40 +000013572/*-
13573 * Copyright (c) 1989, 1991, 1993, 1994
Eric Andersen2870d962001-07-02 17:27:21 +000013574 * The Regents of the University of California. All rights reserved.
Eric Andersendf82f612001-06-28 07:46:40 +000013575 *
13576 * This code is derived from software contributed to Berkeley by
13577 * Kenneth Almquist.
13578 *
13579 * Redistribution and use in source and binary forms, with or without
13580 * modification, are permitted provided that the following conditions
13581 * are met:
13582 * 1. Redistributions of source code must retain the above copyright
13583 * notice, this list of conditions and the following disclaimer.
13584 * 2. Redistributions in binary form must reproduce the above copyright
13585 * notice, this list of conditions and the following disclaimer in the
13586 * documentation and/or other materials provided with the distribution.
"Vladimir N. Oleynik"ddc280e2005-12-15 12:01:49 +000013587 * 3. Neither the name of the University nor the names of its contributors
Eric Andersendf82f612001-06-28 07:46:40 +000013588 * may be used to endorse or promote products derived from this software
13589 * without specific prior written permission.
13590 *
13591 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
13592 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
13593 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
13594 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
13595 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
13596 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
13597 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
13598 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
13599 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
13600 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
13601 * SUCH DAMAGE.
13602 */