blob: 87f2127a1f491d81da431e2692a2bbe8cb94a0dd [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 */
18
Eric Andersenc470f442003-07-28 09:56:35 +000019/*
Denis Vlasenko653d8e72009-03-19 21:59:35 +000020 * The following should be set to reflect the type of system you have:
Eric Andersenc470f442003-07-28 09:56:35 +000021 * JOBS -> 1 if you have Berkeley job control, 0 otherwise.
22 * define SYSV if you are running under System V.
23 * define DEBUG=1 to compile in debugging ('set -o debug' to turn on)
24 * define DEBUG=2 to compile in and turn on debugging.
25 *
Denys Vlasenkof451b2c2012-06-09 02:06:57 +020026 * When debugging is on (DEBUG is 1 and "set -o debug" was executed),
27 * debugging info will be written to ./trace and a quit signal
28 * will generate a core dump.
Eric Andersenc470f442003-07-28 09:56:35 +000029 */
Denis Vlasenkof1733952009-03-19 23:21:55 +000030#define DEBUG 0
Denis Vlasenko653d8e72009-03-19 21:59:35 +000031/* Tweak debug output verbosity here */
32#define DEBUG_TIME 0
33#define DEBUG_PID 1
34#define DEBUG_SIG 1
Denys Vlasenko06b11492016-11-04 16:43:18 +010035#define DEBUG_INTONOFF 0
Denis Vlasenko653d8e72009-03-19 21:59:35 +000036
Eric Andersenc470f442003-07-28 09:56:35 +000037#define PROFILE 0
Denis Vlasenko0e6f6612008-02-15 15:02:15 +000038
Denis Vlasenko0e6f6612008-02-15 15:02:15 +000039#define JOBS ENABLE_ASH_JOB_CONTROL
Eric Andersenc470f442003-07-28 09:56:35 +000040
Denis Vlasenkob012b102007-02-19 22:43:01 +000041#include <setjmp.h>
42#include <fnmatch.h>
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020043#include <sys/times.h>
Denys Vlasenko3fa97af2014-04-15 11:43:29 +020044#include <sys/utsname.h> /* for setting $HOSTNAME */
Denys Vlasenko73067272010-01-12 22:11:24 +010045
Denys Vlasenko20704f02011-03-23 17:59:27 +010046#include "busybox.h" /* for applet_names */
Denys Vlasenko20704f02011-03-23 17:59:27 +010047
Denys Vlasenko514b51d2016-10-01 14:33:08 +020048#if defined(__ANDROID_API__) && __ANDROID_API__ <= 24
49/* Bionic at least up to version 24 has no glob() */
50# undef ENABLE_ASH_INTERNAL_GLOB
Denys Vlasenko08089c72016-10-01 14:47:52 +020051# define ENABLE_ASH_INTERNAL_GLOB 1
Denys Vlasenko514b51d2016-10-01 14:33:08 +020052#endif
53
54#if !ENABLE_ASH_INTERNAL_GLOB
55# include <glob.h>
56#endif
57
58#include "unicode.h"
Denys Vlasenko73067272010-01-12 22:11:24 +010059#include "shell_common.h"
Denys Vlasenko26777aa2010-11-22 23:49:10 +010060#if ENABLE_SH_MATH_SUPPORT
61# include "math.h"
62#endif
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020063#if ENABLE_ASH_RANDOM_SUPPORT
64# include "random.h"
Denys Vlasenko36df0482009-10-19 16:07:28 +020065#else
66# define CLEAR_RANDOM_T(rnd) ((void)0)
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020067#endif
Denis Vlasenko61befda2008-11-25 01:36:03 +000068
Denys Vlasenko1fcbff22010-06-26 02:40:08 +020069#include "NUM_APPLETS.h"
Denys Vlasenko14974842010-03-23 01:08:26 +010070#if NUM_APPLETS == 1
Denis Vlasenko61befda2008-11-25 01:36:03 +000071/* STANDALONE does not make sense, and won't compile */
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020072# undef CONFIG_FEATURE_SH_STANDALONE
73# undef ENABLE_FEATURE_SH_STANDALONE
74# undef IF_FEATURE_SH_STANDALONE
Denys Vlasenko14974842010-03-23 01:08:26 +010075# undef IF_NOT_FEATURE_SH_STANDALONE
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020076# define ENABLE_FEATURE_SH_STANDALONE 0
77# define IF_FEATURE_SH_STANDALONE(...)
78# define IF_NOT_FEATURE_SH_STANDALONE(...) __VA_ARGS__
Eric Andersencb57d552001-06-28 07:25:16 +000079#endif
80
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000081#ifndef PIPE_BUF
Denis Vlasenko653d8e72009-03-19 21:59:35 +000082# define PIPE_BUF 4096 /* amount of buffering in a pipe */
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000083#endif
84
Denys Vlasenko153fcaa2010-02-21 05:17:41 +010085#if !BB_MMU
Denis Vlasenko653d8e72009-03-19 21:59:35 +000086# error "Do not even bother, ash will not run on NOMMU machine"
Denis Vlasenkob012b102007-02-19 22:43:01 +000087#endif
88
Denys Vlasenko771f1992010-07-16 14:31:34 +020089//config:config ASH
90//config: bool "ash"
91//config: default y
92//config: depends on !NOMMU
93//config: help
94//config: Tha 'ash' shell adds about 60k in the default configuration and is
95//config: the most complete and most pedantically correct shell included with
96//config: busybox. This shell is actually a derivative of the Debian 'dash'
97//config: shell (by Herbert Xu), which was created by porting the 'ash' shell
98//config: (written by Kenneth Almquist) from NetBSD.
99//config:
Denys Vlasenko514b51d2016-10-01 14:33:08 +0200100//config:config ASH_OPTIMIZE_FOR_SIZE
101//config: bool "Optimize for size instead of speed"
102//config: default y
103//config: depends on ASH
104//config: help
105//config: Compile ash for reduced size at the price of speed.
106//config:
107//config:config ASH_INTERNAL_GLOB
108//config: bool "Use internal glob() implementation"
109//config: default n
110//config: depends on ASH
111//config: help
112//config: Do not use glob() function from libc, use internal implementation.
113//config: Use this if you are getting "glob.h: No such file or directory"
114//config: or similar build errors.
115//config:
116//config:config ASH_RANDOM_SUPPORT
117//config: bool "Pseudorandom generator and $RANDOM variable"
118//config: default y
119//config: depends on ASH
120//config: help
121//config: Enable pseudorandom generator and dynamic variable "$RANDOM".
122//config: Each read of "$RANDOM" will generate a new pseudorandom value.
123//config: You can reset the generator by using a specified start value.
124//config: After "unset RANDOM" the generator will switch off and this
125//config: variable will no longer have special treatment.
126//config:
127//config:config ASH_EXPAND_PRMT
128//config: bool "Expand prompt string"
129//config: default y
130//config: depends on ASH
131//config: help
132//config: "PS#" may contain volatile content, such as backquote commands.
133//config: This option recreates the prompt string from the environment
134//config: variable each time it is displayed.
135//config:
Denys Vlasenko771f1992010-07-16 14:31:34 +0200136//config:config ASH_BASH_COMPAT
137//config: bool "bash-compatible extensions"
138//config: default y
139//config: depends on ASH
140//config: help
141//config: Enable bash-compatible extensions.
142//config:
Denys Vlasenko046341e2011-02-04 17:53:59 +0100143//config:config ASH_IDLE_TIMEOUT
144//config: bool "Idle timeout variable"
145//config: default n
146//config: depends on ASH
147//config: help
Denys Vlasenko66c5b122011-02-08 05:07:02 +0100148//config: Enables bash-like auto-logout after $TMOUT seconds of idle time.
Denys Vlasenko046341e2011-02-04 17:53:59 +0100149//config:
Denys Vlasenko771f1992010-07-16 14:31:34 +0200150//config:config ASH_JOB_CONTROL
151//config: bool "Job control"
152//config: default y
153//config: depends on ASH
154//config: help
155//config: Enable job control in the ash shell.
156//config:
157//config:config ASH_ALIAS
Denys Vlasenko8c52f802011-02-04 17:36:21 +0100158//config: bool "Alias support"
Denys Vlasenko771f1992010-07-16 14:31:34 +0200159//config: default y
160//config: depends on ASH
161//config: help
162//config: Enable alias support in the ash shell.
163//config:
164//config:config ASH_GETOPTS
165//config: bool "Builtin getopt to parse positional parameters"
166//config: default y
167//config: depends on ASH
168//config: help
Denys Vlasenko8c52f802011-02-04 17:36:21 +0100169//config: Enable support for getopts builtin in ash.
Denys Vlasenko771f1992010-07-16 14:31:34 +0200170//config:
171//config:config ASH_BUILTIN_ECHO
172//config: bool "Builtin version of 'echo'"
173//config: default y
174//config: depends on ASH
175//config: help
Denys Vlasenko8c52f802011-02-04 17:36:21 +0100176//config: Enable support for echo builtin in ash.
Denys Vlasenko771f1992010-07-16 14:31:34 +0200177//config:
178//config:config ASH_BUILTIN_PRINTF
179//config: bool "Builtin version of 'printf'"
180//config: default y
181//config: depends on ASH
182//config: help
Denys Vlasenko8c52f802011-02-04 17:36:21 +0100183//config: Enable support for printf builtin in ash.
Denys Vlasenko771f1992010-07-16 14:31:34 +0200184//config:
185//config:config ASH_BUILTIN_TEST
186//config: bool "Builtin version of 'test'"
187//config: default y
188//config: depends on ASH
189//config: help
Denys Vlasenko8c52f802011-02-04 17:36:21 +0100190//config: Enable support for test builtin in ash.
Denys Vlasenko771f1992010-07-16 14:31:34 +0200191//config:
Denys Vlasenko2ec34962014-09-08 16:52:39 +0200192//config:config ASH_HELP
193//config: bool "help builtin"
194//config: default y
195//config: depends on ASH
196//config: help
197//config: Enable help builtin in ash.
198//config:
Denys Vlasenko771f1992010-07-16 14:31:34 +0200199//config:config ASH_CMDCMD
200//config: bool "'command' command to override shell builtins"
201//config: default y
202//config: depends on ASH
203//config: help
204//config: Enable support for the ash 'command' builtin, which allows
205//config: you to run the specified command with the specified arguments,
206//config: even when there is an ash builtin command with the same name.
207//config:
208//config:config ASH_MAIL
209//config: bool "Check for new mail on interactive shells"
210//config: default n
211//config: depends on ASH
212//config: help
Denys Vlasenko8c52f802011-02-04 17:36:21 +0100213//config: Enable "check for new mail" function in the ash shell.
Denys Vlasenko771f1992010-07-16 14:31:34 +0200214//config:
Denys Vlasenko771f1992010-07-16 14:31:34 +0200215
Denys Vlasenko20704f02011-03-23 17:59:27 +0100216//applet:IF_ASH(APPLET(ash, BB_DIR_BIN, BB_SUID_DROP))
217//applet:IF_FEATURE_SH_IS_ASH(APPLET_ODDNAME(sh, ash, BB_DIR_BIN, BB_SUID_DROP, sh))
218//applet:IF_FEATURE_BASH_IS_ASH(APPLET_ODDNAME(bash, ash, BB_DIR_BIN, BB_SUID_DROP, bash))
219
220//kbuild:lib-$(CONFIG_ASH) += ash.o ash_ptr_hack.o shell_common.o
221//kbuild:lib-$(CONFIG_ASH_RANDOM_SUPPORT) += random.o
222
Denis Vlasenkob012b102007-02-19 22:43:01 +0000223
Denis Vlasenko01631112007-12-16 17:20:38 +0000224/* ============ Hash table sizes. Configurable. */
225
226#define VTABSIZE 39
227#define ATABSIZE 39
228#define CMDTABLESIZE 31 /* should be prime */
229
230
Denis Vlasenkob012b102007-02-19 22:43:01 +0000231/* ============ Shell options */
232
233static const char *const optletters_optnames[] = {
234 "e" "errexit",
235 "f" "noglob",
236 "I" "ignoreeof",
237 "i" "interactive",
238 "m" "monitor",
239 "n" "noexec",
240 "s" "stdin",
241 "x" "xtrace",
242 "v" "verbose",
243 "C" "noclobber",
244 "a" "allexport",
245 "b" "notify",
246 "u" "nounset",
Denys Vlasenkoe9ac32a2009-12-05 02:01:25 +0100247 "\0" "vi"
Michael Abbott359da5e2009-12-04 23:03:29 +0100248#if ENABLE_ASH_BASH_COMPAT
Denys Vlasenkoe9ac32a2009-12-05 02:01:25 +0100249 ,"\0" "pipefail"
Michael Abbott359da5e2009-12-04 23:03:29 +0100250#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +0000251#if DEBUG
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000252 ,"\0" "nolog"
253 ,"\0" "debug"
Denis Vlasenkob012b102007-02-19 22:43:01 +0000254#endif
255};
256
Denys Vlasenko285ad152009-12-04 23:02:27 +0100257#define optletters(n) optletters_optnames[n][0]
258#define optnames(n) (optletters_optnames[n] + 1)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000259
Denis Vlasenko80b8b392007-06-25 10:55:35 +0000260enum { NOPTS = ARRAY_SIZE(optletters_optnames) };
Denis Vlasenkob012b102007-02-19 22:43:01 +0000261
Eric Andersenc470f442003-07-28 09:56:35 +0000262
Denis Vlasenkob012b102007-02-19 22:43:01 +0000263/* ============ Misc data */
Eric Andersenc470f442003-07-28 09:56:35 +0000264
Denys Vlasenkoea8b2522010-06-02 12:57:26 +0200265#define msg_illnum "Illegal number: %s"
Denis Vlasenkoaa744452007-02-23 01:04:22 +0000266
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +0000267/*
Eric Andersenc470f442003-07-28 09:56:35 +0000268 * We enclose jmp_buf in a structure so that we can declare pointers to
269 * jump locations. The global variable handler contains the location to
Denis Vlasenkof1733952009-03-19 23:21:55 +0000270 * jump to when an exception occurs, and the global variable exception_type
Eric Andersenaff114c2004-04-14 17:51:38 +0000271 * contains a code identifying the exception. To implement nested
Eric Andersenc470f442003-07-28 09:56:35 +0000272 * exception handlers, the user should save the value of handler on entry
273 * to an inner scope, set handler to point to a jmploc structure for the
274 * inner scope, and restore handler on exit from the scope.
275 */
Eric Andersenc470f442003-07-28 09:56:35 +0000276struct jmploc {
277 jmp_buf loc;
278};
Denis Vlasenko01631112007-12-16 17:20:38 +0000279
280struct globals_misc {
Denys Vlasenko4d12e942016-10-01 16:03:11 +0200281 uint8_t exitstatus; /* exit status of last command */
282 uint8_t back_exitstatus;/* exit status of backquoted command */
283 smallint job_warning; /* user was warned about stopped jobs (can be 2, 1 or 0). */
284 int rootpid; /* pid of main shell */
Denis Vlasenko01631112007-12-16 17:20:38 +0000285 /* shell level: 0 for the main shell, 1 for its children, and so on */
286 int shlvl;
287#define rootshell (!shlvl)
288 char *minusc; /* argument to -c option */
289
290 char *curdir; // = nullstr; /* current working directory */
291 char *physdir; // = nullstr; /* physical working directory */
292
293 char *arg0; /* value of $0 */
294
295 struct jmploc *exception_handler;
Denis Vlasenko991a1da2008-02-10 19:02:53 +0000296
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200297 volatile int suppress_int; /* counter */
298 volatile /*sig_atomic_t*/ smallint pending_int; /* 1 = got SIGINT */
Denys Vlasenko458c1f22016-10-27 23:51:19 +0200299 volatile /*sig_atomic_t*/ smallint got_sigchld; /* 1 = got SIGCHLD */
Denys Vlasenko8f7b0242016-10-28 17:16:11 +0200300 volatile /*sig_atomic_t*/ smallint pending_sig; /* last pending signal */
Denis Vlasenko7f88e342009-03-19 03:36:18 +0000301 smallint exception_type; /* kind of exception (0..5) */
Denis Vlasenko01631112007-12-16 17:20:38 +0000302 /* exceptions */
Eric Andersenc470f442003-07-28 09:56:35 +0000303#define EXINT 0 /* SIGINT received */
304#define EXERROR 1 /* a generic error */
Eric Andersenc470f442003-07-28 09:56:35 +0000305#define EXEXIT 4 /* exit the shell */
Eric Andersen2870d962001-07-02 17:27:21 +0000306
Denis Vlasenko01631112007-12-16 17:20:38 +0000307 smallint isloginsh;
Denis Vlasenkob07a4962008-06-22 13:16:23 +0000308 char nullstr[1]; /* zero length string */
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000309
310 char optlist[NOPTS];
311#define eflag optlist[0]
312#define fflag optlist[1]
313#define Iflag optlist[2]
314#define iflag optlist[3]
315#define mflag optlist[4]
316#define nflag optlist[5]
317#define sflag optlist[6]
318#define xflag optlist[7]
319#define vflag optlist[8]
320#define Cflag optlist[9]
321#define aflag optlist[10]
322#define bflag optlist[11]
323#define uflag optlist[12]
324#define viflag optlist[13]
Michael Abbott359da5e2009-12-04 23:03:29 +0100325#if ENABLE_ASH_BASH_COMPAT
326# define pipefail optlist[14]
327#else
328# define pipefail 0
329#endif
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000330#if DEBUG
Michael Abbott359da5e2009-12-04 23:03:29 +0100331# define nolog optlist[14 + ENABLE_ASH_BASH_COMPAT]
332# define debug optlist[15 + ENABLE_ASH_BASH_COMPAT]
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000333#endif
334
335 /* trap handler commands */
Denis Vlasenko01631112007-12-16 17:20:38 +0000336 /*
337 * Sigmode records the current value of the signal handlers for the various
338 * modes. A value of zero means that the current handler is not known.
Denis Vlasenkof8535cc2008-12-03 10:36:26 +0000339 * S_HARD_IGN indicates that the signal was ignored on entry to the shell.
Denis Vlasenko01631112007-12-16 17:20:38 +0000340 */
341 char sigmode[NSIG - 1];
Denis Vlasenkof8535cc2008-12-03 10:36:26 +0000342#define S_DFL 1 /* default signal handling (SIG_DFL) */
343#define S_CATCH 2 /* signal is caught */
344#define S_IGN 3 /* signal is ignored (SIG_IGN) */
Denys Vlasenkoe5814a52016-07-16 18:33:55 +0200345#define S_HARD_IGN 4 /* signal is ignored permanently */
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +0000346
Denis Vlasenko01631112007-12-16 17:20:38 +0000347 /* indicates specified signal received */
Denis Vlasenko4b875702009-03-19 13:30:04 +0000348 uint8_t gotsig[NSIG - 1]; /* offset by 1: "signal" 0 is meaningless */
Denys Vlasenko238bf182010-05-18 15:49:07 +0200349 uint8_t may_have_traps; /* 0: definitely no traps are set, 1: some traps may be set */
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000350 char *trap[NSIG];
Denys Vlasenko21d87d42009-09-25 00:06:51 +0200351 char **trap_ptr; /* used only by "trap hack" */
Denis Vlasenko448d30e2008-06-27 00:24:11 +0000352
353 /* Rarely referenced stuff */
354#if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenko3ea2e822009-10-09 20:59:04 +0200355 random_t random_gen;
Denis Vlasenko448d30e2008-06-27 00:24:11 +0000356#endif
357 pid_t backgndpid; /* pid of last background process */
Denis Vlasenko01631112007-12-16 17:20:38 +0000358};
Denis Vlasenko574f2f42008-02-27 18:41:59 +0000359extern struct globals_misc *const ash_ptr_to_globals_misc;
360#define G_misc (*ash_ptr_to_globals_misc)
Denys Vlasenko4d12e942016-10-01 16:03:11 +0200361#define exitstatus (G_misc.exitstatus )
362#define back_exitstatus (G_misc.back_exitstatus )
363#define job_warning (G_misc.job_warning)
Denis Vlasenko26bc57d2008-06-27 00:29:34 +0000364#define rootpid (G_misc.rootpid )
365#define shlvl (G_misc.shlvl )
366#define minusc (G_misc.minusc )
367#define curdir (G_misc.curdir )
368#define physdir (G_misc.physdir )
369#define arg0 (G_misc.arg0 )
Denis Vlasenko01631112007-12-16 17:20:38 +0000370#define exception_handler (G_misc.exception_handler)
Denis Vlasenko7f88e342009-03-19 03:36:18 +0000371#define exception_type (G_misc.exception_type )
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200372#define suppress_int (G_misc.suppress_int )
373#define pending_int (G_misc.pending_int )
Denys Vlasenko458c1f22016-10-27 23:51:19 +0200374#define got_sigchld (G_misc.got_sigchld )
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200375#define pending_sig (G_misc.pending_sig )
Denis Vlasenko26bc57d2008-06-27 00:29:34 +0000376#define isloginsh (G_misc.isloginsh )
377#define nullstr (G_misc.nullstr )
378#define optlist (G_misc.optlist )
379#define sigmode (G_misc.sigmode )
380#define gotsig (G_misc.gotsig )
Denys Vlasenko238bf182010-05-18 15:49:07 +0200381#define may_have_traps (G_misc.may_have_traps )
Denis Vlasenko26bc57d2008-06-27 00:29:34 +0000382#define trap (G_misc.trap )
Denys Vlasenko21d87d42009-09-25 00:06:51 +0200383#define trap_ptr (G_misc.trap_ptr )
Denys Vlasenko3ea2e822009-10-09 20:59:04 +0200384#define random_gen (G_misc.random_gen )
Denis Vlasenko448d30e2008-06-27 00:24:11 +0000385#define backgndpid (G_misc.backgndpid )
Denis Vlasenko01631112007-12-16 17:20:38 +0000386#define INIT_G_misc() do { \
Denis Vlasenko574f2f42008-02-27 18:41:59 +0000387 (*(struct globals_misc**)&ash_ptr_to_globals_misc) = xzalloc(sizeof(G_misc)); \
388 barrier(); \
Denis Vlasenko01631112007-12-16 17:20:38 +0000389 curdir = nullstr; \
390 physdir = nullstr; \
Denys Vlasenko21d87d42009-09-25 00:06:51 +0200391 trap_ptr = trap; \
Denis Vlasenko01631112007-12-16 17:20:38 +0000392} while (0)
393
394
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000395/* ============ DEBUG */
396#if DEBUG
397static void trace_printf(const char *fmt, ...);
398static void trace_vprintf(const char *fmt, va_list va);
399# define TRACE(param) trace_printf param
400# define TRACEV(param) trace_vprintf param
Denis Vlasenko1bb3d7e2009-03-20 07:45:36 +0000401# define close(fd) do { \
402 int dfd = (fd); \
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +0000403 if (close(dfd) < 0) \
Denys Vlasenko883cea42009-07-11 15:31:59 +0200404 bb_error_msg("bug on %d: closing %d(0x%x)", \
Denis Vlasenko1bb3d7e2009-03-20 07:45:36 +0000405 __LINE__, dfd, dfd); \
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +0000406} while (0)
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000407#else
408# define TRACE(param)
409# define TRACEV(param)
410#endif
411
412
Denis Vlasenko559691a2008-10-05 18:39:31 +0000413/* ============ Utility functions */
Denys Vlasenko1961aea2013-02-26 00:36:53 +0100414#define is_name(c) ((c) == '_' || isalpha((unsigned char)(c)))
415#define is_in_name(c) ((c) == '_' || isalnum((unsigned char)(c)))
416
Denys Vlasenko37dc08b2016-10-02 04:38:07 +0200417static int
418isdigit_str9(const char *str)
Denis Vlasenko559691a2008-10-05 18:39:31 +0000419{
420 int maxlen = 9 + 1; /* max 9 digits: 999999999 */
421 while (--maxlen && isdigit(*str))
422 str++;
423 return (*str == '\0');
424}
Denis Vlasenko01631112007-12-16 17:20:38 +0000425
Denys Vlasenko37dc08b2016-10-02 04:38:07 +0200426static const char *
427var_end(const char *var)
Denys Vlasenko8837c5d2010-06-02 12:56:18 +0200428{
429 while (*var)
430 if (*var++ == '=')
431 break;
432 return var;
433}
434
Denis Vlasenko559691a2008-10-05 18:39:31 +0000435
436/* ============ Interrupts / exceptions */
Denys Vlasenko66c5b122011-02-08 05:07:02 +0100437
438static void exitshell(void) NORETURN;
439
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +0000440/*
Eric Andersen2870d962001-07-02 17:27:21 +0000441 * These macros allow the user to suspend the handling of interrupt signals
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +0000442 * over a period of time. This is similar to SIGHOLD or to sigblock, but
Eric Andersen2870d962001-07-02 17:27:21 +0000443 * much more efficient and portable. (But hacking the kernel is so much
444 * more fun than worrying about efficiency and portability. :-))
445 */
Denys Vlasenko06b11492016-11-04 16:43:18 +0100446#if DEBUG_INTONOFF
447# define INT_OFF do { \
448 TRACE(("%s:%d INT_OFF(%d)\n", __func__, __LINE__, suppress_int)); \
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200449 suppress_int++; \
Denys Vlasenkode892052016-10-02 01:49:13 +0200450 barrier(); \
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000451} while (0)
Denys Vlasenko06b11492016-11-04 16:43:18 +0100452#else
453# define INT_OFF do { \
454 suppress_int++; \
455 barrier(); \
456} while (0)
457#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +0000458
459/*
460 * Called to raise an exception. Since C doesn't include exceptions, we
461 * just do a longjmp to the exception handler. The type of exception is
Denis Vlasenko4b875702009-03-19 13:30:04 +0000462 * stored in the global variable "exception_type".
Denis Vlasenkob012b102007-02-19 22:43:01 +0000463 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000464static void raise_exception(int) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +0000465static void
466raise_exception(int e)
467{
468#if DEBUG
Denis Vlasenko2da584f2007-02-19 22:44:05 +0000469 if (exception_handler == NULL)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000470 abort();
471#endif
472 INT_OFF;
Denis Vlasenko7f88e342009-03-19 03:36:18 +0000473 exception_type = e;
Denis Vlasenko2da584f2007-02-19 22:44:05 +0000474 longjmp(exception_handler->loc, 1);
Denis Vlasenkob012b102007-02-19 22:43:01 +0000475}
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000476#if DEBUG
477#define raise_exception(e) do { \
478 TRACE(("raising exception %d on line %d\n", (e), __LINE__)); \
479 raise_exception(e); \
480} while (0)
481#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +0000482
483/*
Denys Vlasenkof37e1152016-10-07 03:17:28 +0200484 * Called when a SIGINT is received. (If the user specifies
Denis Vlasenkob012b102007-02-19 22:43:01 +0000485 * that SIGINT is to be trapped or ignored using the trap builtin, then
486 * this routine is not called.) Suppressint is nonzero when interrupts
487 * are held using the INT_OFF macro. (The test for iflag is just
488 * defensive programming.)
489 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000490static void raise_interrupt(void) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +0000491static void
492raise_interrupt(void)
493{
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200494 pending_int = 0;
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +0000495 /* Signal is not automatically unmasked after it is raised,
496 * do it ourself - unmask all signals */
Denis Vlasenko3f165fa2008-03-17 08:29:08 +0000497 sigprocmask_allsigs(SIG_UNBLOCK);
Denys Vlasenko238bf182010-05-18 15:49:07 +0200498 /* pending_sig = 0; - now done in signal_handler() */
Denis Vlasenko7c139b42007-03-21 20:17:27 +0000499
Denys Vlasenkoc0663c72016-10-27 21:09:01 +0200500 if (!(rootshell && iflag)) {
501 /* Kill ourself with SIGINT */
502 signal(SIGINT, SIG_DFL);
503 raise(SIGINT);
Denis Vlasenkob012b102007-02-19 22:43:01 +0000504 }
Denys Vlasenko4d12e942016-10-01 16:03:11 +0200505 /* bash: ^C even on empty command line sets $? */
506 exitstatus = SIGINT + 128;
Denys Vlasenkoc0663c72016-10-27 21:09:01 +0200507 raise_exception(EXINT);
Denis Vlasenkob012b102007-02-19 22:43:01 +0000508 /* NOTREACHED */
509}
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000510#if DEBUG
511#define raise_interrupt() do { \
512 TRACE(("raising interrupt on line %d\n", __LINE__)); \
513 raise_interrupt(); \
514} while (0)
515#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +0000516
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000517static IF_ASH_OPTIMIZE_FOR_SIZE(inline) void
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000518int_on(void)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000519{
Denys Vlasenkode892052016-10-02 01:49:13 +0200520 barrier();
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200521 if (--suppress_int == 0 && pending_int) {
Denis Vlasenkob012b102007-02-19 22:43:01 +0000522 raise_interrupt();
523 }
524}
Denys Vlasenko06b11492016-11-04 16:43:18 +0100525#if DEBUG_INTONOFF
526# define INT_ON do { \
527 TRACE(("%s:%d INT_ON(%d)\n", __func__, __LINE__, suppress_int-1)); \
528 int_on(); \
529} while (0)
530#else
531# define INT_ON int_on()
532#endif
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000533static IF_ASH_OPTIMIZE_FOR_SIZE(inline) void
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000534force_int_on(void)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000535{
Denys Vlasenkode892052016-10-02 01:49:13 +0200536 barrier();
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200537 suppress_int = 0;
538 if (pending_int)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000539 raise_interrupt();
540}
541#define FORCE_INT_ON force_int_on()
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000542
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200543#define SAVE_INT(v) ((v) = suppress_int)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000544
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000545#define RESTORE_INT(v) do { \
Denys Vlasenkode892052016-10-02 01:49:13 +0200546 barrier(); \
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200547 suppress_int = (v); \
548 if (suppress_int == 0 && pending_int) \
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000549 raise_interrupt(); \
550} while (0)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000551
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000552
Denis Vlasenkobc54cff2007-02-23 01:05:52 +0000553/* ============ Stdout/stderr output */
Eric Andersenc470f442003-07-28 09:56:35 +0000554
Eric Andersenc470f442003-07-28 09:56:35 +0000555static void
Denis Vlasenkob012b102007-02-19 22:43:01 +0000556outstr(const char *p, FILE *file)
Denis Vlasenkoe5570da2007-02-19 22:41:55 +0000557{
Denis Vlasenkob012b102007-02-19 22:43:01 +0000558 INT_OFF;
559 fputs(p, file);
560 INT_ON;
561}
562
563static void
564flush_stdout_stderr(void)
565{
566 INT_OFF;
Denys Vlasenko8131eea2009-11-02 14:19:51 +0100567 fflush_all();
Denis Vlasenkob012b102007-02-19 22:43:01 +0000568 INT_ON;
569}
570
Denys Vlasenko9c541002015-10-07 15:44:36 +0200571/* Was called outcslow(c,FILE*), but c was always '\n' */
Denis Vlasenkob012b102007-02-19 22:43:01 +0000572static void
Denys Vlasenko9c541002015-10-07 15:44:36 +0200573newline_and_flush(FILE *dest)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000574{
575 INT_OFF;
Denys Vlasenko9c541002015-10-07 15:44:36 +0200576 putc('\n', dest);
Denis Vlasenkob012b102007-02-19 22:43:01 +0000577 fflush(dest);
578 INT_ON;
579}
580
581static int out1fmt(const char *, ...) __attribute__((__format__(__printf__,1,2)));
582static int
583out1fmt(const char *fmt, ...)
584{
585 va_list ap;
586 int r;
587
588 INT_OFF;
589 va_start(ap, fmt);
590 r = vprintf(fmt, ap);
591 va_end(ap);
592 INT_ON;
593 return r;
594}
595
596static int fmtstr(char *, size_t, const char *, ...) __attribute__((__format__(__printf__,3,4)));
597static int
598fmtstr(char *outbuf, size_t length, const char *fmt, ...)
599{
600 va_list ap;
601 int ret;
602
603 va_start(ap, fmt);
604 INT_OFF;
605 ret = vsnprintf(outbuf, length, fmt, ap);
606 va_end(ap);
607 INT_ON;
608 return ret;
609}
610
611static void
612out1str(const char *p)
613{
614 outstr(p, stdout);
615}
616
617static void
618out2str(const char *p)
619{
620 outstr(p, stderr);
Denys Vlasenko8131eea2009-11-02 14:19:51 +0100621 flush_stdout_stderr();
Denis Vlasenkob012b102007-02-19 22:43:01 +0000622}
623
624
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +0000625/* ============ Parser structures */
Denis Vlasenko4d2183b2007-02-23 01:05:38 +0000626
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000627/* control characters in argument strings */
Denys Vlasenko2ce42e92009-11-29 02:18:13 +0100628#define CTL_FIRST CTLESC
Denys Vlasenkob6c84342009-08-29 20:23:20 +0200629#define CTLESC ((unsigned char)'\201') /* escape next character */
630#define CTLVAR ((unsigned char)'\202') /* variable defn */
631#define CTLENDVAR ((unsigned char)'\203')
632#define CTLBACKQ ((unsigned char)'\204')
Denys Vlasenkob6c84342009-08-29 20:23:20 +0200633#define CTLARI ((unsigned char)'\206') /* arithmetic expression */
634#define CTLENDARI ((unsigned char)'\207')
635#define CTLQUOTEMARK ((unsigned char)'\210')
Denys Vlasenko2ce42e92009-11-29 02:18:13 +0100636#define CTL_LAST CTLQUOTEMARK
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000637
638/* variable substitution byte (follows CTLVAR) */
639#define VSTYPE 0x0f /* type of variable substitution */
640#define VSNUL 0x10 /* colon--treat the empty string as unset */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000641
642/* values of VSTYPE field */
Denis Vlasenko92e13c22008-03-25 01:17:40 +0000643#define VSNORMAL 0x1 /* normal variable: $var or ${var} */
644#define VSMINUS 0x2 /* ${var-text} */
645#define VSPLUS 0x3 /* ${var+text} */
646#define VSQUESTION 0x4 /* ${var?message} */
647#define VSASSIGN 0x5 /* ${var=text} */
648#define VSTRIMRIGHT 0x6 /* ${var%pattern} */
649#define VSTRIMRIGHTMAX 0x7 /* ${var%%pattern} */
650#define VSTRIMLEFT 0x8 /* ${var#pattern} */
651#define VSTRIMLEFTMAX 0x9 /* ${var##pattern} */
652#define VSLENGTH 0xa /* ${#var} */
653#if ENABLE_ASH_BASH_COMPAT
654#define VSSUBSTR 0xc /* ${var:position:length} */
655#define VSREPLACE 0xd /* ${var/pattern/replacement} */
656#define VSREPLACEALL 0xe /* ${var//pattern/replacement} */
657#endif
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000658
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000659static const char dolatstr[] ALIGN1 = {
Ron Yorston549deab2015-05-18 09:57:51 +0200660 CTLQUOTEMARK, CTLVAR, VSNORMAL, '@', '=', CTLQUOTEMARK, '\0'
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000661};
Ron Yorston549deab2015-05-18 09:57:51 +0200662#define DOLATSTRLEN 6
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +0000663
Denis Vlasenko559691a2008-10-05 18:39:31 +0000664#define NCMD 0
665#define NPIPE 1
666#define NREDIR 2
667#define NBACKGND 3
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000668#define NSUBSHELL 4
Denis Vlasenko559691a2008-10-05 18:39:31 +0000669#define NAND 5
670#define NOR 6
671#define NSEMI 7
672#define NIF 8
673#define NWHILE 9
674#define NUNTIL 10
675#define NFOR 11
676#define NCASE 12
677#define NCLIST 13
678#define NDEFUN 14
679#define NARG 15
680#define NTO 16
681#if ENABLE_ASH_BASH_COMPAT
682#define NTO2 17
683#endif
684#define NCLOBBER 18
685#define NFROM 19
686#define NFROMTO 20
687#define NAPPEND 21
688#define NTOFD 22
689#define NFROMFD 23
690#define NHERE 24
691#define NXHERE 25
692#define NNOT 26
Denis Vlasenko340299a2008-11-21 10:36:36 +0000693#define N_NUMBER 27
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000694
695union node;
696
697struct ncmd {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000698 smallint type; /* Nxxxx */
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000699 union node *assign;
700 union node *args;
701 union node *redirect;
702};
703
704struct npipe {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000705 smallint type;
706 smallint pipe_backgnd;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000707 struct nodelist *cmdlist;
708};
709
710struct nredir {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000711 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000712 union node *n;
713 union node *redirect;
714};
715
716struct nbinary {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000717 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000718 union node *ch1;
719 union node *ch2;
720};
721
722struct nif {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000723 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000724 union node *test;
725 union node *ifpart;
726 union node *elsepart;
727};
728
729struct nfor {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000730 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000731 union node *args;
732 union node *body;
733 char *var;
734};
735
736struct ncase {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000737 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000738 union node *expr;
739 union node *cases;
740};
741
742struct nclist {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000743 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000744 union node *next;
745 union node *pattern;
746 union node *body;
747};
748
749struct narg {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000750 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000751 union node *next;
752 char *text;
753 struct nodelist *backquote;
754};
755
Denis Vlasenko559691a2008-10-05 18:39:31 +0000756/* nfile and ndup layout must match!
757 * NTOFD (>&fdnum) uses ndup structure, but we may discover mid-flight
758 * that it is actually NTO2 (>&file), and change its type.
759 */
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000760struct nfile {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000761 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000762 union node *next;
763 int fd;
Denis Vlasenko559691a2008-10-05 18:39:31 +0000764 int _unused_dupfd;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000765 union node *fname;
766 char *expfname;
767};
768
769struct ndup {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000770 smallint type;
Denis Vlasenko559691a2008-10-05 18:39:31 +0000771 union node *next;
772 int fd;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000773 int dupfd;
774 union node *vname;
Denis Vlasenko559691a2008-10-05 18:39:31 +0000775 char *_unused_expfname;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000776};
777
778struct nhere {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000779 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000780 union node *next;
781 int fd;
782 union node *doc;
783};
784
785struct nnot {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000786 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000787 union node *com;
788};
789
790union node {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000791 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000792 struct ncmd ncmd;
793 struct npipe npipe;
794 struct nredir nredir;
795 struct nbinary nbinary;
796 struct nif nif;
797 struct nfor nfor;
798 struct ncase ncase;
799 struct nclist nclist;
800 struct narg narg;
801 struct nfile nfile;
802 struct ndup ndup;
803 struct nhere nhere;
804 struct nnot nnot;
805};
806
Denys Vlasenko86e83ec2009-07-23 22:07:07 +0200807/*
808 * NODE_EOF is returned by parsecmd when it encounters an end of file.
809 * It must be distinct from NULL.
810 */
811#define NODE_EOF ((union node *) -1L)
812
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000813struct nodelist {
814 struct nodelist *next;
815 union node *n;
816};
817
818struct funcnode {
819 int count;
820 union node n;
821};
822
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000823/*
824 * Free a parse tree.
825 */
826static void
827freefunc(struct funcnode *f)
828{
829 if (f && --f->count < 0)
830 free(f);
831}
832
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000833
834/* ============ Debugging output */
835
836#if DEBUG
837
838static FILE *tracefile;
839
840static void
841trace_printf(const char *fmt, ...)
842{
843 va_list va;
844
845 if (debug != 1)
846 return;
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000847 if (DEBUG_TIME)
848 fprintf(tracefile, "%u ", (int) time(NULL));
849 if (DEBUG_PID)
850 fprintf(tracefile, "[%u] ", (int) getpid());
851 if (DEBUG_SIG)
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200852 fprintf(tracefile, "pending s:%d i:%d(supp:%d) ", pending_sig, pending_int, suppress_int);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000853 va_start(va, fmt);
854 vfprintf(tracefile, fmt, va);
855 va_end(va);
856}
857
858static void
859trace_vprintf(const char *fmt, va_list va)
860{
861 if (debug != 1)
862 return;
863 vfprintf(tracefile, fmt, va);
Denys Vlasenko474ed062016-10-30 18:30:29 +0100864 fprintf(tracefile, "\n");
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000865}
866
867static void
868trace_puts(const char *s)
869{
870 if (debug != 1)
871 return;
872 fputs(s, tracefile);
873}
874
875static void
876trace_puts_quoted(char *s)
877{
878 char *p;
879 char c;
880
881 if (debug != 1)
882 return;
883 putc('"', tracefile);
884 for (p = s; *p; p++) {
Denys Vlasenkocd716832009-11-28 22:14:02 +0100885 switch ((unsigned char)*p) {
886 case '\n': c = 'n'; goto backslash;
887 case '\t': c = 't'; goto backslash;
888 case '\r': c = 'r'; goto backslash;
889 case '\"': c = '\"'; goto backslash;
890 case '\\': c = '\\'; goto backslash;
891 case CTLESC: c = 'e'; goto backslash;
892 case CTLVAR: c = 'v'; goto backslash;
Denys Vlasenkocd716832009-11-28 22:14:02 +0100893 case CTLBACKQ: c = 'q'; goto backslash;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000894 backslash:
895 putc('\\', tracefile);
896 putc(c, tracefile);
897 break;
898 default:
899 if (*p >= ' ' && *p <= '~')
900 putc(*p, tracefile);
901 else {
902 putc('\\', tracefile);
Denys Vlasenkocd716832009-11-28 22:14:02 +0100903 putc((*p >> 6) & 03, tracefile);
904 putc((*p >> 3) & 07, tracefile);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000905 putc(*p & 07, tracefile);
906 }
907 break;
908 }
909 }
910 putc('"', tracefile);
911}
912
913static void
914trace_puts_args(char **ap)
915{
916 if (debug != 1)
917 return;
918 if (!*ap)
919 return;
920 while (1) {
921 trace_puts_quoted(*ap);
922 if (!*++ap) {
923 putc('\n', tracefile);
924 break;
925 }
926 putc(' ', tracefile);
927 }
928}
929
930static void
931opentrace(void)
932{
933 char s[100];
934#ifdef O_APPEND
935 int flags;
936#endif
937
938 if (debug != 1) {
939 if (tracefile)
940 fflush(tracefile);
941 /* leave open because libedit might be using it */
942 return;
943 }
944 strcpy(s, "./trace");
945 if (tracefile) {
946 if (!freopen(s, "a", tracefile)) {
947 fprintf(stderr, "Can't re-open %s\n", s);
948 debug = 0;
949 return;
950 }
951 } else {
952 tracefile = fopen(s, "a");
953 if (tracefile == NULL) {
954 fprintf(stderr, "Can't open %s\n", s);
955 debug = 0;
956 return;
957 }
958 }
959#ifdef O_APPEND
Denis Vlasenkod37f2222007-08-19 13:42:08 +0000960 flags = fcntl(fileno(tracefile), F_GETFL);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000961 if (flags >= 0)
962 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
963#endif
964 setlinebuf(tracefile);
965 fputs("\nTracing started.\n", tracefile);
966}
967
968static void
969indent(int amount, char *pfx, FILE *fp)
970{
971 int i;
972
973 for (i = 0; i < amount; i++) {
974 if (pfx && i == amount - 1)
975 fputs(pfx, fp);
976 putc('\t', fp);
977 }
978}
979
980/* little circular references here... */
981static void shtree(union node *n, int ind, char *pfx, FILE *fp);
982
983static void
984sharg(union node *arg, FILE *fp)
985{
986 char *p;
987 struct nodelist *bqlist;
Denys Vlasenkocd716832009-11-28 22:14:02 +0100988 unsigned char subtype;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000989
990 if (arg->type != NARG) {
991 out1fmt("<node type %d>\n", arg->type);
992 abort();
993 }
994 bqlist = arg->narg.backquote;
995 for (p = arg->narg.text; *p; p++) {
Denys Vlasenkocd716832009-11-28 22:14:02 +0100996 switch ((unsigned char)*p) {
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000997 case CTLESC:
Dan Fandrich77d48722010-09-07 23:38:28 -0700998 p++;
999 putc(*p, fp);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001000 break;
1001 case CTLVAR:
1002 putc('$', fp);
1003 putc('{', fp);
1004 subtype = *++p;
1005 if (subtype == VSLENGTH)
1006 putc('#', fp);
1007
Dan Fandrich77d48722010-09-07 23:38:28 -07001008 while (*p != '=') {
1009 putc(*p, fp);
1010 p++;
1011 }
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001012
1013 if (subtype & VSNUL)
1014 putc(':', fp);
1015
1016 switch (subtype & VSTYPE) {
1017 case VSNORMAL:
1018 putc('}', fp);
1019 break;
1020 case VSMINUS:
1021 putc('-', fp);
1022 break;
1023 case VSPLUS:
1024 putc('+', fp);
1025 break;
1026 case VSQUESTION:
1027 putc('?', fp);
1028 break;
1029 case VSASSIGN:
1030 putc('=', fp);
1031 break;
1032 case VSTRIMLEFT:
1033 putc('#', fp);
1034 break;
1035 case VSTRIMLEFTMAX:
1036 putc('#', fp);
1037 putc('#', fp);
1038 break;
1039 case VSTRIMRIGHT:
1040 putc('%', fp);
1041 break;
1042 case VSTRIMRIGHTMAX:
1043 putc('%', fp);
1044 putc('%', fp);
1045 break;
1046 case VSLENGTH:
1047 break;
1048 default:
1049 out1fmt("<subtype %d>", subtype);
1050 }
1051 break;
1052 case CTLENDVAR:
1053 putc('}', fp);
1054 break;
1055 case CTLBACKQ:
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001056 putc('$', fp);
1057 putc('(', fp);
1058 shtree(bqlist->n, -1, NULL, fp);
1059 putc(')', fp);
1060 break;
1061 default:
1062 putc(*p, fp);
1063 break;
1064 }
1065 }
1066}
1067
Denys Vlasenko641dd7b2009-06-11 19:30:19 +02001068static void
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001069shcmd(union node *cmd, FILE *fp)
1070{
1071 union node *np;
1072 int first;
1073 const char *s;
1074 int dftfd;
1075
1076 first = 1;
1077 for (np = cmd->ncmd.args; np; np = np->narg.next) {
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001078 if (!first)
1079 putc(' ', fp);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001080 sharg(np, fp);
1081 first = 0;
1082 }
1083 for (np = cmd->ncmd.redirect; np; np = np->nfile.next) {
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001084 if (!first)
1085 putc(' ', fp);
1086 dftfd = 0;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001087 switch (np->nfile.type) {
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001088 case NTO: s = ">>"+1; dftfd = 1; break;
1089 case NCLOBBER: s = ">|"; dftfd = 1; break;
1090 case NAPPEND: s = ">>"; dftfd = 1; break;
Denis Vlasenko559691a2008-10-05 18:39:31 +00001091#if ENABLE_ASH_BASH_COMPAT
1092 case NTO2:
1093#endif
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001094 case NTOFD: s = ">&"; dftfd = 1; break;
Denis Vlasenko559691a2008-10-05 18:39:31 +00001095 case NFROM: s = "<"; break;
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001096 case NFROMFD: s = "<&"; break;
1097 case NFROMTO: s = "<>"; break;
1098 default: s = "*error*"; break;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001099 }
1100 if (np->nfile.fd != dftfd)
1101 fprintf(fp, "%d", np->nfile.fd);
1102 fputs(s, fp);
1103 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
1104 fprintf(fp, "%d", np->ndup.dupfd);
1105 } else {
1106 sharg(np->nfile.fname, fp);
1107 }
1108 first = 0;
1109 }
1110}
1111
1112static void
1113shtree(union node *n, int ind, char *pfx, FILE *fp)
1114{
1115 struct nodelist *lp;
1116 const char *s;
1117
1118 if (n == NULL)
1119 return;
1120
1121 indent(ind, pfx, fp);
Denys Vlasenko86e83ec2009-07-23 22:07:07 +02001122
1123 if (n == NODE_EOF) {
1124 fputs("<EOF>", fp);
1125 return;
1126 }
1127
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001128 switch (n->type) {
1129 case NSEMI:
1130 s = "; ";
1131 goto binop;
1132 case NAND:
1133 s = " && ";
1134 goto binop;
1135 case NOR:
1136 s = " || ";
1137 binop:
1138 shtree(n->nbinary.ch1, ind, NULL, fp);
1139 /* if (ind < 0) */
1140 fputs(s, fp);
1141 shtree(n->nbinary.ch2, ind, NULL, fp);
1142 break;
1143 case NCMD:
1144 shcmd(n, fp);
1145 if (ind >= 0)
1146 putc('\n', fp);
1147 break;
1148 case NPIPE:
1149 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
Denys Vlasenko7cee00e2009-07-24 01:08:03 +02001150 shtree(lp->n, 0, NULL, fp);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001151 if (lp->next)
1152 fputs(" | ", fp);
1153 }
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00001154 if (n->npipe.pipe_backgnd)
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001155 fputs(" &", fp);
1156 if (ind >= 0)
1157 putc('\n', fp);
1158 break;
1159 default:
1160 fprintf(fp, "<node type %d>", n->type);
1161 if (ind >= 0)
1162 putc('\n', fp);
1163 break;
1164 }
1165}
1166
1167static void
1168showtree(union node *n)
1169{
1170 trace_puts("showtree called\n");
Denys Vlasenko883cea42009-07-11 15:31:59 +02001171 shtree(n, 1, NULL, stderr);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001172}
1173
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001174#endif /* DEBUG */
1175
1176
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00001177/* ============ Parser data */
1178
1179/*
Denis Vlasenkob012b102007-02-19 22:43:01 +00001180 * ash_vmsg() needs parsefile->fd, hence parsefile definition is moved up.
1181 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001182struct strlist {
1183 struct strlist *next;
1184 char *text;
1185};
1186
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001187struct alias;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001188
Denis Vlasenkob012b102007-02-19 22:43:01 +00001189struct strpush {
1190 struct strpush *prev; /* preceding string on stack */
Denis Vlasenko41eb3002008-11-28 03:42:31 +00001191 char *prev_string;
1192 int prev_left_in_line;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001193#if ENABLE_ASH_ALIAS
1194 struct alias *ap; /* if push was associated with an alias */
1195#endif
1196 char *string; /* remember the string since it may change */
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02001197
1198 /* Remember last two characters for pungetc. */
1199 int lastc[2];
1200
1201 /* Number of outstanding calls to pungetc. */
1202 int unget;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001203};
1204
1205struct parsefile {
1206 struct parsefile *prev; /* preceding file on stack */
1207 int linno; /* current line */
Denys Vlasenko79b3d422010-06-03 04:29:08 +02001208 int pf_fd; /* file descriptor (or -1 if string) */
Denis Vlasenko41eb3002008-11-28 03:42:31 +00001209 int left_in_line; /* number of chars left in this line */
1210 int left_in_buffer; /* number of chars left in this buffer past the line */
1211 char *next_to_pgetc; /* next char in buffer */
Denis Vlasenkob012b102007-02-19 22:43:01 +00001212 char *buf; /* input buffer */
1213 struct strpush *strpush; /* for pushing strings at this level */
1214 struct strpush basestrpush; /* so pushing one is fast */
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
Denis Vlasenko448d30e2008-06-27 00:24:11 +00001223static struct parsefile basepf; /* top level input file */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00001224static struct parsefile *g_parsefile = &basepf; /* current input file */
Denis Vlasenkob012b102007-02-19 22:43:01 +00001225static int startlinno; /* line # where last token started */
1226static char *commandname; /* currently executing command */
1227static struct strlist *cmdenviron; /* environment for builtin command */
Denis Vlasenkob012b102007-02-19 22:43:01 +00001228
1229
1230/* ============ Message printing */
1231
1232static void
1233ash_vmsg(const char *msg, va_list ap)
1234{
1235 fprintf(stderr, "%s: ", arg0);
1236 if (commandname) {
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00001237 if (strcmp(arg0, commandname))
1238 fprintf(stderr, "%s: ", commandname);
Denys Vlasenko79b3d422010-06-03 04:29:08 +02001239 if (!iflag || g_parsefile->pf_fd > 0)
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00001240 fprintf(stderr, "line %d: ", startlinno);
Eric Andersenc470f442003-07-28 09:56:35 +00001241 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00001242 vfprintf(stderr, msg, ap);
Denys Vlasenko9c541002015-10-07 15:44:36 +02001243 newline_and_flush(stderr);
Eric Andersenc470f442003-07-28 09:56:35 +00001244}
Denis Vlasenkob012b102007-02-19 22:43:01 +00001245
1246/*
1247 * Exverror is called to raise the error exception. If the second argument
1248 * is not NULL then error prints an error message using printf style
1249 * formatting. It then raises the error exception.
1250 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00001251static void ash_vmsg_and_raise(int, const char *, va_list) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001252static void
1253ash_vmsg_and_raise(int cond, const char *msg, va_list ap)
Eric Andersenc470f442003-07-28 09:56:35 +00001254{
Denis Vlasenkob012b102007-02-19 22:43:01 +00001255#if DEBUG
1256 if (msg) {
Denys Vlasenko474ed062016-10-30 18:30:29 +01001257 TRACE(("ash_vmsg_and_raise(%d):", cond));
Denis Vlasenkob012b102007-02-19 22:43:01 +00001258 TRACEV((msg, ap));
Denis Vlasenkob012b102007-02-19 22:43:01 +00001259 } else
Denys Vlasenko474ed062016-10-30 18:30:29 +01001260 TRACE(("ash_vmsg_and_raise(%d):NULL\n", cond));
Denis Vlasenkob012b102007-02-19 22:43:01 +00001261 if (msg)
1262#endif
1263 ash_vmsg(msg, ap);
1264
1265 flush_stdout_stderr();
1266 raise_exception(cond);
1267 /* NOTREACHED */
Eric Andersenc470f442003-07-28 09:56:35 +00001268}
Denis Vlasenkob012b102007-02-19 22:43:01 +00001269
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00001270static void ash_msg_and_raise_error(const char *, ...) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001271static void
1272ash_msg_and_raise_error(const char *msg, ...)
1273{
1274 va_list ap;
1275
1276 va_start(ap, msg);
1277 ash_vmsg_and_raise(EXERROR, msg, ap);
1278 /* NOTREACHED */
1279 va_end(ap);
1280}
1281
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00001282static void raise_error_syntax(const char *) NORETURN;
1283static void
1284raise_error_syntax(const char *msg)
1285{
1286 ash_msg_and_raise_error("syntax error: %s", msg);
1287 /* NOTREACHED */
1288}
1289
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00001290static void ash_msg_and_raise(int, const char *, ...) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001291static void
1292ash_msg_and_raise(int cond, const char *msg, ...)
1293{
1294 va_list ap;
1295
1296 va_start(ap, msg);
1297 ash_vmsg_and_raise(cond, msg, ap);
1298 /* NOTREACHED */
1299 va_end(ap);
1300}
1301
1302/*
1303 * error/warning routines for external builtins
1304 */
1305static void
1306ash_msg(const char *fmt, ...)
1307{
1308 va_list ap;
1309
1310 va_start(ap, fmt);
1311 ash_vmsg(fmt, ap);
1312 va_end(ap);
1313}
1314
1315/*
1316 * Return a string describing an error. The returned string may be a
1317 * pointer to a static buffer that will be overwritten on the next call.
1318 * Action describes the operation that got the error.
1319 */
1320static const char *
1321errmsg(int e, const char *em)
1322{
1323 if (e == ENOENT || e == ENOTDIR) {
1324 return em;
1325 }
1326 return strerror(e);
1327}
1328
1329
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001330/* ============ Memory allocation */
1331
Denys Vlasenkoe7670ff2009-10-11 00:45:25 +02001332#if 0
1333/* I consider these wrappers nearly useless:
1334 * ok, they return you to nearest exception handler, but
1335 * how much memory do you leak in the process, making
1336 * memory starvation worse?
1337 */
1338static void *
1339ckrealloc(void * p, size_t nbytes)
1340{
1341 p = realloc(p, nbytes);
1342 if (!p)
1343 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1344 return p;
1345}
1346
1347static void *
1348ckmalloc(size_t nbytes)
1349{
1350 return ckrealloc(NULL, nbytes);
1351}
1352
1353static void *
1354ckzalloc(size_t nbytes)
1355{
1356 return memset(ckmalloc(nbytes), 0, nbytes);
1357}
1358
1359static char *
1360ckstrdup(const char *s)
1361{
1362 char *p = strdup(s);
1363 if (!p)
1364 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1365 return p;
1366}
1367#else
1368/* Using bbox equivalents. They exit if out of memory */
1369# define ckrealloc xrealloc
1370# define ckmalloc xmalloc
1371# define ckzalloc xzalloc
1372# define ckstrdup xstrdup
1373#endif
1374
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001375/*
1376 * It appears that grabstackstr() will barf with such alignments
1377 * because stalloc() will return a string allocated in a new stackblock.
1378 */
1379#define SHELL_ALIGN(nbytes) (((nbytes) + SHELL_SIZE) & ~SHELL_SIZE)
1380enum {
1381 /* Most machines require the value returned from malloc to be aligned
1382 * in some way. The following macro will get this right
1383 * on many machines. */
Denys Vlasenko0e5e4ea2009-10-11 00:36:20 +02001384 SHELL_SIZE = sizeof(union { int i; char *cp; double d; }) - 1,
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001385 /* Minimum size of a block */
Denis Vlasenko01631112007-12-16 17:20:38 +00001386 MINSIZE = SHELL_ALIGN(504),
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001387};
1388
1389struct stack_block {
1390 struct stack_block *prev;
1391 char space[MINSIZE];
1392};
1393
1394struct stackmark {
1395 struct stack_block *stackp;
1396 char *stacknxt;
1397 size_t stacknleft;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001398};
1399
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001400
Denis Vlasenko01631112007-12-16 17:20:38 +00001401struct globals_memstack {
1402 struct stack_block *g_stackp; // = &stackbase;
Denis Vlasenko01631112007-12-16 17:20:38 +00001403 char *g_stacknxt; // = stackbase.space;
1404 char *sstrend; // = stackbase.space + MINSIZE;
1405 size_t g_stacknleft; // = MINSIZE;
Denis Vlasenko01631112007-12-16 17:20:38 +00001406 struct stack_block stackbase;
1407};
Denis Vlasenko574f2f42008-02-27 18:41:59 +00001408extern struct globals_memstack *const ash_ptr_to_globals_memstack;
1409#define G_memstack (*ash_ptr_to_globals_memstack)
Denis Vlasenko01631112007-12-16 17:20:38 +00001410#define g_stackp (G_memstack.g_stackp )
Denis Vlasenko01631112007-12-16 17:20:38 +00001411#define g_stacknxt (G_memstack.g_stacknxt )
1412#define sstrend (G_memstack.sstrend )
1413#define g_stacknleft (G_memstack.g_stacknleft)
Denis Vlasenko01631112007-12-16 17:20:38 +00001414#define stackbase (G_memstack.stackbase )
1415#define INIT_G_memstack() do { \
Denis Vlasenko574f2f42008-02-27 18:41:59 +00001416 (*(struct globals_memstack**)&ash_ptr_to_globals_memstack) = xzalloc(sizeof(G_memstack)); \
1417 barrier(); \
Denis Vlasenko01631112007-12-16 17:20:38 +00001418 g_stackp = &stackbase; \
1419 g_stacknxt = stackbase.space; \
1420 g_stacknleft = MINSIZE; \
1421 sstrend = stackbase.space + MINSIZE; \
Denis Vlasenko01631112007-12-16 17:20:38 +00001422} while (0)
1423
Denys Vlasenkoe7670ff2009-10-11 00:45:25 +02001424
Denis Vlasenko01631112007-12-16 17:20:38 +00001425#define stackblock() ((void *)g_stacknxt)
1426#define stackblocksize() g_stacknleft
1427
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001428/*
1429 * Parse trees for commands are allocated in lifo order, so we use a stack
1430 * to make this more efficient, and also to avoid all sorts of exception
1431 * handling code to handle interrupts in the middle of a parse.
1432 *
1433 * The size 504 was chosen because the Ultrix malloc handles that size
1434 * well.
1435 */
1436static void *
1437stalloc(size_t nbytes)
1438{
1439 char *p;
1440 size_t aligned;
1441
1442 aligned = SHELL_ALIGN(nbytes);
Denis Vlasenko01631112007-12-16 17:20:38 +00001443 if (aligned > g_stacknleft) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001444 size_t len;
1445 size_t blocksize;
1446 struct stack_block *sp;
1447
1448 blocksize = aligned;
1449 if (blocksize < MINSIZE)
1450 blocksize = MINSIZE;
1451 len = sizeof(struct stack_block) - MINSIZE + blocksize;
1452 if (len < blocksize)
1453 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1454 INT_OFF;
1455 sp = ckmalloc(len);
Denis Vlasenko01631112007-12-16 17:20:38 +00001456 sp->prev = g_stackp;
1457 g_stacknxt = sp->space;
1458 g_stacknleft = blocksize;
1459 sstrend = g_stacknxt + blocksize;
1460 g_stackp = sp;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001461 INT_ON;
1462 }
Denis Vlasenko01631112007-12-16 17:20:38 +00001463 p = g_stacknxt;
1464 g_stacknxt += aligned;
1465 g_stacknleft -= aligned;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001466 return p;
1467}
1468
Denis Vlasenko597906c2008-02-20 16:38:54 +00001469static void *
1470stzalloc(size_t nbytes)
1471{
1472 return memset(stalloc(nbytes), 0, nbytes);
1473}
1474
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001475static void
1476stunalloc(void *p)
1477{
1478#if DEBUG
Denis Vlasenko01631112007-12-16 17:20:38 +00001479 if (!p || (g_stacknxt < (char *)p) || ((char *)p < g_stackp->space)) {
Bernhard Reutner-Fischer5e25ddb2008-05-19 09:48:17 +00001480 write(STDERR_FILENO, "stunalloc\n", 10);
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001481 abort();
1482 }
1483#endif
Denis Vlasenko01631112007-12-16 17:20:38 +00001484 g_stacknleft += g_stacknxt - (char *)p;
1485 g_stacknxt = p;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001486}
1487
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001488/*
1489 * Like strdup but works with the ash stack.
1490 */
1491static char *
Denys Vlasenko8e2bc472016-09-28 23:02:57 +02001492sstrdup(const char *p)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001493{
1494 size_t len = strlen(p) + 1;
1495 return memcpy(stalloc(len), p, len);
1496}
1497
Denys Vlasenkoa318bba2016-10-26 18:26:27 +02001498static inline void
Denys Vlasenko60ca8342016-09-30 11:21:21 +02001499grabstackblock(size_t len)
1500{
Denys Vlasenkoa318bba2016-10-26 18:26:27 +02001501 stalloc(len);
Denys Vlasenko60ca8342016-09-30 11:21:21 +02001502}
1503
1504static void
1505pushstackmark(struct stackmark *mark, size_t len)
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001506{
Denis Vlasenko01631112007-12-16 17:20:38 +00001507 mark->stackp = g_stackp;
1508 mark->stacknxt = g_stacknxt;
1509 mark->stacknleft = g_stacknleft;
Denys Vlasenko60ca8342016-09-30 11:21:21 +02001510 grabstackblock(len);
1511}
1512
1513static void
1514setstackmark(struct stackmark *mark)
1515{
1516 pushstackmark(mark, g_stacknxt == g_stackp->space && g_stackp != &stackbase);
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001517}
1518
1519static void
1520popstackmark(struct stackmark *mark)
1521{
1522 struct stack_block *sp;
1523
Denis Vlasenko93ebd4f2007-03-13 20:55:36 +00001524 if (!mark->stackp)
1525 return;
1526
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001527 INT_OFF;
Denis Vlasenko01631112007-12-16 17:20:38 +00001528 while (g_stackp != mark->stackp) {
1529 sp = g_stackp;
1530 g_stackp = sp->prev;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001531 free(sp);
1532 }
Denis Vlasenko01631112007-12-16 17:20:38 +00001533 g_stacknxt = mark->stacknxt;
1534 g_stacknleft = mark->stacknleft;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001535 sstrend = mark->stacknxt + mark->stacknleft;
1536 INT_ON;
1537}
1538
1539/*
1540 * When the parser reads in a string, it wants to stick the string on the
1541 * stack and only adjust the stack pointer when it knows how big the
1542 * string is. Stackblock (defined in stack.h) returns a pointer to a block
1543 * of space on top of the stack and stackblocklen returns the length of
1544 * this block. Growstackblock will grow this space by at least one byte,
1545 * possibly moving it (like realloc). Grabstackblock actually allocates the
1546 * part of the block that has been used.
1547 */
1548static void
1549growstackblock(void)
1550{
1551 size_t newlen;
1552
Denis Vlasenko01631112007-12-16 17:20:38 +00001553 newlen = g_stacknleft * 2;
1554 if (newlen < g_stacknleft)
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001555 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1556 if (newlen < 128)
1557 newlen += 128;
1558
Denis Vlasenko01631112007-12-16 17:20:38 +00001559 if (g_stacknxt == g_stackp->space && g_stackp != &stackbase) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001560 struct stack_block *sp;
1561 struct stack_block *prevstackp;
1562 size_t grosslen;
1563
1564 INT_OFF;
Denis Vlasenko01631112007-12-16 17:20:38 +00001565 sp = g_stackp;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001566 prevstackp = sp->prev;
1567 grosslen = newlen + sizeof(struct stack_block) - MINSIZE;
1568 sp = ckrealloc(sp, grosslen);
1569 sp->prev = prevstackp;
Denis Vlasenko01631112007-12-16 17:20:38 +00001570 g_stackp = sp;
1571 g_stacknxt = sp->space;
1572 g_stacknleft = newlen;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001573 sstrend = sp->space + newlen;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001574 INT_ON;
1575 } else {
Denis Vlasenko01631112007-12-16 17:20:38 +00001576 char *oldspace = g_stacknxt;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001577 size_t oldlen = g_stacknleft;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001578 char *p = stalloc(newlen);
1579
1580 /* free the space we just allocated */
Denis Vlasenko01631112007-12-16 17:20:38 +00001581 g_stacknxt = memcpy(p, oldspace, oldlen);
1582 g_stacknleft += newlen;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001583 }
1584}
1585
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001586/*
1587 * The following routines are somewhat easier to use than the above.
1588 * The user declares a variable of type STACKSTR, which may be declared
1589 * to be a register. The macro STARTSTACKSTR initializes things. Then
1590 * the user uses the macro STPUTC to add characters to the string. In
1591 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
1592 * grown as necessary. When the user is done, she can just leave the
1593 * string there and refer to it using stackblock(). Or she can allocate
1594 * the space for it using grabstackstr(). If it is necessary to allow
1595 * someone else to use the stack temporarily and then continue to grow
1596 * the string, the user should use grabstack to allocate the space, and
1597 * then call ungrabstr(p) to return to the previous mode of operation.
1598 *
1599 * USTPUTC is like STPUTC except that it doesn't check for overflow.
1600 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
1601 * is space for at least one character.
1602 */
1603static void *
1604growstackstr(void)
1605{
1606 size_t len = stackblocksize();
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001607 growstackblock();
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001608 return (char *)stackblock() + len;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001609}
1610
1611/*
1612 * Called from CHECKSTRSPACE.
1613 */
1614static char *
1615makestrspace(size_t newlen, char *p)
1616{
Denis Vlasenko01631112007-12-16 17:20:38 +00001617 size_t len = p - g_stacknxt;
Denys Vlasenko53d6e032016-09-30 11:24:12 +02001618 size_t size;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001619
1620 for (;;) {
1621 size_t nleft;
1622
1623 size = stackblocksize();
1624 nleft = size - len;
1625 if (nleft >= newlen)
1626 break;
1627 growstackblock();
1628 }
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001629 return (char *)stackblock() + len;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001630}
1631
1632static char *
1633stack_nputstr(const char *s, size_t n, char *p)
1634{
1635 p = makestrspace(n, p);
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001636 p = (char *)memcpy(p, s, n) + n;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001637 return p;
1638}
1639
1640static char *
1641stack_putstr(const char *s, char *p)
1642{
1643 return stack_nputstr(s, strlen(s), p);
1644}
1645
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001646static char *
1647_STPUTC(int c, char *p)
1648{
1649 if (p == sstrend)
1650 p = growstackstr();
1651 *p++ = c;
1652 return p;
1653}
1654
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00001655#define STARTSTACKSTR(p) ((p) = stackblock())
1656#define STPUTC(c, p) ((p) = _STPUTC((c), (p)))
Denis Vlasenko843cbd52008-06-27 00:23:18 +00001657#define CHECKSTRSPACE(n, p) do { \
1658 char *q = (p); \
1659 size_t l = (n); \
1660 size_t m = sstrend - q; \
1661 if (l > m) \
1662 (p) = makestrspace(l, q); \
1663} while (0)
Denis Vlasenkoef527f52008-06-23 01:52:30 +00001664#define USTPUTC(c, p) (*(p)++ = (c))
Denis Vlasenko843cbd52008-06-27 00:23:18 +00001665#define STACKSTRNUL(p) do { \
1666 if ((p) == sstrend) \
1667 (p) = growstackstr(); \
1668 *(p) = '\0'; \
1669} while (0)
Denis Vlasenkoef527f52008-06-23 01:52:30 +00001670#define STUNPUTC(p) (--(p))
1671#define STTOPC(p) ((p)[-1])
1672#define STADJUST(amount, p) ((p) += (amount))
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001673
1674#define grabstackstr(p) stalloc((char *)(p) - (char *)stackblock())
Denis Vlasenkoef527f52008-06-23 01:52:30 +00001675#define ungrabstackstr(s, p) stunalloc(s)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001676#define stackstrend() ((void *)sstrend)
1677
1678
1679/* ============ String helpers */
1680
1681/*
1682 * prefix -- see if pfx is a prefix of string.
1683 */
1684static char *
1685prefix(const char *string, const char *pfx)
1686{
1687 while (*pfx) {
1688 if (*pfx++ != *string++)
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00001689 return NULL;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001690 }
1691 return (char *) string;
1692}
1693
1694/*
1695 * Check for a valid number. This should be elsewhere.
1696 */
1697static int
1698is_number(const char *p)
1699{
1700 do {
1701 if (!isdigit(*p))
1702 return 0;
1703 } while (*++p != '\0');
1704 return 1;
1705}
1706
1707/*
1708 * Convert a string of digits to an integer, printing an error message on
1709 * failure.
1710 */
1711static int
1712number(const char *s)
1713{
1714 if (!is_number(s))
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02001715 ash_msg_and_raise_error(msg_illnum, s);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001716 return atoi(s);
1717}
1718
1719/*
1720 * Produce a possibly single quoted string suitable as input to the shell.
1721 * The return string is allocated on the stack.
1722 */
1723static char *
1724single_quote(const char *s)
1725{
1726 char *p;
1727
1728 STARTSTACKSTR(p);
1729
1730 do {
1731 char *q;
1732 size_t len;
1733
1734 len = strchrnul(s, '\'') - s;
1735
1736 q = p = makestrspace(len + 3, p);
1737
1738 *q++ = '\'';
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001739 q = (char *)memcpy(q, s, len) + len;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001740 *q++ = '\'';
1741 s += len;
1742
1743 STADJUST(q - p, p);
1744
Denys Vlasenkocd716832009-11-28 22:14:02 +01001745 if (*s != '\'')
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001746 break;
Denys Vlasenkocd716832009-11-28 22:14:02 +01001747 len = 0;
1748 do len++; while (*++s == '\'');
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001749
1750 q = p = makestrspace(len + 3, p);
1751
1752 *q++ = '"';
Denys Vlasenkocd716832009-11-28 22:14:02 +01001753 q = (char *)memcpy(q, s - len, len) + len;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001754 *q++ = '"';
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001755
1756 STADJUST(q - p, p);
1757 } while (*s);
1758
Denys Vlasenkocd716832009-11-28 22:14:02 +01001759 USTPUTC('\0', p);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001760
1761 return stackblock();
1762}
1763
1764
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00001765/* ============ nextopt */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001766
1767static char **argptr; /* argument list for builtin commands */
1768static char *optionarg; /* set by nextopt (like getopt) */
1769static char *optptr; /* used by nextopt */
1770
1771/*
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001772 * XXX - should get rid of. Have all builtins use getopt(3).
1773 * The library getopt must have the BSD extension static variable
1774 * "optreset", otherwise it can't be used within the shell safely.
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001775 *
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001776 * Standard option processing (a la getopt) for builtin routines.
1777 * The only argument that is passed to nextopt is the option string;
1778 * the other arguments are unnecessary. It returns the character,
1779 * or '\0' on end of input.
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001780 */
1781static int
1782nextopt(const char *optstring)
1783{
1784 char *p;
1785 const char *q;
1786 char c;
1787
1788 p = optptr;
1789 if (p == NULL || *p == '\0') {
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001790 /* We ate entire "-param", take next one */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001791 p = *argptr;
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001792 if (p == NULL)
1793 return '\0';
1794 if (*p != '-')
1795 return '\0';
1796 if (*++p == '\0') /* just "-" ? */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001797 return '\0';
1798 argptr++;
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001799 if (LONE_DASH(p)) /* "--" ? */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001800 return '\0';
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001801 /* p => next "-param" */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001802 }
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001803 /* p => some option char in the middle of a "-param" */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001804 c = *p++;
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +00001805 for (q = optstring; *q != c;) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001806 if (*q == '\0')
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00001807 ash_msg_and_raise_error("illegal option -%c", c);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001808 if (*++q == ':')
1809 q++;
1810 }
1811 if (*++q == ':') {
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001812 if (*p == '\0') {
1813 p = *argptr++;
1814 if (p == NULL)
1815 ash_msg_and_raise_error("no arg for -%c option", c);
1816 }
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001817 optionarg = p;
1818 p = NULL;
1819 }
1820 optptr = p;
1821 return c;
1822}
1823
1824
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00001825/* ============ Shell variables */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001826
Denis Vlasenko01631112007-12-16 17:20:38 +00001827/*
1828 * The parsefile structure pointed to by the global variable parsefile
1829 * contains information about the current file being read.
1830 */
Denis Vlasenko01631112007-12-16 17:20:38 +00001831struct shparam {
1832 int nparam; /* # of positional parameters (without $0) */
1833#if ENABLE_ASH_GETOPTS
1834 int optind; /* next parameter to be processed by getopts */
1835 int optoff; /* used by getopts */
1836#endif
1837 unsigned char malloced; /* if parameter list dynamically allocated */
1838 char **p; /* parameter list */
1839};
1840
1841/*
1842 * Free the list of positional parameters.
1843 */
1844static void
1845freeparam(volatile struct shparam *param)
1846{
Denis Vlasenko01631112007-12-16 17:20:38 +00001847 if (param->malloced) {
Denis Vlasenko3177ba02008-07-13 20:39:23 +00001848 char **ap, **ap1;
1849 ap = ap1 = param->p;
1850 while (*ap)
1851 free(*ap++);
1852 free(ap1);
Denis Vlasenko01631112007-12-16 17:20:38 +00001853 }
1854}
1855
1856#if ENABLE_ASH_GETOPTS
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02001857static void FAST_FUNC getoptsreset(const char *value);
Denis Vlasenko01631112007-12-16 17:20:38 +00001858#endif
1859
1860struct var {
1861 struct var *next; /* next entry in hash list */
1862 int flags; /* flags are defined above */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001863 const char *var_text; /* name=value */
1864 void (*var_func)(const char *) FAST_FUNC; /* function to be called when */
Denis Vlasenko01631112007-12-16 17:20:38 +00001865 /* the variable gets set/unset */
1866};
1867
1868struct localvar {
1869 struct localvar *next; /* next local variable in list */
1870 struct var *vp; /* the variable that was made local */
1871 int flags; /* saved flags */
1872 const char *text; /* saved text */
1873};
1874
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001875/* flags */
1876#define VEXPORT 0x01 /* variable is exported */
1877#define VREADONLY 0x02 /* variable cannot be modified */
1878#define VSTRFIXED 0x04 /* variable struct is statically allocated */
1879#define VTEXTFIXED 0x08 /* text is statically allocated */
1880#define VSTACK 0x10 /* text is allocated on the stack */
1881#define VUNSET 0x20 /* the variable is not set */
1882#define VNOFUNC 0x40 /* don't call the callback function */
1883#define VNOSET 0x80 /* do not set variable - just readonly test */
1884#define VNOSAVE 0x100 /* when text is on the heap before setvareq */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00001885#if ENABLE_ASH_RANDOM_SUPPORT
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00001886# define VDYNAMIC 0x200 /* dynamic variable */
1887#else
1888# define VDYNAMIC 0
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001889#endif
1890
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00001891
Denis Vlasenko01631112007-12-16 17:20:38 +00001892/* Need to be before varinit_data[] */
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00001893#if ENABLE_LOCALE_SUPPORT
Denys Vlasenko2634bf32009-06-09 18:40:07 +02001894static void FAST_FUNC
Denis Vlasenkoa8915072007-02-23 21:10:06 +00001895change_lc_all(const char *value)
1896{
1897 if (value && *value != '\0')
1898 setlocale(LC_ALL, value);
1899}
Denys Vlasenko2634bf32009-06-09 18:40:07 +02001900static void FAST_FUNC
Denis Vlasenkoa8915072007-02-23 21:10:06 +00001901change_lc_ctype(const char *value)
1902{
1903 if (value && *value != '\0')
1904 setlocale(LC_CTYPE, value);
1905}
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00001906#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001907#if ENABLE_ASH_MAIL
1908static void chkmail(void);
Denys Vlasenko8c52f802011-02-04 17:36:21 +01001909static void changemail(const char *var_value) FAST_FUNC;
1910#else
1911# define chkmail() ((void)0)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001912#endif
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02001913static void changepath(const char *) FAST_FUNC;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001914#if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02001915static void change_random(const char *) FAST_FUNC;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001916#endif
1917
Denis Vlasenko01631112007-12-16 17:20:38 +00001918static const struct {
1919 int flags;
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001920 const char *var_text;
1921 void (*var_func)(const char *) FAST_FUNC;
Denis Vlasenko01631112007-12-16 17:20:38 +00001922} varinit_data[] = {
Denys Vlasenko566a3132012-07-07 21:40:35 +02001923 /*
1924 * Note: VEXPORT would not work correctly here for NOFORK applets:
1925 * some environment strings may be constant.
1926 */
Denis Vlasenko01631112007-12-16 17:20:38 +00001927 { VSTRFIXED|VTEXTFIXED , defifsvar , NULL },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001928#if ENABLE_ASH_MAIL
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001929 { VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL" , changemail },
1930 { VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH" , changemail },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001931#endif
Denis Vlasenko01631112007-12-16 17:20:38 +00001932 { VSTRFIXED|VTEXTFIXED , bb_PATH_root_path, changepath },
1933 { VSTRFIXED|VTEXTFIXED , "PS1=$ " , NULL },
1934 { VSTRFIXED|VTEXTFIXED , "PS2=> " , NULL },
1935 { VSTRFIXED|VTEXTFIXED , "PS4=+ " , NULL },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001936#if ENABLE_ASH_GETOPTS
Denys Vlasenkoe627ac92016-09-30 14:36:59 +02001937 { VSTRFIXED|VTEXTFIXED , defoptindvar, getoptsreset },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001938#endif
1939#if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001940 { VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM", change_random },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001941#endif
1942#if ENABLE_LOCALE_SUPPORT
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001943 { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_ALL" , change_lc_all },
1944 { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_CTYPE" , change_lc_ctype },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001945#endif
1946#if ENABLE_FEATURE_EDITING_SAVEHISTORY
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001947 { VSTRFIXED|VTEXTFIXED|VUNSET, "HISTFILE" , NULL },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001948#endif
1949};
1950
Denis Vlasenko0b769642008-07-24 07:54:57 +00001951struct redirtab;
Denis Vlasenko01631112007-12-16 17:20:38 +00001952
1953struct globals_var {
1954 struct shparam shellparam; /* $@ current positional parameters */
1955 struct redirtab *redirlist;
Denis Vlasenko01631112007-12-16 17:20:38 +00001956 int preverrout_fd; /* save fd2 before print debug if xflag is set. */
1957 struct var *vartab[VTABSIZE];
1958 struct var varinit[ARRAY_SIZE(varinit_data)];
1959};
Denis Vlasenko574f2f42008-02-27 18:41:59 +00001960extern struct globals_var *const ash_ptr_to_globals_var;
1961#define G_var (*ash_ptr_to_globals_var)
Denis Vlasenko01631112007-12-16 17:20:38 +00001962#define shellparam (G_var.shellparam )
Denis Vlasenko0b769642008-07-24 07:54:57 +00001963//#define redirlist (G_var.redirlist )
Denis Vlasenko01631112007-12-16 17:20:38 +00001964#define preverrout_fd (G_var.preverrout_fd)
1965#define vartab (G_var.vartab )
1966#define varinit (G_var.varinit )
1967#define INIT_G_var() do { \
Denis Vlasenko6b06cb82008-05-15 21:30:45 +00001968 unsigned i; \
Denis Vlasenko574f2f42008-02-27 18:41:59 +00001969 (*(struct globals_var**)&ash_ptr_to_globals_var) = xzalloc(sizeof(G_var)); \
1970 barrier(); \
Denis Vlasenko01631112007-12-16 17:20:38 +00001971 for (i = 0; i < ARRAY_SIZE(varinit_data); i++) { \
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001972 varinit[i].flags = varinit_data[i].flags; \
1973 varinit[i].var_text = varinit_data[i].var_text; \
1974 varinit[i].var_func = varinit_data[i].var_func; \
Denis Vlasenko01631112007-12-16 17:20:38 +00001975 } \
1976} while (0)
1977
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00001978#define vifs varinit[0]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001979#if ENABLE_ASH_MAIL
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00001980# define vmail (&vifs)[1]
1981# define vmpath (&vmail)[1]
1982# define vpath (&vmpath)[1]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001983#else
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00001984# define vpath (&vifs)[1]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001985#endif
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00001986#define vps1 (&vpath)[1]
1987#define vps2 (&vps1)[1]
1988#define vps4 (&vps2)[1]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001989#if ENABLE_ASH_GETOPTS
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00001990# define voptind (&vps4)[1]
1991# if ENABLE_ASH_RANDOM_SUPPORT
1992# define vrandom (&voptind)[1]
1993# endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001994#else
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00001995# if ENABLE_ASH_RANDOM_SUPPORT
1996# define vrandom (&vps4)[1]
1997# endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001998#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001999
2000/*
2001 * The following macros access the values of the above variables.
2002 * They have to skip over the name. They return the null string
2003 * for unset variables.
2004 */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002005#define ifsval() (vifs.var_text + 4)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002006#define ifsset() ((vifs.flags & VUNSET) == 0)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002007#if ENABLE_ASH_MAIL
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002008# define mailval() (vmail.var_text + 5)
2009# define mpathval() (vmpath.var_text + 9)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002010# define mpathset() ((vmpath.flags & VUNSET) == 0)
2011#endif
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002012#define pathval() (vpath.var_text + 5)
2013#define ps1val() (vps1.var_text + 4)
2014#define ps2val() (vps2.var_text + 4)
2015#define ps4val() (vps4.var_text + 4)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002016#if ENABLE_ASH_GETOPTS
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002017# define optindval() (voptind.var_text + 7)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002018#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002019
Denis Vlasenko01631112007-12-16 17:20:38 +00002020#if ENABLE_ASH_GETOPTS
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02002021static void FAST_FUNC
Denis Vlasenko01631112007-12-16 17:20:38 +00002022getoptsreset(const char *value)
2023{
Denys Vlasenkoa513bf32016-10-26 02:03:37 +02002024 shellparam.optind = number(value) ?: 1;
Denis Vlasenko01631112007-12-16 17:20:38 +00002025 shellparam.optoff = -1;
2026}
2027#endif
2028
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002029/*
2030 * Compares two strings up to the first = or '\0'. The first
2031 * string must be terminated by '='; the second may be terminated by
2032 * either '=' or '\0'.
2033 */
2034static int
2035varcmp(const char *p, const char *q)
2036{
2037 int c, d;
2038
2039 while ((c = *p) == (d = *q)) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02002040 if (c == '\0' || c == '=')
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002041 goto out;
2042 p++;
2043 q++;
2044 }
2045 if (c == '=')
Denis Vlasenko9650f362007-02-23 01:04:37 +00002046 c = '\0';
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002047 if (d == '=')
Denis Vlasenko9650f362007-02-23 01:04:37 +00002048 d = '\0';
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002049 out:
2050 return c - d;
2051}
2052
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002053/*
2054 * Find the appropriate entry in the hash table from the name.
2055 */
2056static struct var **
2057hashvar(const char *p)
2058{
2059 unsigned hashval;
2060
2061 hashval = ((unsigned char) *p) << 4;
2062 while (*p && *p != '=')
2063 hashval += (unsigned char) *p++;
2064 return &vartab[hashval % VTABSIZE];
2065}
2066
2067static int
2068vpcmp(const void *a, const void *b)
2069{
2070 return varcmp(*(const char **)a, *(const char **)b);
2071}
2072
2073/*
2074 * This routine initializes the builtin variables.
2075 */
2076static void
2077initvar(void)
2078{
2079 struct var *vp;
2080 struct var *end;
2081 struct var **vpp;
2082
2083 /*
2084 * PS1 depends on uid
2085 */
2086#if ENABLE_FEATURE_EDITING && ENABLE_FEATURE_EDITING_FANCY_PROMPT
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002087 vps1.var_text = "PS1=\\w \\$ ";
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002088#else
2089 if (!geteuid())
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002090 vps1.var_text = "PS1=# ";
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002091#endif
2092 vp = varinit;
Denis Vlasenko80b8b392007-06-25 10:55:35 +00002093 end = vp + ARRAY_SIZE(varinit);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002094 do {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002095 vpp = hashvar(vp->var_text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002096 vp->next = *vpp;
2097 *vpp = vp;
2098 } while (++vp < end);
2099}
2100
2101static struct var **
2102findvar(struct var **vpp, const char *name)
2103{
2104 for (; *vpp; vpp = &(*vpp)->next) {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002105 if (varcmp((*vpp)->var_text, name) == 0) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002106 break;
2107 }
2108 }
2109 return vpp;
2110}
2111
2112/*
2113 * Find the value of a variable. Returns NULL if not set.
2114 */
Denys Vlasenko03dad222010-01-12 23:29:57 +01002115static const char* FAST_FUNC
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002116lookupvar(const char *name)
2117{
2118 struct var *v;
2119
2120 v = *findvar(hashvar(name), name);
2121 if (v) {
Denis Vlasenko448d30e2008-06-27 00:24:11 +00002122#if ENABLE_ASH_RANDOM_SUPPORT
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002123 /*
2124 * Dynamic variables are implemented roughly the same way they are
2125 * in bash. Namely, they're "special" so long as they aren't unset.
2126 * As soon as they're unset, they're no longer dynamic, and dynamic
2127 * lookup will no longer happen at that point. -- PFM.
2128 */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002129 if (v->flags & VDYNAMIC)
2130 v->var_func(NULL);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002131#endif
2132 if (!(v->flags & VUNSET))
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002133 return var_end(v->var_text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002134 }
2135 return NULL;
2136}
2137
Denys Vlasenko37dc08b2016-10-02 04:38:07 +02002138static void
2139reinit_unicode_for_ash(void)
Denys Vlasenkoe9ab07c2014-08-13 18:00:08 +02002140{
2141 /* Unicode support should be activated even if LANG is set
2142 * _during_ shell execution, not only if it was set when
2143 * shell was started. Therefore, re-check LANG every time:
2144 */
2145 if (ENABLE_FEATURE_CHECK_UNICODE_IN_ENV
2146 || ENABLE_UNICODE_USING_LOCALE
2147 ) {
2148 const char *s = lookupvar("LC_ALL");
2149 if (!s) s = lookupvar("LC_CTYPE");
2150 if (!s) s = lookupvar("LANG");
2151 reinit_unicode(s);
2152 }
2153}
2154
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002155/*
2156 * Search the environment of a builtin command.
2157 */
Mike Frysinger98c52642009-04-02 10:02:37 +00002158static const char *
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002159bltinlookup(const char *name)
2160{
2161 struct strlist *sp;
2162
2163 for (sp = cmdenviron; sp; sp = sp->next) {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002164 if (varcmp(sp->text, name) == 0)
2165 return var_end(sp->text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002166 }
2167 return lookupvar(name);
2168}
2169
2170/*
2171 * Same as setvar except that the variable and value are passed in
2172 * the first argument as name=value. Since the first argument will
2173 * be actually stored in the table, it should not be a string that
2174 * will go away.
2175 * Called with interrupts off.
2176 */
2177static void
2178setvareq(char *s, int flags)
2179{
2180 struct var *vp, **vpp;
2181
2182 vpp = hashvar(s);
2183 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
2184 vp = *findvar(vpp, s);
2185 if (vp) {
2186 if ((vp->flags & (VREADONLY|VDYNAMIC)) == VREADONLY) {
2187 const char *n;
2188
2189 if (flags & VNOSAVE)
2190 free(s);
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002191 n = vp->var_text;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +02002192 exitstatus = 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002193 ash_msg_and_raise_error("%.*s: is read only", strchrnul(n, '=') - n, n);
2194 }
2195
2196 if (flags & VNOSET)
2197 return;
2198
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002199 if (vp->var_func && !(flags & VNOFUNC))
2200 vp->var_func(var_end(s));
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002201
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002202 if (!(vp->flags & (VTEXTFIXED|VSTACK)))
2203 free((char*)vp->var_text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002204
2205 flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
2206 } else {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002207 /* variable s is not found */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002208 if (flags & VNOSET)
2209 return;
Denis Vlasenko597906c2008-02-20 16:38:54 +00002210 vp = ckzalloc(sizeof(*vp));
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002211 vp->next = *vpp;
Denis Vlasenko597906c2008-02-20 16:38:54 +00002212 /*vp->func = NULL; - ckzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002213 *vpp = vp;
2214 }
2215 if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE)))
2216 s = ckstrdup(s);
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002217 vp->var_text = s;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002218 vp->flags = flags;
2219}
2220
2221/*
2222 * Set the value of a variable. The flags argument is ored with the
2223 * flags of the variable. If val is NULL, the variable is unset.
2224 */
2225static void
2226setvar(const char *name, const char *val, int flags)
2227{
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002228 const char *q;
2229 char *p;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002230 char *nameeq;
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002231 size_t namelen;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002232 size_t vallen;
2233
2234 q = endofname(name);
2235 p = strchrnul(q, '=');
2236 namelen = p - name;
2237 if (!namelen || p != q)
2238 ash_msg_and_raise_error("%.*s: bad variable name", namelen, name);
2239 vallen = 0;
2240 if (val == NULL) {
2241 flags |= VUNSET;
2242 } else {
2243 vallen = strlen(val);
2244 }
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002245
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002246 INT_OFF;
2247 nameeq = ckmalloc(namelen + vallen + 2);
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002248 p = memcpy(nameeq, name, namelen) + namelen;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002249 if (val) {
2250 *p++ = '=';
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002251 p = memcpy(p, val, vallen) + vallen;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002252 }
2253 *p = '\0';
2254 setvareq(nameeq, flags | VNOSAVE);
2255 INT_ON;
2256}
2257
Denys Vlasenko03dad222010-01-12 23:29:57 +01002258static void FAST_FUNC
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02002259setvar0(const char *name, const char *val)
Denys Vlasenko03dad222010-01-12 23:29:57 +01002260{
2261 setvar(name, val, 0);
2262}
2263
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002264/*
2265 * Unset the specified variable.
2266 */
2267static int
2268unsetvar(const char *s)
2269{
2270 struct var **vpp;
2271 struct var *vp;
2272 int retval;
2273
2274 vpp = findvar(hashvar(s), s);
2275 vp = *vpp;
2276 retval = 2;
2277 if (vp) {
2278 int flags = vp->flags;
2279
2280 retval = 1;
2281 if (flags & VREADONLY)
2282 goto out;
Denis Vlasenko448d30e2008-06-27 00:24:11 +00002283#if ENABLE_ASH_RANDOM_SUPPORT
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002284 vp->flags &= ~VDYNAMIC;
2285#endif
2286 if (flags & VUNSET)
2287 goto ok;
2288 if ((flags & VSTRFIXED) == 0) {
2289 INT_OFF;
2290 if ((flags & (VTEXTFIXED|VSTACK)) == 0)
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002291 free((char*)vp->var_text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002292 *vpp = vp->next;
2293 free(vp);
2294 INT_ON;
2295 } else {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02002296 setvar0(s, NULL);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002297 vp->flags &= ~VEXPORT;
2298 }
2299 ok:
2300 retval = 0;
2301 }
2302 out:
2303 return retval;
2304}
2305
2306/*
2307 * Process a linked list of variable assignments.
2308 */
2309static void
2310listsetvar(struct strlist *list_set_var, int flags)
2311{
2312 struct strlist *lp = list_set_var;
2313
2314 if (!lp)
2315 return;
2316 INT_OFF;
2317 do {
2318 setvareq(lp->text, flags);
Denis Vlasenko9650f362007-02-23 01:04:37 +00002319 lp = lp->next;
2320 } while (lp);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002321 INT_ON;
2322}
2323
2324/*
2325 * Generate a list of variables satisfying the given conditions.
2326 */
2327static char **
2328listvars(int on, int off, char ***end)
2329{
2330 struct var **vpp;
2331 struct var *vp;
2332 char **ep;
2333 int mask;
2334
2335 STARTSTACKSTR(ep);
2336 vpp = vartab;
2337 mask = on | off;
2338 do {
2339 for (vp = *vpp; vp; vp = vp->next) {
2340 if ((vp->flags & mask) == on) {
2341 if (ep == stackstrend())
2342 ep = growstackstr();
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002343 *ep++ = (char*)vp->var_text;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002344 }
2345 }
2346 } while (++vpp < vartab + VTABSIZE);
2347 if (ep == stackstrend())
2348 ep = growstackstr();
2349 if (end)
2350 *end = ep;
2351 *ep++ = NULL;
2352 return grabstackstr(ep);
2353}
2354
2355
2356/* ============ Path search helper
2357 *
2358 * The variable path (passed by reference) should be set to the start
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002359 * of the path before the first call; path_advance will update
2360 * this value as it proceeds. Successive calls to path_advance will return
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002361 * the possible path expansions in sequence. If an option (indicated by
2362 * a percent sign) appears in the path entry then the global variable
2363 * pathopt will be set to point to it; otherwise pathopt will be set to
2364 * NULL.
2365 */
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002366static const char *pathopt; /* set by path_advance */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002367
2368static char *
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002369path_advance(const char **path, const char *name)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002370{
2371 const char *p;
2372 char *q;
2373 const char *start;
2374 size_t len;
2375
2376 if (*path == NULL)
2377 return NULL;
2378 start = *path;
Denis Vlasenkof7d56652008-03-25 05:51:41 +00002379 for (p = start; *p && *p != ':' && *p != '%'; p++)
2380 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002381 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
2382 while (stackblocksize() < len)
2383 growstackblock();
2384 q = stackblock();
2385 if (p != start) {
2386 memcpy(q, start, p - start);
2387 q += p - start;
2388 *q++ = '/';
2389 }
2390 strcpy(q, name);
2391 pathopt = NULL;
2392 if (*p == '%') {
2393 pathopt = ++p;
Denis Vlasenkof7d56652008-03-25 05:51:41 +00002394 while (*p && *p != ':')
2395 p++;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002396 }
2397 if (*p == ':')
2398 *path = p + 1;
2399 else
2400 *path = NULL;
2401 return stalloc(len);
2402}
2403
2404
2405/* ============ Prompt */
2406
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +00002407static smallint doprompt; /* if set, prompt the user */
2408static smallint needprompt; /* true if interactive and at start of line */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002409
2410#if ENABLE_FEATURE_EDITING
2411static line_input_t *line_input_state;
2412static const char *cmdedit_prompt;
2413static void
2414putprompt(const char *s)
2415{
2416 if (ENABLE_ASH_EXPAND_PRMT) {
2417 free((char*)cmdedit_prompt);
Denis Vlasenko4222ae42007-02-25 02:37:49 +00002418 cmdedit_prompt = ckstrdup(s);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002419 return;
2420 }
2421 cmdedit_prompt = s;
2422}
2423#else
2424static void
2425putprompt(const char *s)
2426{
2427 out2str(s);
2428}
2429#endif
2430
2431#if ENABLE_ASH_EXPAND_PRMT
2432/* expandstr() needs parsing machinery, so it is far away ahead... */
2433static const char *expandstr(const char *ps);
2434#else
2435#define expandstr(s) s
2436#endif
2437
2438static void
Denys Vlasenko958581a2010-09-12 15:04:27 +02002439setprompt_if(smallint do_set, int whichprompt)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002440{
2441 const char *prompt;
Denys Vlasenko958581a2010-09-12 15:04:27 +02002442 IF_ASH_EXPAND_PRMT(struct stackmark smark;)
2443
2444 if (!do_set)
2445 return;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002446
2447 needprompt = 0;
2448
2449 switch (whichprompt) {
2450 case 1:
2451 prompt = ps1val();
2452 break;
2453 case 2:
2454 prompt = ps2val();
2455 break;
2456 default: /* 0 */
2457 prompt = nullstr;
2458 }
2459#if ENABLE_ASH_EXPAND_PRMT
Denys Vlasenko60ca8342016-09-30 11:21:21 +02002460 pushstackmark(&smark, stackblocksize());
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002461#endif
2462 putprompt(expandstr(prompt));
2463#if ENABLE_ASH_EXPAND_PRMT
2464 popstackmark(&smark);
2465#endif
2466}
2467
2468
2469/* ============ The cd and pwd commands */
2470
2471#define CD_PHYSICAL 1
2472#define CD_PRINT 2
2473
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002474static int
2475cdopt(void)
2476{
2477 int flags = 0;
2478 int i, j;
2479
2480 j = 'L';
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02002481 while ((i = nextopt("LP")) != '\0') {
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002482 if (i != j) {
2483 flags ^= CD_PHYSICAL;
2484 j = i;
2485 }
2486 }
2487
2488 return flags;
2489}
2490
2491/*
2492 * Update curdir (the name of the current directory) in response to a
2493 * cd command.
2494 */
2495static const char *
2496updatepwd(const char *dir)
2497{
2498 char *new;
2499 char *p;
2500 char *cdcomppath;
2501 const char *lim;
2502
Denys Vlasenko8e2bc472016-09-28 23:02:57 +02002503 cdcomppath = sstrdup(dir);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002504 STARTSTACKSTR(new);
2505 if (*dir != '/') {
2506 if (curdir == nullstr)
2507 return 0;
2508 new = stack_putstr(curdir, new);
2509 }
2510 new = makestrspace(strlen(dir) + 2, new);
Denis Vlasenko29eb3592008-05-18 14:06:08 +00002511 lim = (char *)stackblock() + 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002512 if (*dir != '/') {
2513 if (new[-1] != '/')
2514 USTPUTC('/', new);
2515 if (new > lim && *lim == '/')
2516 lim++;
2517 } else {
2518 USTPUTC('/', new);
2519 cdcomppath++;
2520 if (dir[1] == '/' && dir[2] != '/') {
2521 USTPUTC('/', new);
2522 cdcomppath++;
2523 lim++;
2524 }
2525 }
2526 p = strtok(cdcomppath, "/");
2527 while (p) {
2528 switch (*p) {
2529 case '.':
2530 if (p[1] == '.' && p[2] == '\0') {
2531 while (new > lim) {
2532 STUNPUTC(new);
2533 if (new[-1] == '/')
2534 break;
2535 }
2536 break;
Denis Vlasenko16abcd92007-04-13 23:59:52 +00002537 }
2538 if (p[1] == '\0')
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002539 break;
2540 /* fall through */
2541 default:
2542 new = stack_putstr(p, new);
2543 USTPUTC('/', new);
2544 }
Denys Vlasenko00da72b2015-10-23 18:43:16 +02002545 p = strtok(NULL, "/");
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002546 }
2547 if (new > lim)
2548 STUNPUTC(new);
2549 *new = 0;
2550 return stackblock();
2551}
2552
2553/*
2554 * Find out what the current directory is. If we already know the current
2555 * directory, this routine returns immediately.
2556 */
2557static char *
2558getpwd(void)
2559{
Denis Vlasenko01631112007-12-16 17:20:38 +00002560 char *dir = getcwd(NULL, 0); /* huh, using glibc extension? */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002561 return dir ? dir : nullstr;
2562}
2563
2564static void
2565setpwd(const char *val, int setold)
2566{
2567 char *oldcur, *dir;
2568
2569 oldcur = dir = curdir;
2570
2571 if (setold) {
2572 setvar("OLDPWD", oldcur, VEXPORT);
2573 }
2574 INT_OFF;
2575 if (physdir != nullstr) {
2576 if (physdir != oldcur)
2577 free(physdir);
2578 physdir = nullstr;
2579 }
2580 if (oldcur == val || !val) {
2581 char *s = getpwd();
2582 physdir = s;
2583 if (!val)
2584 dir = s;
2585 } else
2586 dir = ckstrdup(val);
2587 if (oldcur != dir && oldcur != nullstr) {
2588 free(oldcur);
2589 }
2590 curdir = dir;
2591 INT_ON;
2592 setvar("PWD", dir, VEXPORT);
2593}
2594
2595static void hashcd(void);
2596
2597/*
Denys Vlasenko70392332016-10-27 02:31:55 +02002598 * Actually do the chdir. We also call hashcd to let other routines
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002599 * know that the current directory has changed.
2600 */
2601static int
2602docd(const char *dest, int flags)
2603{
Denys Vlasenko4b1100e2010-03-05 14:10:54 +01002604 const char *dir = NULL;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002605 int err;
2606
2607 TRACE(("docd(\"%s\", %d) called\n", dest, flags));
2608
2609 INT_OFF;
2610 if (!(flags & CD_PHYSICAL)) {
2611 dir = updatepwd(dest);
2612 if (dir)
2613 dest = dir;
2614 }
2615 err = chdir(dest);
2616 if (err)
2617 goto out;
2618 setpwd(dir, 1);
2619 hashcd();
2620 out:
2621 INT_ON;
2622 return err;
2623}
2624
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02002625static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00002626cdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002627{
2628 const char *dest;
2629 const char *path;
2630 const char *p;
2631 char c;
2632 struct stat statb;
2633 int flags;
2634
2635 flags = cdopt();
2636 dest = *argptr;
2637 if (!dest)
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02002638 dest = bltinlookup("HOME");
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002639 else if (LONE_DASH(dest)) {
2640 dest = bltinlookup("OLDPWD");
2641 flags |= CD_PRINT;
2642 }
2643 if (!dest)
2644 dest = nullstr;
2645 if (*dest == '/')
Denys Vlasenko0e081d02016-10-26 19:56:05 +02002646 goto step6;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002647 if (*dest == '.') {
2648 c = dest[1];
2649 dotdot:
2650 switch (c) {
2651 case '\0':
2652 case '/':
2653 goto step6;
2654 case '.':
2655 c = dest[2];
2656 if (c != '.')
2657 goto dotdot;
2658 }
2659 }
2660 if (!*dest)
2661 dest = ".";
2662 path = bltinlookup("CDPATH");
Denys Vlasenko0e081d02016-10-26 19:56:05 +02002663 while (path) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002664 c = *path;
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002665 p = path_advance(&path, dest);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002666 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
2667 if (c && c != ':')
2668 flags |= CD_PRINT;
2669 docd:
2670 if (!docd(p, flags))
2671 goto out;
Denys Vlasenko0e081d02016-10-26 19:56:05 +02002672 goto err;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002673 }
Denys Vlasenko0e081d02016-10-26 19:56:05 +02002674 }
2675
2676 step6:
2677 p = dest;
2678 goto docd;
2679
2680 err:
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002681 ash_msg_and_raise_error("can't cd to %s", dest);
2682 /* NOTREACHED */
2683 out:
2684 if (flags & CD_PRINT)
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02002685 out1fmt("%s\n", curdir);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002686 return 0;
2687}
2688
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02002689static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00002690pwdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002691{
2692 int flags;
2693 const char *dir = curdir;
2694
2695 flags = cdopt();
2696 if (flags) {
2697 if (physdir == nullstr)
2698 setpwd(dir, 0);
2699 dir = physdir;
2700 }
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02002701 out1fmt("%s\n", dir);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002702 return 0;
2703}
2704
Denis Vlasenko0c032a42007-02-23 01:03:40 +00002705
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00002706/* ============ ... */
Eric Andersenc470f442003-07-28 09:56:35 +00002707
Denis Vlasenko834dee72008-10-07 09:18:30 +00002708
Denys Vlasenko82dd14a2010-05-17 10:10:01 +02002709#define IBUFSIZ (ENABLE_FEATURE_EDITING ? CONFIG_FEATURE_EDITING_MAX_LEN : 1024)
Eric Andersenc470f442003-07-28 09:56:35 +00002710
Eric Andersenc470f442003-07-28 09:56:35 +00002711/* Syntax classes */
Denis Vlasenko834dee72008-10-07 09:18:30 +00002712#define CWORD 0 /* character is nothing special */
2713#define CNL 1 /* newline character */
2714#define CBACK 2 /* a backslash character */
2715#define CSQUOTE 3 /* single quote */
2716#define CDQUOTE 4 /* double quote */
Eric Andersenc470f442003-07-28 09:56:35 +00002717#define CENDQUOTE 5 /* a terminating quote */
Denis Vlasenko834dee72008-10-07 09:18:30 +00002718#define CBQUOTE 6 /* backwards single quote */
2719#define CVAR 7 /* a dollar sign */
2720#define CENDVAR 8 /* a '}' character */
2721#define CLP 9 /* a left paren in arithmetic */
2722#define CRP 10 /* a right paren in arithmetic */
Eric Andersenc470f442003-07-28 09:56:35 +00002723#define CENDFILE 11 /* end of file */
Denis Vlasenko834dee72008-10-07 09:18:30 +00002724#define CCTL 12 /* like CWORD, except it must be escaped */
2725#define CSPCL 13 /* these terminate a word */
2726#define CIGN 14 /* character should be ignored */
Eric Andersenc470f442003-07-28 09:56:35 +00002727
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002728#define PEOF 256
Denis Vlasenko131ae172007-02-18 13:00:19 +00002729#if ENABLE_ASH_ALIAS
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002730# define PEOA 257
Eric Andersenc470f442003-07-28 09:56:35 +00002731#endif
2732
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002733#define USE_SIT_FUNCTION ENABLE_ASH_OPTIMIZE_FOR_SIZE
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002734
Mike Frysinger98c52642009-04-02 10:02:37 +00002735#if ENABLE_SH_MATH_SUPPORT
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002736# define SIT_ITEM(a,b,c,d) (a | (b << 4) | (c << 8) | (d << 12))
Eric Andersenc470f442003-07-28 09:56:35 +00002737#else
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002738# define SIT_ITEM(a,b,c,d) (a | (b << 4) | (c << 8))
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002739#endif
Denys Vlasenko3e134eb2016-04-22 18:09:21 +02002740static const uint16_t S_I_T[] ALIGN2 = {
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002741#if ENABLE_ASH_ALIAS
2742 SIT_ITEM(CSPCL , CIGN , CIGN , CIGN ), /* 0, PEOA */
2743#endif
2744 SIT_ITEM(CSPCL , CWORD , CWORD, CWORD ), /* 1, ' ' */
2745 SIT_ITEM(CNL , CNL , CNL , CNL ), /* 2, \n */
2746 SIT_ITEM(CWORD , CCTL , CCTL , CWORD ), /* 3, !*-/:=?[]~ */
2747 SIT_ITEM(CDQUOTE , CENDQUOTE, CWORD, CWORD ), /* 4, '"' */
2748 SIT_ITEM(CVAR , CVAR , CWORD, CVAR ), /* 5, $ */
2749 SIT_ITEM(CSQUOTE , CWORD , CENDQUOTE, CWORD), /* 6, "'" */
2750 SIT_ITEM(CSPCL , CWORD , CWORD, CLP ), /* 7, ( */
2751 SIT_ITEM(CSPCL , CWORD , CWORD, CRP ), /* 8, ) */
2752 SIT_ITEM(CBACK , CBACK , CCTL , CBACK ), /* 9, \ */
2753 SIT_ITEM(CBQUOTE , CBQUOTE , CWORD, CBQUOTE), /* 10, ` */
2754 SIT_ITEM(CENDVAR , CENDVAR , CWORD, CENDVAR), /* 11, } */
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002755#if !USE_SIT_FUNCTION
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002756 SIT_ITEM(CENDFILE, CENDFILE , CENDFILE, CENDFILE),/* 12, PEOF */
2757 SIT_ITEM(CWORD , CWORD , CWORD, CWORD ), /* 13, 0-9A-Za-z */
2758 SIT_ITEM(CCTL , CCTL , CCTL , CCTL ) /* 14, CTLESC ... */
2759#endif
2760#undef SIT_ITEM
Eric Andersenc470f442003-07-28 09:56:35 +00002761};
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002762/* Constants below must match table above */
2763enum {
2764#if ENABLE_ASH_ALIAS
2765 CSPCL_CIGN_CIGN_CIGN , /* 0 */
2766#endif
2767 CSPCL_CWORD_CWORD_CWORD , /* 1 */
2768 CNL_CNL_CNL_CNL , /* 2 */
2769 CWORD_CCTL_CCTL_CWORD , /* 3 */
2770 CDQUOTE_CENDQUOTE_CWORD_CWORD , /* 4 */
2771 CVAR_CVAR_CWORD_CVAR , /* 5 */
2772 CSQUOTE_CWORD_CENDQUOTE_CWORD , /* 6 */
2773 CSPCL_CWORD_CWORD_CLP , /* 7 */
2774 CSPCL_CWORD_CWORD_CRP , /* 8 */
2775 CBACK_CBACK_CCTL_CBACK , /* 9 */
2776 CBQUOTE_CBQUOTE_CWORD_CBQUOTE , /* 10 */
2777 CENDVAR_CENDVAR_CWORD_CENDVAR , /* 11 */
2778 CENDFILE_CENDFILE_CENDFILE_CENDFILE, /* 12 */
2779 CWORD_CWORD_CWORD_CWORD , /* 13 */
2780 CCTL_CCTL_CCTL_CCTL , /* 14 */
2781};
Eric Andersen2870d962001-07-02 17:27:21 +00002782
Denys Vlasenkocd716832009-11-28 22:14:02 +01002783/* c in SIT(c, syntax) must be an *unsigned char* or PEOA or PEOF,
2784 * caller must ensure proper cast on it if c is *char_ptr!
2785 */
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002786/* Values for syntax param */
2787#define BASESYNTAX 0 /* not in quotes */
2788#define DQSYNTAX 1 /* in double quotes */
2789#define SQSYNTAX 2 /* in single quotes */
2790#define ARISYNTAX 3 /* in arithmetic */
2791#define PSSYNTAX 4 /* prompt. never passed to SIT() */
Denys Vlasenkocd716832009-11-28 22:14:02 +01002792
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002793#if USE_SIT_FUNCTION
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002794
Denis Vlasenko0c032a42007-02-23 01:03:40 +00002795static int
2796SIT(int c, int syntax)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002797{
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02002798 /* Used to also have '/' in this string: "\t\n !\"$&'()*-/:;<=>?[\\]`|}~" */
2799 static const char spec_symbls[] ALIGN1 = "\t\n !\"$&'()*-:;<=>?[\\]`|}~";
2800 /*
2801 * This causes '/' to be prepended with CTLESC in dquoted string,
2802 * making "./file"* treated incorrectly because we feed
2803 * ".\/file*" string to glob(), confusing it (see expandmeta func).
2804 * The "homegrown" glob implementation is okay with that,
2805 * but glibc one isn't. With '/' always treated as CWORD,
2806 * both work fine.
2807 */
Denys Vlasenkocd716832009-11-28 22:14:02 +01002808# if ENABLE_ASH_ALIAS
2809 static const uint8_t syntax_index_table[] ALIGN1 = {
Eric Andersenc470f442003-07-28 09:56:35 +00002810 1, 2, 1, 3, 4, 5, 1, 6, /* "\t\n !\"$&'" */
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02002811 7, 8, 3, 3,/*3,*/3, 1, 1, /* "()*-/:;<" */
Eric Andersenc470f442003-07-28 09:56:35 +00002812 3, 1, 3, 3, 9, 3, 10, 1, /* "=>?[\\]`|" */
2813 11, 3 /* "}~" */
2814 };
Denys Vlasenkocd716832009-11-28 22:14:02 +01002815# else
2816 static const uint8_t syntax_index_table[] ALIGN1 = {
Eric Andersenc470f442003-07-28 09:56:35 +00002817 0, 1, 0, 2, 3, 4, 0, 5, /* "\t\n !\"$&'" */
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02002818 6, 7, 2, 2,/*2,*/2, 0, 0, /* "()*-/:;<" */
Eric Andersenc470f442003-07-28 09:56:35 +00002819 2, 0, 2, 2, 8, 2, 9, 0, /* "=>?[\\]`|" */
2820 10, 2 /* "}~" */
2821 };
Denys Vlasenkocd716832009-11-28 22:14:02 +01002822# endif
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002823 const char *s;
2824 int indx;
2825
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002826 if (c == PEOF)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002827 return CENDFILE;
Denys Vlasenkocd716832009-11-28 22:14:02 +01002828# if ENABLE_ASH_ALIAS
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002829 if (c == PEOA)
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002830 indx = 0;
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002831 else
Denys Vlasenkocd716832009-11-28 22:14:02 +01002832# endif
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002833 {
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002834 /* Cast is purely for paranoia here,
2835 * just in case someone passed signed char to us */
2836 if ((unsigned char)c >= CTL_FIRST
2837 && (unsigned char)c <= CTL_LAST
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002838 ) {
2839 return CCTL;
2840 }
2841 s = strchrnul(spec_symbls, c);
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002842 if (*s == '\0')
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002843 return CWORD;
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002844 indx = syntax_index_table[s - spec_symbls];
2845 }
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002846 return (S_I_T[indx] >> (syntax*4)) & 0xf;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002847}
2848
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00002849#else /* !USE_SIT_FUNCTION */
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002850
Denys Vlasenko3e134eb2016-04-22 18:09:21 +02002851static const uint8_t syntax_index_table[] ALIGN1 = {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002852 /* BASESYNTAX_DQSYNTAX_SQSYNTAX_ARISYNTAX */
Denys Vlasenkocd716832009-11-28 22:14:02 +01002853 /* 0 */ CWORD_CWORD_CWORD_CWORD,
2854 /* 1 */ CWORD_CWORD_CWORD_CWORD,
2855 /* 2 */ CWORD_CWORD_CWORD_CWORD,
2856 /* 3 */ CWORD_CWORD_CWORD_CWORD,
2857 /* 4 */ CWORD_CWORD_CWORD_CWORD,
2858 /* 5 */ CWORD_CWORD_CWORD_CWORD,
2859 /* 6 */ CWORD_CWORD_CWORD_CWORD,
2860 /* 7 */ CWORD_CWORD_CWORD_CWORD,
2861 /* 8 */ CWORD_CWORD_CWORD_CWORD,
2862 /* 9 "\t" */ CSPCL_CWORD_CWORD_CWORD,
2863 /* 10 "\n" */ CNL_CNL_CNL_CNL,
2864 /* 11 */ CWORD_CWORD_CWORD_CWORD,
2865 /* 12 */ CWORD_CWORD_CWORD_CWORD,
2866 /* 13 */ CWORD_CWORD_CWORD_CWORD,
2867 /* 14 */ CWORD_CWORD_CWORD_CWORD,
2868 /* 15 */ CWORD_CWORD_CWORD_CWORD,
2869 /* 16 */ CWORD_CWORD_CWORD_CWORD,
2870 /* 17 */ CWORD_CWORD_CWORD_CWORD,
2871 /* 18 */ CWORD_CWORD_CWORD_CWORD,
2872 /* 19 */ CWORD_CWORD_CWORD_CWORD,
2873 /* 20 */ CWORD_CWORD_CWORD_CWORD,
2874 /* 21 */ CWORD_CWORD_CWORD_CWORD,
2875 /* 22 */ CWORD_CWORD_CWORD_CWORD,
2876 /* 23 */ CWORD_CWORD_CWORD_CWORD,
2877 /* 24 */ CWORD_CWORD_CWORD_CWORD,
2878 /* 25 */ CWORD_CWORD_CWORD_CWORD,
2879 /* 26 */ CWORD_CWORD_CWORD_CWORD,
2880 /* 27 */ CWORD_CWORD_CWORD_CWORD,
2881 /* 28 */ CWORD_CWORD_CWORD_CWORD,
2882 /* 29 */ CWORD_CWORD_CWORD_CWORD,
2883 /* 30 */ CWORD_CWORD_CWORD_CWORD,
2884 /* 31 */ CWORD_CWORD_CWORD_CWORD,
2885 /* 32 " " */ CSPCL_CWORD_CWORD_CWORD,
2886 /* 33 "!" */ CWORD_CCTL_CCTL_CWORD,
2887 /* 34 """ */ CDQUOTE_CENDQUOTE_CWORD_CWORD,
2888 /* 35 "#" */ CWORD_CWORD_CWORD_CWORD,
2889 /* 36 "$" */ CVAR_CVAR_CWORD_CVAR,
2890 /* 37 "%" */ CWORD_CWORD_CWORD_CWORD,
2891 /* 38 "&" */ CSPCL_CWORD_CWORD_CWORD,
2892 /* 39 "'" */ CSQUOTE_CWORD_CENDQUOTE_CWORD,
2893 /* 40 "(" */ CSPCL_CWORD_CWORD_CLP,
2894 /* 41 ")" */ CSPCL_CWORD_CWORD_CRP,
2895 /* 42 "*" */ CWORD_CCTL_CCTL_CWORD,
2896 /* 43 "+" */ CWORD_CWORD_CWORD_CWORD,
2897 /* 44 "," */ CWORD_CWORD_CWORD_CWORD,
2898 /* 45 "-" */ CWORD_CCTL_CCTL_CWORD,
2899 /* 46 "." */ CWORD_CWORD_CWORD_CWORD,
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02002900/* "/" was CWORD_CCTL_CCTL_CWORD, see comment in SIT() function why this is changed: */
2901 /* 47 "/" */ CWORD_CWORD_CWORD_CWORD,
Denys Vlasenkocd716832009-11-28 22:14:02 +01002902 /* 48 "0" */ CWORD_CWORD_CWORD_CWORD,
2903 /* 49 "1" */ CWORD_CWORD_CWORD_CWORD,
2904 /* 50 "2" */ CWORD_CWORD_CWORD_CWORD,
2905 /* 51 "3" */ CWORD_CWORD_CWORD_CWORD,
2906 /* 52 "4" */ CWORD_CWORD_CWORD_CWORD,
2907 /* 53 "5" */ CWORD_CWORD_CWORD_CWORD,
2908 /* 54 "6" */ CWORD_CWORD_CWORD_CWORD,
2909 /* 55 "7" */ CWORD_CWORD_CWORD_CWORD,
2910 /* 56 "8" */ CWORD_CWORD_CWORD_CWORD,
2911 /* 57 "9" */ CWORD_CWORD_CWORD_CWORD,
2912 /* 58 ":" */ CWORD_CCTL_CCTL_CWORD,
2913 /* 59 ";" */ CSPCL_CWORD_CWORD_CWORD,
2914 /* 60 "<" */ CSPCL_CWORD_CWORD_CWORD,
2915 /* 61 "=" */ CWORD_CCTL_CCTL_CWORD,
2916 /* 62 ">" */ CSPCL_CWORD_CWORD_CWORD,
2917 /* 63 "?" */ CWORD_CCTL_CCTL_CWORD,
2918 /* 64 "@" */ CWORD_CWORD_CWORD_CWORD,
2919 /* 65 "A" */ CWORD_CWORD_CWORD_CWORD,
2920 /* 66 "B" */ CWORD_CWORD_CWORD_CWORD,
2921 /* 67 "C" */ CWORD_CWORD_CWORD_CWORD,
2922 /* 68 "D" */ CWORD_CWORD_CWORD_CWORD,
2923 /* 69 "E" */ CWORD_CWORD_CWORD_CWORD,
2924 /* 70 "F" */ CWORD_CWORD_CWORD_CWORD,
2925 /* 71 "G" */ CWORD_CWORD_CWORD_CWORD,
2926 /* 72 "H" */ CWORD_CWORD_CWORD_CWORD,
2927 /* 73 "I" */ CWORD_CWORD_CWORD_CWORD,
2928 /* 74 "J" */ CWORD_CWORD_CWORD_CWORD,
2929 /* 75 "K" */ CWORD_CWORD_CWORD_CWORD,
2930 /* 76 "L" */ CWORD_CWORD_CWORD_CWORD,
2931 /* 77 "M" */ CWORD_CWORD_CWORD_CWORD,
2932 /* 78 "N" */ CWORD_CWORD_CWORD_CWORD,
2933 /* 79 "O" */ CWORD_CWORD_CWORD_CWORD,
2934 /* 80 "P" */ CWORD_CWORD_CWORD_CWORD,
2935 /* 81 "Q" */ CWORD_CWORD_CWORD_CWORD,
2936 /* 82 "R" */ CWORD_CWORD_CWORD_CWORD,
2937 /* 83 "S" */ CWORD_CWORD_CWORD_CWORD,
2938 /* 84 "T" */ CWORD_CWORD_CWORD_CWORD,
2939 /* 85 "U" */ CWORD_CWORD_CWORD_CWORD,
2940 /* 86 "V" */ CWORD_CWORD_CWORD_CWORD,
2941 /* 87 "W" */ CWORD_CWORD_CWORD_CWORD,
2942 /* 88 "X" */ CWORD_CWORD_CWORD_CWORD,
2943 /* 89 "Y" */ CWORD_CWORD_CWORD_CWORD,
2944 /* 90 "Z" */ CWORD_CWORD_CWORD_CWORD,
2945 /* 91 "[" */ CWORD_CCTL_CCTL_CWORD,
2946 /* 92 "\" */ CBACK_CBACK_CCTL_CBACK,
2947 /* 93 "]" */ CWORD_CCTL_CCTL_CWORD,
2948 /* 94 "^" */ CWORD_CWORD_CWORD_CWORD,
2949 /* 95 "_" */ CWORD_CWORD_CWORD_CWORD,
2950 /* 96 "`" */ CBQUOTE_CBQUOTE_CWORD_CBQUOTE,
2951 /* 97 "a" */ CWORD_CWORD_CWORD_CWORD,
2952 /* 98 "b" */ CWORD_CWORD_CWORD_CWORD,
2953 /* 99 "c" */ CWORD_CWORD_CWORD_CWORD,
2954 /* 100 "d" */ CWORD_CWORD_CWORD_CWORD,
2955 /* 101 "e" */ CWORD_CWORD_CWORD_CWORD,
2956 /* 102 "f" */ CWORD_CWORD_CWORD_CWORD,
2957 /* 103 "g" */ CWORD_CWORD_CWORD_CWORD,
2958 /* 104 "h" */ CWORD_CWORD_CWORD_CWORD,
2959 /* 105 "i" */ CWORD_CWORD_CWORD_CWORD,
2960 /* 106 "j" */ CWORD_CWORD_CWORD_CWORD,
2961 /* 107 "k" */ CWORD_CWORD_CWORD_CWORD,
2962 /* 108 "l" */ CWORD_CWORD_CWORD_CWORD,
2963 /* 109 "m" */ CWORD_CWORD_CWORD_CWORD,
2964 /* 110 "n" */ CWORD_CWORD_CWORD_CWORD,
2965 /* 111 "o" */ CWORD_CWORD_CWORD_CWORD,
2966 /* 112 "p" */ CWORD_CWORD_CWORD_CWORD,
2967 /* 113 "q" */ CWORD_CWORD_CWORD_CWORD,
2968 /* 114 "r" */ CWORD_CWORD_CWORD_CWORD,
2969 /* 115 "s" */ CWORD_CWORD_CWORD_CWORD,
2970 /* 116 "t" */ CWORD_CWORD_CWORD_CWORD,
2971 /* 117 "u" */ CWORD_CWORD_CWORD_CWORD,
2972 /* 118 "v" */ CWORD_CWORD_CWORD_CWORD,
2973 /* 119 "w" */ CWORD_CWORD_CWORD_CWORD,
2974 /* 120 "x" */ CWORD_CWORD_CWORD_CWORD,
2975 /* 121 "y" */ CWORD_CWORD_CWORD_CWORD,
2976 /* 122 "z" */ CWORD_CWORD_CWORD_CWORD,
2977 /* 123 "{" */ CWORD_CWORD_CWORD_CWORD,
2978 /* 124 "|" */ CSPCL_CWORD_CWORD_CWORD,
2979 /* 125 "}" */ CENDVAR_CENDVAR_CWORD_CENDVAR,
2980 /* 126 "~" */ CWORD_CCTL_CCTL_CWORD,
2981 /* 127 del */ CWORD_CWORD_CWORD_CWORD,
2982 /* 128 0x80 */ CWORD_CWORD_CWORD_CWORD,
2983 /* 129 CTLESC */ CCTL_CCTL_CCTL_CCTL,
2984 /* 130 CTLVAR */ CCTL_CCTL_CCTL_CCTL,
2985 /* 131 CTLENDVAR */ CCTL_CCTL_CCTL_CCTL,
2986 /* 132 CTLBACKQ */ CCTL_CCTL_CCTL_CCTL,
2987 /* 133 CTLQUOTE */ CCTL_CCTL_CCTL_CCTL,
2988 /* 134 CTLARI */ CCTL_CCTL_CCTL_CCTL,
2989 /* 135 CTLENDARI */ CCTL_CCTL_CCTL_CCTL,
2990 /* 136 CTLQUOTEMARK */ CCTL_CCTL_CCTL_CCTL,
2991 /* 137 */ CWORD_CWORD_CWORD_CWORD,
2992 /* 138 */ CWORD_CWORD_CWORD_CWORD,
2993 /* 139 */ CWORD_CWORD_CWORD_CWORD,
2994 /* 140 */ CWORD_CWORD_CWORD_CWORD,
2995 /* 141 */ CWORD_CWORD_CWORD_CWORD,
2996 /* 142 */ CWORD_CWORD_CWORD_CWORD,
2997 /* 143 */ CWORD_CWORD_CWORD_CWORD,
2998 /* 144 */ CWORD_CWORD_CWORD_CWORD,
2999 /* 145 */ CWORD_CWORD_CWORD_CWORD,
3000 /* 146 */ CWORD_CWORD_CWORD_CWORD,
3001 /* 147 */ CWORD_CWORD_CWORD_CWORD,
3002 /* 148 */ CWORD_CWORD_CWORD_CWORD,
3003 /* 149 */ CWORD_CWORD_CWORD_CWORD,
3004 /* 150 */ CWORD_CWORD_CWORD_CWORD,
3005 /* 151 */ CWORD_CWORD_CWORD_CWORD,
3006 /* 152 */ CWORD_CWORD_CWORD_CWORD,
3007 /* 153 */ CWORD_CWORD_CWORD_CWORD,
3008 /* 154 */ CWORD_CWORD_CWORD_CWORD,
3009 /* 155 */ CWORD_CWORD_CWORD_CWORD,
3010 /* 156 */ CWORD_CWORD_CWORD_CWORD,
3011 /* 157 */ CWORD_CWORD_CWORD_CWORD,
3012 /* 158 */ CWORD_CWORD_CWORD_CWORD,
3013 /* 159 */ CWORD_CWORD_CWORD_CWORD,
3014 /* 160 */ CWORD_CWORD_CWORD_CWORD,
3015 /* 161 */ CWORD_CWORD_CWORD_CWORD,
3016 /* 162 */ CWORD_CWORD_CWORD_CWORD,
3017 /* 163 */ CWORD_CWORD_CWORD_CWORD,
3018 /* 164 */ CWORD_CWORD_CWORD_CWORD,
3019 /* 165 */ CWORD_CWORD_CWORD_CWORD,
3020 /* 166 */ CWORD_CWORD_CWORD_CWORD,
3021 /* 167 */ CWORD_CWORD_CWORD_CWORD,
3022 /* 168 */ CWORD_CWORD_CWORD_CWORD,
3023 /* 169 */ CWORD_CWORD_CWORD_CWORD,
3024 /* 170 */ CWORD_CWORD_CWORD_CWORD,
3025 /* 171 */ CWORD_CWORD_CWORD_CWORD,
3026 /* 172 */ CWORD_CWORD_CWORD_CWORD,
3027 /* 173 */ CWORD_CWORD_CWORD_CWORD,
3028 /* 174 */ CWORD_CWORD_CWORD_CWORD,
3029 /* 175 */ CWORD_CWORD_CWORD_CWORD,
3030 /* 176 */ CWORD_CWORD_CWORD_CWORD,
3031 /* 177 */ CWORD_CWORD_CWORD_CWORD,
3032 /* 178 */ CWORD_CWORD_CWORD_CWORD,
3033 /* 179 */ CWORD_CWORD_CWORD_CWORD,
3034 /* 180 */ CWORD_CWORD_CWORD_CWORD,
3035 /* 181 */ CWORD_CWORD_CWORD_CWORD,
3036 /* 182 */ CWORD_CWORD_CWORD_CWORD,
3037 /* 183 */ CWORD_CWORD_CWORD_CWORD,
3038 /* 184 */ CWORD_CWORD_CWORD_CWORD,
3039 /* 185 */ CWORD_CWORD_CWORD_CWORD,
3040 /* 186 */ CWORD_CWORD_CWORD_CWORD,
3041 /* 187 */ CWORD_CWORD_CWORD_CWORD,
3042 /* 188 */ CWORD_CWORD_CWORD_CWORD,
3043 /* 189 */ CWORD_CWORD_CWORD_CWORD,
3044 /* 190 */ CWORD_CWORD_CWORD_CWORD,
3045 /* 191 */ CWORD_CWORD_CWORD_CWORD,
3046 /* 192 */ CWORD_CWORD_CWORD_CWORD,
3047 /* 193 */ CWORD_CWORD_CWORD_CWORD,
3048 /* 194 */ CWORD_CWORD_CWORD_CWORD,
3049 /* 195 */ CWORD_CWORD_CWORD_CWORD,
3050 /* 196 */ CWORD_CWORD_CWORD_CWORD,
3051 /* 197 */ CWORD_CWORD_CWORD_CWORD,
3052 /* 198 */ CWORD_CWORD_CWORD_CWORD,
3053 /* 199 */ CWORD_CWORD_CWORD_CWORD,
3054 /* 200 */ CWORD_CWORD_CWORD_CWORD,
3055 /* 201 */ CWORD_CWORD_CWORD_CWORD,
3056 /* 202 */ CWORD_CWORD_CWORD_CWORD,
3057 /* 203 */ CWORD_CWORD_CWORD_CWORD,
3058 /* 204 */ CWORD_CWORD_CWORD_CWORD,
3059 /* 205 */ CWORD_CWORD_CWORD_CWORD,
3060 /* 206 */ CWORD_CWORD_CWORD_CWORD,
3061 /* 207 */ CWORD_CWORD_CWORD_CWORD,
3062 /* 208 */ CWORD_CWORD_CWORD_CWORD,
3063 /* 209 */ CWORD_CWORD_CWORD_CWORD,
3064 /* 210 */ CWORD_CWORD_CWORD_CWORD,
3065 /* 211 */ CWORD_CWORD_CWORD_CWORD,
3066 /* 212 */ CWORD_CWORD_CWORD_CWORD,
3067 /* 213 */ CWORD_CWORD_CWORD_CWORD,
3068 /* 214 */ CWORD_CWORD_CWORD_CWORD,
3069 /* 215 */ CWORD_CWORD_CWORD_CWORD,
3070 /* 216 */ CWORD_CWORD_CWORD_CWORD,
3071 /* 217 */ CWORD_CWORD_CWORD_CWORD,
3072 /* 218 */ CWORD_CWORD_CWORD_CWORD,
3073 /* 219 */ CWORD_CWORD_CWORD_CWORD,
3074 /* 220 */ CWORD_CWORD_CWORD_CWORD,
3075 /* 221 */ CWORD_CWORD_CWORD_CWORD,
3076 /* 222 */ CWORD_CWORD_CWORD_CWORD,
3077 /* 223 */ CWORD_CWORD_CWORD_CWORD,
3078 /* 224 */ CWORD_CWORD_CWORD_CWORD,
3079 /* 225 */ CWORD_CWORD_CWORD_CWORD,
3080 /* 226 */ CWORD_CWORD_CWORD_CWORD,
3081 /* 227 */ CWORD_CWORD_CWORD_CWORD,
3082 /* 228 */ CWORD_CWORD_CWORD_CWORD,
3083 /* 229 */ CWORD_CWORD_CWORD_CWORD,
3084 /* 230 */ CWORD_CWORD_CWORD_CWORD,
3085 /* 231 */ CWORD_CWORD_CWORD_CWORD,
3086 /* 232 */ CWORD_CWORD_CWORD_CWORD,
3087 /* 233 */ CWORD_CWORD_CWORD_CWORD,
3088 /* 234 */ CWORD_CWORD_CWORD_CWORD,
3089 /* 235 */ CWORD_CWORD_CWORD_CWORD,
3090 /* 236 */ CWORD_CWORD_CWORD_CWORD,
3091 /* 237 */ CWORD_CWORD_CWORD_CWORD,
3092 /* 238 */ CWORD_CWORD_CWORD_CWORD,
3093 /* 239 */ CWORD_CWORD_CWORD_CWORD,
3094 /* 230 */ CWORD_CWORD_CWORD_CWORD,
3095 /* 241 */ CWORD_CWORD_CWORD_CWORD,
3096 /* 242 */ CWORD_CWORD_CWORD_CWORD,
3097 /* 243 */ CWORD_CWORD_CWORD_CWORD,
3098 /* 244 */ CWORD_CWORD_CWORD_CWORD,
3099 /* 245 */ CWORD_CWORD_CWORD_CWORD,
3100 /* 246 */ CWORD_CWORD_CWORD_CWORD,
3101 /* 247 */ CWORD_CWORD_CWORD_CWORD,
3102 /* 248 */ CWORD_CWORD_CWORD_CWORD,
3103 /* 249 */ CWORD_CWORD_CWORD_CWORD,
3104 /* 250 */ CWORD_CWORD_CWORD_CWORD,
3105 /* 251 */ CWORD_CWORD_CWORD_CWORD,
3106 /* 252 */ CWORD_CWORD_CWORD_CWORD,
3107 /* 253 */ CWORD_CWORD_CWORD_CWORD,
3108 /* 254 */ CWORD_CWORD_CWORD_CWORD,
3109 /* 255 */ CWORD_CWORD_CWORD_CWORD,
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01003110 /* PEOF */ CENDFILE_CENDFILE_CENDFILE_CENDFILE,
Denys Vlasenkocd716832009-11-28 22:14:02 +01003111# if ENABLE_ASH_ALIAS
3112 /* PEOA */ CSPCL_CIGN_CIGN_CIGN,
3113# endif
Eric Andersen2870d962001-07-02 17:27:21 +00003114};
3115
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01003116# define SIT(c, syntax) ((S_I_T[syntax_index_table[c]] >> ((syntax)*4)) & 0xf)
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00003117
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01003118#endif /* !USE_SIT_FUNCTION */
Eric Andersenc470f442003-07-28 09:56:35 +00003119
Eric Andersen2870d962001-07-02 17:27:21 +00003120
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00003121/* ============ Alias handling */
Denis Vlasenkofc06f292007-02-23 21:09:35 +00003122
Denis Vlasenko131ae172007-02-18 13:00:19 +00003123#if ENABLE_ASH_ALIAS
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00003124
3125#define ALIASINUSE 1
3126#define ALIASDEAD 2
3127
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00003128struct alias {
3129 struct alias *next;
3130 char *name;
3131 char *val;
3132 int flag;
3133};
3134
Denis Vlasenko01631112007-12-16 17:20:38 +00003135
3136static struct alias **atab; // [ATABSIZE];
3137#define INIT_G_alias() do { \
3138 atab = xzalloc(ATABSIZE * sizeof(atab[0])); \
3139} while (0)
3140
Eric Andersen2870d962001-07-02 17:27:21 +00003141
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00003142static struct alias **
Denys Vlasenko37dc08b2016-10-02 04:38:07 +02003143__lookupalias(const char *name)
3144{
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00003145 unsigned int hashval;
3146 struct alias **app;
3147 const char *p;
3148 unsigned int ch;
3149
3150 p = name;
3151
3152 ch = (unsigned char)*p;
3153 hashval = ch << 4;
3154 while (ch) {
3155 hashval += ch;
3156 ch = (unsigned char)*++p;
3157 }
3158 app = &atab[hashval % ATABSIZE];
3159
3160 for (; *app; app = &(*app)->next) {
3161 if (strcmp(name, (*app)->name) == 0) {
3162 break;
3163 }
3164 }
3165
3166 return app;
3167}
3168
3169static struct alias *
3170lookupalias(const char *name, int check)
3171{
3172 struct alias *ap = *__lookupalias(name);
3173
3174 if (check && ap && (ap->flag & ALIASINUSE))
3175 return NULL;
3176 return ap;
3177}
3178
3179static struct alias *
3180freealias(struct alias *ap)
3181{
3182 struct alias *next;
3183
3184 if (ap->flag & ALIASINUSE) {
3185 ap->flag |= ALIASDEAD;
3186 return ap;
3187 }
3188
3189 next = ap->next;
3190 free(ap->name);
3191 free(ap->val);
3192 free(ap);
3193 return next;
3194}
Eric Andersencb57d552001-06-28 07:25:16 +00003195
Eric Andersenc470f442003-07-28 09:56:35 +00003196static void
3197setalias(const char *name, const char *val)
Eric Andersencb57d552001-06-28 07:25:16 +00003198{
3199 struct alias *ap, **app;
3200
3201 app = __lookupalias(name);
3202 ap = *app;
Denis Vlasenkob012b102007-02-19 22:43:01 +00003203 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +00003204 if (ap) {
3205 if (!(ap->flag & ALIASINUSE)) {
Denis Vlasenkob012b102007-02-19 22:43:01 +00003206 free(ap->val);
Eric Andersencb57d552001-06-28 07:25:16 +00003207 }
Denis Vlasenko0c032a42007-02-23 01:03:40 +00003208 ap->val = ckstrdup(val);
Eric Andersencb57d552001-06-28 07:25:16 +00003209 ap->flag &= ~ALIASDEAD;
3210 } else {
3211 /* not found */
Denis Vlasenko597906c2008-02-20 16:38:54 +00003212 ap = ckzalloc(sizeof(struct alias));
Denis Vlasenko0c032a42007-02-23 01:03:40 +00003213 ap->name = ckstrdup(name);
3214 ap->val = ckstrdup(val);
Denis Vlasenko597906c2008-02-20 16:38:54 +00003215 /*ap->flag = 0; - ckzalloc did it */
3216 /*ap->next = NULL;*/
Eric Andersencb57d552001-06-28 07:25:16 +00003217 *app = ap;
3218 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00003219 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +00003220}
3221
Eric Andersenc470f442003-07-28 09:56:35 +00003222static int
3223unalias(const char *name)
Eric Andersen2870d962001-07-02 17:27:21 +00003224{
Eric Andersencb57d552001-06-28 07:25:16 +00003225 struct alias **app;
3226
3227 app = __lookupalias(name);
3228
3229 if (*app) {
Denis Vlasenkob012b102007-02-19 22:43:01 +00003230 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +00003231 *app = freealias(*app);
Denis Vlasenkob012b102007-02-19 22:43:01 +00003232 INT_ON;
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003233 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003234 }
3235
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003236 return 1;
Eric Andersencb57d552001-06-28 07:25:16 +00003237}
3238
Eric Andersenc470f442003-07-28 09:56:35 +00003239static void
3240rmaliases(void)
Eric Andersen2870d962001-07-02 17:27:21 +00003241{
Eric Andersencb57d552001-06-28 07:25:16 +00003242 struct alias *ap, **app;
3243 int i;
3244
Denis Vlasenkob012b102007-02-19 22:43:01 +00003245 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +00003246 for (i = 0; i < ATABSIZE; i++) {
3247 app = &atab[i];
3248 for (ap = *app; ap; ap = *app) {
3249 *app = freealias(*app);
3250 if (ap == *app) {
3251 app = &ap->next;
3252 }
3253 }
3254 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00003255 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +00003256}
3257
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00003258static void
3259printalias(const struct alias *ap)
3260{
3261 out1fmt("%s=%s\n", ap->name, single_quote(ap->val));
3262}
3263
Eric Andersencb57d552001-06-28 07:25:16 +00003264/*
3265 * TODO - sort output
3266 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02003267static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003268aliascmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003269{
3270 char *n, *v;
3271 int ret = 0;
3272 struct alias *ap;
3273
Denis Vlasenko68404f12008-03-17 09:00:54 +00003274 if (!argv[1]) {
Eric Andersencb57d552001-06-28 07:25:16 +00003275 int i;
3276
Denis Vlasenko68404f12008-03-17 09:00:54 +00003277 for (i = 0; i < ATABSIZE; i++) {
Eric Andersencb57d552001-06-28 07:25:16 +00003278 for (ap = atab[i]; ap; ap = ap->next) {
3279 printalias(ap);
3280 }
Denis Vlasenko68404f12008-03-17 09:00:54 +00003281 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003282 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003283 }
3284 while ((n = *++argv) != NULL) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +00003285 v = strchr(n+1, '=');
3286 if (v == NULL) { /* n+1: funny ksh stuff */
3287 ap = *__lookupalias(n);
3288 if (ap == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00003289 fprintf(stderr, "%s: %s not found\n", "alias", n);
Eric Andersencb57d552001-06-28 07:25:16 +00003290 ret = 1;
3291 } else
3292 printalias(ap);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003293 } else {
Eric Andersencb57d552001-06-28 07:25:16 +00003294 *v++ = '\0';
3295 setalias(n, v);
3296 }
3297 }
3298
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003299 return ret;
Eric Andersencb57d552001-06-28 07:25:16 +00003300}
3301
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02003302static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003303unaliascmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +00003304{
3305 int i;
3306
3307 while ((i = nextopt("a")) != '\0') {
3308 if (i == 'a') {
3309 rmaliases();
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003310 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003311 }
3312 }
3313 for (i = 0; *argptr; argptr++) {
3314 if (unalias(*argptr)) {
Eric Andersenc470f442003-07-28 09:56:35 +00003315 fprintf(stderr, "%s: %s not found\n", "unalias", *argptr);
Eric Andersencb57d552001-06-28 07:25:16 +00003316 i = 1;
3317 }
3318 }
3319
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003320 return i;
Eric Andersencb57d552001-06-28 07:25:16 +00003321}
Denis Vlasenkofc06f292007-02-23 21:09:35 +00003322
Denis Vlasenko131ae172007-02-18 13:00:19 +00003323#endif /* ASH_ALIAS */
Eric Andersencb57d552001-06-28 07:25:16 +00003324
Eric Andersenc470f442003-07-28 09:56:35 +00003325
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003326/* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */
Denys Vlasenko285ad152009-12-04 23:02:27 +01003327#define FORK_FG 0
3328#define FORK_BG 1
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003329#define FORK_NOJOB 2
3330
3331/* mode flags for showjob(s) */
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02003332#define SHOW_ONLY_PGID 0x01 /* show only pgid (jobs -p) */
3333#define SHOW_PIDS 0x02 /* show individual pids, not just one line per job */
3334#define SHOW_CHANGED 0x04 /* only jobs whose state has changed */
Denys Vlasenko9c541002015-10-07 15:44:36 +02003335#define SHOW_STDERR 0x08 /* print to stderr (else stdout) */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003336
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003337/*
3338 * A job structure contains information about a job. A job is either a
3339 * single process or a set of processes contained in a pipeline. In the
3340 * latter case, pidlist will be non-NULL, and will point to a -1 terminated
3341 * array of pids.
3342 */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003343struct procstat {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003344 pid_t ps_pid; /* process id */
3345 int ps_status; /* last process status from wait() */
3346 char *ps_cmd; /* text of command being run */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003347};
3348
3349struct job {
3350 struct procstat ps0; /* status of process */
3351 struct procstat *ps; /* status or processes when more than one */
3352#if JOBS
3353 int stopstatus; /* status of a stopped job */
3354#endif
3355 uint32_t
3356 nprocs: 16, /* number of processes */
3357 state: 8,
3358#define JOBRUNNING 0 /* at least one proc running */
3359#define JOBSTOPPED 1 /* all procs are stopped */
3360#define JOBDONE 2 /* all procs are completed */
3361#if JOBS
3362 sigint: 1, /* job was killed by SIGINT */
3363 jobctl: 1, /* job running under job control */
3364#endif
3365 waited: 1, /* true if this entry has been waited for */
3366 used: 1, /* true if this entry is in used */
3367 changed: 1; /* true if status has changed */
3368 struct job *prev_job; /* previous job */
3369};
3370
Denis Vlasenko68404f12008-03-17 09:00:54 +00003371static struct job *makejob(/*union node *,*/ int);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003372static int forkshell(struct job *, union node *, int);
3373static int waitforjob(struct job *);
3374
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00003375#if !JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +00003376enum { doing_jobctl = 0 };
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00003377#define setjobctl(on) do {} while (0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003378#else
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003379static smallint doing_jobctl; //references:8
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003380static void setjobctl(int);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003381#endif
3382
3383/*
Denis Vlasenko4b875702009-03-19 13:30:04 +00003384 * Ignore a signal.
3385 */
3386static void
3387ignoresig(int signo)
3388{
3389 /* Avoid unnecessary system calls. Is it already SIG_IGNed? */
3390 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
3391 /* No, need to do it */
3392 signal(signo, SIG_IGN);
3393 }
3394 sigmode[signo - 1] = S_HARD_IGN;
3395}
3396
3397/*
Denys Vlasenko238bf182010-05-18 15:49:07 +02003398 * Only one usage site - in setsignal()
Denis Vlasenko4b875702009-03-19 13:30:04 +00003399 */
3400static void
Denys Vlasenko238bf182010-05-18 15:49:07 +02003401signal_handler(int signo)
Denis Vlasenko4b875702009-03-19 13:30:04 +00003402{
Denys Vlasenko458c1f22016-10-27 23:51:19 +02003403 if (signo == SIGCHLD) {
3404 got_sigchld = 1;
3405 if (!trap[SIGCHLD])
3406 return;
3407 }
3408
Denis Vlasenko4b875702009-03-19 13:30:04 +00003409 gotsig[signo - 1] = 1;
Denys Vlasenko458c1f22016-10-27 23:51:19 +02003410 pending_sig = signo;
Denis Vlasenko4b875702009-03-19 13:30:04 +00003411
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02003412 if (signo == SIGINT && !trap[SIGINT]) {
3413 if (!suppress_int) {
3414 pending_sig = 0;
Denis Vlasenko4b875702009-03-19 13:30:04 +00003415 raise_interrupt(); /* does not return */
3416 }
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02003417 pending_int = 1;
Denis Vlasenko4b875702009-03-19 13:30:04 +00003418 }
3419}
3420
3421/*
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003422 * Set the signal handler for the specified signal. The routine figures
3423 * out what it should be set to.
3424 */
3425static void
3426setsignal(int signo)
3427{
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003428 char *t;
3429 char cur_act, new_act;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003430 struct sigaction act;
3431
3432 t = trap[signo];
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003433 new_act = S_DFL;
3434 if (t != NULL) { /* trap for this sig is set */
3435 new_act = S_CATCH;
3436 if (t[0] == '\0') /* trap is "": ignore this sig */
3437 new_act = S_IGN;
3438 }
3439
3440 if (rootshell && new_act == S_DFL) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003441 switch (signo) {
3442 case SIGINT:
3443 if (iflag || minusc || sflag == 0)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003444 new_act = S_CATCH;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003445 break;
3446 case SIGQUIT:
3447#if DEBUG
3448 if (debug)
3449 break;
3450#endif
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003451 /* man bash:
3452 * "In all cases, bash ignores SIGQUIT. Non-builtin
3453 * commands run by bash have signal handlers
3454 * set to the values inherited by the shell
3455 * from its parent". */
3456 new_act = S_IGN;
3457 break;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003458 case SIGTERM:
3459 if (iflag)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003460 new_act = S_IGN;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003461 break;
3462#if JOBS
3463 case SIGTSTP:
3464 case SIGTTOU:
3465 if (mflag)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003466 new_act = S_IGN;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003467 break;
3468#endif
3469 }
3470 }
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003471//TODO: if !rootshell, we reset SIGQUIT to DFL,
3472//whereas we have to restore it to what shell got on entry
3473//from the parent. See comment above
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003474
Denys Vlasenko458c1f22016-10-27 23:51:19 +02003475 if (signo == SIGCHLD)
3476 new_act = S_CATCH;
3477
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003478 t = &sigmode[signo - 1];
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003479 cur_act = *t;
3480 if (cur_act == 0) {
3481 /* current setting is not yet known */
3482 if (sigaction(signo, NULL, &act)) {
3483 /* pretend it worked; maybe we should give a warning,
3484 * but other shells don't. We don't alter sigmode,
3485 * so we retry every time.
3486 * btw, in Linux it never fails. --vda */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003487 return;
3488 }
3489 if (act.sa_handler == SIG_IGN) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003490 cur_act = S_HARD_IGN;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003491 if (mflag
3492 && (signo == SIGTSTP || signo == SIGTTIN || signo == SIGTTOU)
3493 ) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003494 cur_act = S_IGN; /* don't hard ignore these */
Denis Vlasenko991a1da2008-02-10 19:02:53 +00003495 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003496 }
3497 }
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003498 if (cur_act == S_HARD_IGN || cur_act == new_act)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003499 return;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003500
Denis Vlasenko991a1da2008-02-10 19:02:53 +00003501 act.sa_handler = SIG_DFL;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003502 switch (new_act) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003503 case S_CATCH:
Denys Vlasenko238bf182010-05-18 15:49:07 +02003504 act.sa_handler = signal_handler;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003505 break;
3506 case S_IGN:
3507 act.sa_handler = SIG_IGN;
3508 break;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003509 }
Ian Wienand89b3cba2011-04-16 20:05:14 +02003510
3511 /* flags and mask matter only if !DFL and !IGN, but we do it
3512 * for all cases for more deterministic behavior:
3513 */
3514 act.sa_flags = 0;
3515 sigfillset(&act.sa_mask);
3516
Denis Vlasenko8e2cfec2008-03-12 23:19:35 +00003517 sigaction_set(signo, &act);
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003518
3519 *t = new_act;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003520}
3521
3522/* mode flags for set_curjob */
3523#define CUR_DELETE 2
3524#define CUR_RUNNING 1
3525#define CUR_STOPPED 0
3526
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003527#if JOBS
3528/* pgrp of shell on invocation */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003529static int initialpgrp; //references:2
3530static int ttyfd = -1; //5
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003531#endif
3532/* array of jobs */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003533static struct job *jobtab; //5
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003534/* size of array */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003535static unsigned njobs; //4
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003536/* current job */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003537static struct job *curjob; //lots
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003538/* number of presumed living untracked jobs */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003539static int jobless; //4
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003540
3541static void
3542set_curjob(struct job *jp, unsigned mode)
3543{
3544 struct job *jp1;
3545 struct job **jpp, **curp;
3546
3547 /* first remove from list */
3548 jpp = curp = &curjob;
Denys Vlasenko940c7202011-03-02 04:07:14 +01003549 while (1) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003550 jp1 = *jpp;
3551 if (jp1 == jp)
3552 break;
3553 jpp = &jp1->prev_job;
Denys Vlasenko940c7202011-03-02 04:07:14 +01003554 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003555 *jpp = jp1->prev_job;
3556
3557 /* Then re-insert in correct position */
3558 jpp = curp;
3559 switch (mode) {
3560 default:
3561#if DEBUG
3562 abort();
3563#endif
3564 case CUR_DELETE:
3565 /* job being deleted */
3566 break;
3567 case CUR_RUNNING:
3568 /* newly created job or backgrounded job,
Denys Vlasenko60cb48c2013-01-14 15:57:44 +01003569 * put after all stopped jobs.
3570 */
Denys Vlasenko940c7202011-03-02 04:07:14 +01003571 while (1) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003572 jp1 = *jpp;
3573#if JOBS
3574 if (!jp1 || jp1->state != JOBSTOPPED)
3575#endif
3576 break;
3577 jpp = &jp1->prev_job;
Denys Vlasenko940c7202011-03-02 04:07:14 +01003578 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003579 /* FALLTHROUGH */
3580#if JOBS
3581 case CUR_STOPPED:
3582#endif
3583 /* newly stopped job - becomes curjob */
3584 jp->prev_job = *jpp;
3585 *jpp = jp;
3586 break;
3587 }
3588}
3589
3590#if JOBS || DEBUG
3591static int
3592jobno(const struct job *jp)
3593{
3594 return jp - jobtab + 1;
3595}
3596#endif
3597
3598/*
3599 * Convert a job name to a job structure.
3600 */
Denis Vlasenko85c24712008-03-17 09:04:04 +00003601#if !JOBS
3602#define getjob(name, getctl) getjob(name)
3603#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003604static struct job *
3605getjob(const char *name, int getctl)
3606{
3607 struct job *jp;
3608 struct job *found;
Denys Vlasenkoffc39202009-08-17 02:12:20 +02003609 const char *err_msg = "%s: no such job";
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003610 unsigned num;
3611 int c;
3612 const char *p;
3613 char *(*match)(const char *, const char *);
3614
3615 jp = curjob;
3616 p = name;
3617 if (!p)
3618 goto currentjob;
3619
3620 if (*p != '%')
3621 goto err;
3622
3623 c = *++p;
3624 if (!c)
3625 goto currentjob;
3626
3627 if (!p[1]) {
3628 if (c == '+' || c == '%') {
3629 currentjob:
3630 err_msg = "No current job";
3631 goto check;
3632 }
3633 if (c == '-') {
3634 if (jp)
3635 jp = jp->prev_job;
3636 err_msg = "No previous job";
3637 check:
3638 if (!jp)
3639 goto err;
3640 goto gotit;
3641 }
3642 }
3643
3644 if (is_number(p)) {
3645 num = atoi(p);
Denys Vlasenko46a45ce2016-09-29 01:10:08 +02003646 if (num > 0 && num <= njobs) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003647 jp = jobtab + num - 1;
3648 if (jp->used)
3649 goto gotit;
3650 goto err;
3651 }
3652 }
3653
3654 match = prefix;
3655 if (*p == '?') {
3656 match = strstr;
3657 p++;
3658 }
3659
Denys Vlasenkoffc39202009-08-17 02:12:20 +02003660 found = NULL;
3661 while (jp) {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003662 if (match(jp->ps[0].ps_cmd, p)) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003663 if (found)
3664 goto err;
3665 found = jp;
3666 err_msg = "%s: ambiguous";
3667 }
3668 jp = jp->prev_job;
3669 }
Denys Vlasenkoffc39202009-08-17 02:12:20 +02003670 if (!found)
3671 goto err;
3672 jp = found;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003673
3674 gotit:
3675#if JOBS
3676 err_msg = "job %s not created under job control";
3677 if (getctl && jp->jobctl == 0)
3678 goto err;
3679#endif
3680 return jp;
3681 err:
3682 ash_msg_and_raise_error(err_msg, name);
3683}
3684
3685/*
3686 * Mark a job structure as unused.
3687 */
3688static void
3689freejob(struct job *jp)
3690{
3691 struct procstat *ps;
3692 int i;
3693
3694 INT_OFF;
3695 for (i = jp->nprocs, ps = jp->ps; --i >= 0; ps++) {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003696 if (ps->ps_cmd != nullstr)
3697 free(ps->ps_cmd);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003698 }
3699 if (jp->ps != &jp->ps0)
3700 free(jp->ps);
3701 jp->used = 0;
3702 set_curjob(jp, CUR_DELETE);
3703 INT_ON;
3704}
3705
3706#if JOBS
3707static void
3708xtcsetpgrp(int fd, pid_t pgrp)
3709{
3710 if (tcsetpgrp(fd, pgrp))
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +00003711 ash_msg_and_raise_error("can't set tty process group (%m)");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003712}
3713
3714/*
3715 * Turn job control on and off.
3716 *
3717 * Note: This code assumes that the third arg to ioctl is a character
3718 * pointer, which is true on Berkeley systems but not System V. Since
3719 * System V doesn't have job control yet, this isn't a problem now.
3720 *
3721 * Called with interrupts off.
3722 */
3723static void
3724setjobctl(int on)
3725{
3726 int fd;
3727 int pgrp;
3728
Denis Vlasenkob07a4962008-06-22 13:16:23 +00003729 if (on == doing_jobctl || rootshell == 0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003730 return;
3731 if (on) {
3732 int ofd;
3733 ofd = fd = open(_PATH_TTY, O_RDWR);
3734 if (fd < 0) {
3735 /* BTW, bash will try to open(ttyname(0)) if open("/dev/tty") fails.
3736 * That sometimes helps to acquire controlling tty.
3737 * Obviously, a workaround for bugs when someone
3738 * failed to provide a controlling tty to bash! :) */
Denis Vlasenkoed270a52007-11-26 05:37:07 +00003739 fd = 2;
3740 while (!isatty(fd))
3741 if (--fd < 0)
3742 goto out;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003743 }
Denys Vlasenko64774602016-10-26 15:24:30 +02003744 /* fd is a tty at this point */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003745 fd = fcntl(fd, F_DUPFD, 10);
Denys Vlasenko64774602016-10-26 15:24:30 +02003746 if (ofd >= 0) /* if it is "/dev/tty", close. If 0/1/2, dont */
Denis Vlasenkoed270a52007-11-26 05:37:07 +00003747 close(ofd);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003748 if (fd < 0)
Denys Vlasenko64774602016-10-26 15:24:30 +02003749 goto out; /* F_DUPFD failed */
Denis Vlasenko96e1b382007-09-30 23:50:48 +00003750 close_on_exec_on(fd);
Denys Vlasenko940c7202011-03-02 04:07:14 +01003751 while (1) { /* while we are in the background */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003752 pgrp = tcgetpgrp(fd);
3753 if (pgrp < 0) {
3754 out:
3755 ash_msg("can't access tty; job control turned off");
3756 mflag = on = 0;
3757 goto close;
3758 }
3759 if (pgrp == getpgrp())
3760 break;
3761 killpg(0, SIGTTIN);
Denys Vlasenko940c7202011-03-02 04:07:14 +01003762 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003763 initialpgrp = pgrp;
3764
3765 setsignal(SIGTSTP);
3766 setsignal(SIGTTOU);
3767 setsignal(SIGTTIN);
3768 pgrp = rootpid;
3769 setpgid(0, pgrp);
3770 xtcsetpgrp(fd, pgrp);
3771 } else {
3772 /* turning job control off */
3773 fd = ttyfd;
3774 pgrp = initialpgrp;
Denis Vlasenko08c8c1d2007-04-28 22:39:02 +00003775 /* was xtcsetpgrp, but this can make exiting ash
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00003776 * loop forever if pty is already deleted */
Denis Vlasenko08c8c1d2007-04-28 22:39:02 +00003777 tcsetpgrp(fd, pgrp);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003778 setpgid(0, pgrp);
3779 setsignal(SIGTSTP);
3780 setsignal(SIGTTOU);
3781 setsignal(SIGTTIN);
3782 close:
Denis Vlasenkoed270a52007-11-26 05:37:07 +00003783 if (fd >= 0)
3784 close(fd);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003785 fd = -1;
3786 }
3787 ttyfd = fd;
Denis Vlasenkob07a4962008-06-22 13:16:23 +00003788 doing_jobctl = on;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003789}
3790
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02003791static int FAST_FUNC
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003792killcmd(int argc, char **argv)
3793{
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003794 if (argv[1] && strcmp(argv[1], "-l") != 0) {
Denys Vlasenkob12553f2011-02-21 03:22:20 +01003795 int i = 1;
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003796 do {
3797 if (argv[i][0] == '%') {
Denys Vlasenkob12553f2011-02-21 03:22:20 +01003798 /*
3799 * "kill %N" - job kill
3800 * Converting to pgrp / pid kill
3801 */
3802 struct job *jp;
3803 char *dst;
3804 int j, n;
3805
3806 jp = getjob(argv[i], 0);
3807 /*
3808 * In jobs started under job control, we signal
3809 * entire process group by kill -PGRP_ID.
3810 * This happens, f.e., in interactive shell.
3811 *
3812 * Otherwise, we signal each child via
3813 * kill PID1 PID2 PID3.
3814 * Testcases:
3815 * sh -c 'sleep 1|sleep 1 & kill %1'
3816 * sh -c 'true|sleep 2 & sleep 1; kill %1'
3817 * sh -c 'true|sleep 1 & sleep 2; kill %1'
3818 */
3819 n = jp->nprocs; /* can't be 0 (I hope) */
3820 if (jp->jobctl)
3821 n = 1;
3822 dst = alloca(n * sizeof(int)*4);
3823 argv[i] = dst;
3824 for (j = 0; j < n; j++) {
3825 struct procstat *ps = &jp->ps[j];
3826 /* Skip non-running and not-stopped members
3827 * (i.e. dead members) of the job
3828 */
3829 if (ps->ps_status != -1 && !WIFSTOPPED(ps->ps_status))
3830 continue;
3831 /*
3832 * kill_main has matching code to expect
3833 * leading space. Needed to not confuse
3834 * negative pids with "kill -SIGNAL_NO" syntax
3835 */
3836 dst += sprintf(dst, jp->jobctl ? " -%u" : " %u", (int)ps->ps_pid);
3837 }
3838 *dst = '\0';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003839 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003840 } while (argv[++i]);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003841 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003842 return kill_main(argc, argv);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003843}
3844
3845static void
Denys Vlasenko285ad152009-12-04 23:02:27 +01003846showpipe(struct job *jp /*, FILE *out*/)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003847{
Denys Vlasenko285ad152009-12-04 23:02:27 +01003848 struct procstat *ps;
3849 struct procstat *psend;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003850
Denys Vlasenko285ad152009-12-04 23:02:27 +01003851 psend = jp->ps + jp->nprocs;
3852 for (ps = jp->ps + 1; ps < psend; ps++)
3853 printf(" | %s", ps->ps_cmd);
Denys Vlasenko9c541002015-10-07 15:44:36 +02003854 newline_and_flush(stdout);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003855 flush_stdout_stderr();
3856}
3857
3858
3859static int
3860restartjob(struct job *jp, int mode)
3861{
3862 struct procstat *ps;
3863 int i;
3864 int status;
3865 pid_t pgid;
3866
3867 INT_OFF;
3868 if (jp->state == JOBDONE)
3869 goto out;
3870 jp->state = JOBRUNNING;
Denys Vlasenko285ad152009-12-04 23:02:27 +01003871 pgid = jp->ps[0].ps_pid;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003872 if (mode == FORK_FG)
3873 xtcsetpgrp(ttyfd, pgid);
3874 killpg(pgid, SIGCONT);
3875 ps = jp->ps;
3876 i = jp->nprocs;
3877 do {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003878 if (WIFSTOPPED(ps->ps_status)) {
3879 ps->ps_status = -1;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003880 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003881 ps++;
3882 } while (--i);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003883 out:
3884 status = (mode == FORK_FG) ? waitforjob(jp) : 0;
3885 INT_ON;
3886 return status;
3887}
3888
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02003889static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003890fg_bgcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003891{
3892 struct job *jp;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003893 int mode;
3894 int retval;
3895
3896 mode = (**argv == 'f') ? FORK_FG : FORK_BG;
3897 nextopt(nullstr);
3898 argv = argptr;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003899 do {
3900 jp = getjob(*argv, 1);
3901 if (mode == FORK_BG) {
3902 set_curjob(jp, CUR_RUNNING);
Denys Vlasenko285ad152009-12-04 23:02:27 +01003903 printf("[%d] ", jobno(jp));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003904 }
Denys Vlasenko285ad152009-12-04 23:02:27 +01003905 out1str(jp->ps[0].ps_cmd);
3906 showpipe(jp /*, stdout*/);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003907 retval = restartjob(jp, mode);
3908 } while (*argv && *++argv);
3909 return retval;
3910}
3911#endif
3912
3913static int
Denys Vlasenko9c541002015-10-07 15:44:36 +02003914sprint_status48(char *s, int status, int sigonly)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003915{
3916 int col;
3917 int st;
3918
3919 col = 0;
3920 if (!WIFEXITED(status)) {
Denys Vlasenko4700fb52015-10-09 15:40:13 +02003921 if (JOBS && WIFSTOPPED(status))
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003922 st = WSTOPSIG(status);
3923 else
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003924 st = WTERMSIG(status);
3925 if (sigonly) {
3926 if (st == SIGINT || st == SIGPIPE)
3927 goto out;
Denys Vlasenko4700fb52015-10-09 15:40:13 +02003928 if (JOBS && WIFSTOPPED(status))
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003929 goto out;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003930 }
3931 st &= 0x7f;
Denys Vlasenko7c6f2462011-02-14 17:17:10 +01003932//TODO: use bbox's get_signame? strsignal adds ~600 bytes to text+rodata
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003933 col = fmtstr(s, 32, strsignal(st));
3934 if (WCOREDUMP(status)) {
Denys Vlasenko9c541002015-10-07 15:44:36 +02003935 strcpy(s + col, " (core dumped)");
3936 col += sizeof(" (core dumped)")-1;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003937 }
3938 } else if (!sigonly) {
3939 st = WEXITSTATUS(status);
Denys Vlasenko9c541002015-10-07 15:44:36 +02003940 col = fmtstr(s, 16, (st ? "Done(%d)" : "Done"), st);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003941 }
3942 out:
3943 return col;
3944}
3945
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003946static int
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02003947wait_block_or_sig(int *status)
Denys Vlasenko458c1f22016-10-27 23:51:19 +02003948{
Denys Vlasenko458c1f22016-10-27 23:51:19 +02003949 int pid;
3950
3951 do {
Denys Vlasenko1ab7c2f2016-11-03 20:17:23 +01003952 sigset_t mask;
3953
Denys Vlasenko458c1f22016-10-27 23:51:19 +02003954 /* Poll all children for changes in their state */
3955 got_sigchld = 0;
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02003956 /* if job control is active, accept stopped processes too */
3957 pid = waitpid(-1, status, doing_jobctl ? (WNOHANG|WUNTRACED) : WNOHANG);
Denys Vlasenko458c1f22016-10-27 23:51:19 +02003958 if (pid != 0)
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02003959 break; /* Error (e.g. EINTR, ECHILD) or pid */
Denys Vlasenko458c1f22016-10-27 23:51:19 +02003960
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02003961 /* Children exist, but none are ready. Sleep until interesting signal */
Denys Vlasenko1ab7c2f2016-11-03 20:17:23 +01003962#if 1
Denys Vlasenko458c1f22016-10-27 23:51:19 +02003963 sigfillset(&mask);
3964 sigprocmask(SIG_SETMASK, &mask, &mask);
3965 while (!got_sigchld && !pending_sig)
3966 sigsuspend(&mask);
3967 sigprocmask(SIG_SETMASK, &mask, NULL);
Denys Vlasenko1ab7c2f2016-11-03 20:17:23 +01003968#else /* unsafe: a signal can set pending_sig after check, but before pause() */
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02003969 while (!got_sigchld && !pending_sig)
3970 pause();
3971#endif
Denys Vlasenko458c1f22016-10-27 23:51:19 +02003972
3973 /* If it was SIGCHLD, poll children again */
3974 } while (got_sigchld);
3975
3976 return pid;
3977}
3978
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02003979#define DOWAIT_NONBLOCK 0
3980#define DOWAIT_BLOCK 1
3981#define DOWAIT_BLOCK_OR_SIG 2
Denys Vlasenko458c1f22016-10-27 23:51:19 +02003982
3983static int
Denys Vlasenkob543bda2016-10-27 20:08:28 +02003984dowait(int block, struct job *job)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003985{
3986 int pid;
3987 int status;
3988 struct job *jp;
Denys Vlasenko458c1f22016-10-27 23:51:19 +02003989 struct job *thisjob = NULL;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003990
Denys Vlasenkob543bda2016-10-27 20:08:28 +02003991 TRACE(("dowait(0x%x) called\n", block));
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +00003992
Denys Vlasenko458c1f22016-10-27 23:51:19 +02003993 /* It's wrong to call waitpid() outside of INT_OFF region:
3994 * signal can arrive just after syscall return and handler can
3995 * longjmp away, losing stop/exit notification processing.
3996 * Thus, for "jobs" builtin, and for waiting for a fg job,
3997 * we call waitpid() (blocking or non-blocking) inside INT_OFF.
3998 *
3999 * However, for "wait" builtin it is wrong to simply call waitpid()
4000 * in INT_OFF region: "wait" needs to wait for any running job
4001 * to change state, but should exit on any trap too.
4002 * In INT_OFF region, a signal just before syscall entry can set
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004003 * pending_sig variables, but we can't check them, and we would
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004004 * either enter a sleeping waitpid() (BUG), or need to busy-loop.
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004005 *
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004006 * Because of this, we run inside INT_OFF, but use a special routine
Denys Vlasenko1ab7c2f2016-11-03 20:17:23 +01004007 * which combines waitpid() and sigsuspend().
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004008 * This is the reason why we need to have a handler for SIGCHLD:
Denys Vlasenko1ab7c2f2016-11-03 20:17:23 +01004009 * SIG_DFL handler does not wake sigsuspend().
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004010 */
4011 INT_OFF;
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004012 if (block == DOWAIT_BLOCK_OR_SIG) {
4013 pid = wait_block_or_sig(&status);
4014 } else {
4015 int wait_flags = 0;
4016 if (block == DOWAIT_NONBLOCK)
4017 wait_flags = WNOHANG;
4018 /* if job control is active, accept stopped processes too */
4019 if (doing_jobctl)
4020 wait_flags |= WUNTRACED;
4021 /* NB: _not_ safe_waitpid, we need to detect EINTR */
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004022 pid = waitpid(-1, &status, wait_flags);
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004023 }
Denis Vlasenkob21f3792009-03-19 23:09:58 +00004024 TRACE(("wait returns pid=%d, status=0x%x, errno=%d(%s)\n",
4025 pid, status, errno, strerror(errno)));
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004026 if (pid <= 0)
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004027 goto out;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004028
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004029 thisjob = NULL;
4030 for (jp = curjob; jp; jp = jp->prev_job) {
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004031 int jobstate;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004032 struct procstat *ps;
4033 struct procstat *psend;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004034 if (jp->state == JOBDONE)
4035 continue;
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004036 jobstate = JOBDONE;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004037 ps = jp->ps;
4038 psend = ps + jp->nprocs;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004039 do {
Denys Vlasenko285ad152009-12-04 23:02:27 +01004040 if (ps->ps_pid == pid) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004041 TRACE(("Job %d: changing status of proc %d "
4042 "from 0x%x to 0x%x\n",
Denys Vlasenko285ad152009-12-04 23:02:27 +01004043 jobno(jp), pid, ps->ps_status, status));
4044 ps->ps_status = status;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004045 thisjob = jp;
4046 }
Denys Vlasenko285ad152009-12-04 23:02:27 +01004047 if (ps->ps_status == -1)
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004048 jobstate = JOBRUNNING;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004049#if JOBS
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004050 if (jobstate == JOBRUNNING)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004051 continue;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004052 if (WIFSTOPPED(ps->ps_status)) {
4053 jp->stopstatus = ps->ps_status;
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004054 jobstate = JOBSTOPPED;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004055 }
4056#endif
Denys Vlasenko285ad152009-12-04 23:02:27 +01004057 } while (++ps < psend);
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004058 if (!thisjob)
4059 continue;
4060
4061 /* Found the job where one of its processes changed its state.
4062 * Is there at least one live and running process in this job? */
4063 if (jobstate != JOBRUNNING) {
4064 /* No. All live processes in the job are stopped
4065 * (JOBSTOPPED) or there are no live processes (JOBDONE)
4066 */
4067 thisjob->changed = 1;
4068 if (thisjob->state != jobstate) {
4069 TRACE(("Job %d: changing state from %d to %d\n",
4070 jobno(thisjob), thisjob->state, jobstate));
4071 thisjob->state = jobstate;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004072#if JOBS
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004073 if (jobstate == JOBSTOPPED)
4074 set_curjob(thisjob, CUR_STOPPED);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004075#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004076 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004077 }
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004078 goto out;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004079 }
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004080 /* The process wasn't found in job list */
4081 if (JOBS && !WIFSTOPPED(status))
4082 jobless--;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004083 out:
4084 INT_ON;
4085
4086 if (thisjob && thisjob == job) {
4087 char s[48 + 1];
4088 int len;
4089
Denys Vlasenko9c541002015-10-07 15:44:36 +02004090 len = sprint_status48(s, status, 1);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004091 if (len) {
4092 s[len] = '\n';
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004093 s[len + 1] = '\0';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004094 out2str(s);
4095 }
4096 }
4097 return pid;
4098}
4099
4100#if JOBS
4101static void
Denys Vlasenko9c541002015-10-07 15:44:36 +02004102showjob(struct job *jp, int mode)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004103{
4104 struct procstat *ps;
4105 struct procstat *psend;
4106 int col;
Denis Vlasenko40ba9982007-07-14 00:48:29 +00004107 int indent_col;
Denys Vlasenko9c541002015-10-07 15:44:36 +02004108 char s[16 + 16 + 48];
4109 FILE *out = (mode & SHOW_STDERR ? stderr : stdout);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004110
4111 ps = jp->ps;
4112
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004113 if (mode & SHOW_ONLY_PGID) { /* jobs -p */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004114 /* just output process (group) id of pipeline */
Denys Vlasenko285ad152009-12-04 23:02:27 +01004115 fprintf(out, "%d\n", ps->ps_pid);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004116 return;
4117 }
4118
4119 col = fmtstr(s, 16, "[%d] ", jobno(jp));
Denis Vlasenko40ba9982007-07-14 00:48:29 +00004120 indent_col = col;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004121
4122 if (jp == curjob)
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004123 s[col - 3] = '+';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004124 else if (curjob && jp == curjob->prev_job)
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004125 s[col - 3] = '-';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004126
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004127 if (mode & SHOW_PIDS)
Denys Vlasenko285ad152009-12-04 23:02:27 +01004128 col += fmtstr(s + col, 16, "%d ", ps->ps_pid);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004129
4130 psend = ps + jp->nprocs;
4131
4132 if (jp->state == JOBRUNNING) {
4133 strcpy(s + col, "Running");
4134 col += sizeof("Running") - 1;
4135 } else {
Denys Vlasenko285ad152009-12-04 23:02:27 +01004136 int status = psend[-1].ps_status;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004137 if (jp->state == JOBSTOPPED)
4138 status = jp->stopstatus;
Denys Vlasenko9c541002015-10-07 15:44:36 +02004139 col += sprint_status48(s + col, status, 0);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004140 }
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004141 /* By now, "[JOBID]* [maybe PID] STATUS" is printed */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004142
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004143 /* This loop either prints "<cmd1> | <cmd2> | <cmd3>" line
4144 * or prints several "PID | <cmdN>" lines,
4145 * depending on SHOW_PIDS bit.
4146 * We do not print status of individual processes
4147 * between PID and <cmdN>. bash does it, but not very well:
4148 * first line shows overall job status, not process status,
4149 * making it impossible to know 1st process status.
4150 */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004151 goto start;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004152 do {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004153 /* for each process */
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004154 s[0] = '\0';
4155 col = 33;
4156 if (mode & SHOW_PIDS)
Denys Vlasenko285ad152009-12-04 23:02:27 +01004157 col = fmtstr(s, 48, "\n%*c%d ", indent_col, ' ', ps->ps_pid) - 1;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004158 start:
Denys Vlasenko285ad152009-12-04 23:02:27 +01004159 fprintf(out, "%s%*c%s%s",
4160 s,
4161 33 - col >= 0 ? 33 - col : 0, ' ',
4162 ps == jp->ps ? "" : "| ",
4163 ps->ps_cmd
4164 );
4165 } while (++ps != psend);
Denys Vlasenko9c541002015-10-07 15:44:36 +02004166 newline_and_flush(out);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004167
4168 jp->changed = 0;
4169
4170 if (jp->state == JOBDONE) {
4171 TRACE(("showjob: freeing job %d\n", jobno(jp)));
4172 freejob(jp);
4173 }
4174}
4175
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004176/*
4177 * Print a list of jobs. If "change" is nonzero, only print jobs whose
4178 * statuses have changed since the last call to showjobs.
4179 */
4180static void
Denys Vlasenko9c541002015-10-07 15:44:36 +02004181showjobs(int mode)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004182{
4183 struct job *jp;
4184
Denys Vlasenko883cea42009-07-11 15:31:59 +02004185 TRACE(("showjobs(0x%x) called\n", mode));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004186
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004187 /* Handle all finished jobs */
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004188 while (dowait(DOWAIT_NONBLOCK, NULL) > 0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004189 continue;
4190
4191 for (jp = curjob; jp; jp = jp->prev_job) {
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004192 if (!(mode & SHOW_CHANGED) || jp->changed) {
Denys Vlasenko9c541002015-10-07 15:44:36 +02004193 showjob(jp, mode);
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004194 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004195 }
4196}
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004197
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02004198static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00004199jobscmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004200{
4201 int mode, m;
4202
4203 mode = 0;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02004204 while ((m = nextopt("lp")) != '\0') {
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004205 if (m == 'l')
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004206 mode |= SHOW_PIDS;
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004207 else
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004208 mode |= SHOW_ONLY_PGID;
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004209 }
4210
4211 argv = argptr;
4212 if (*argv) {
4213 do
Denys Vlasenko9c541002015-10-07 15:44:36 +02004214 showjob(getjob(*argv, 0), mode);
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004215 while (*++argv);
Denys Vlasenko285ad152009-12-04 23:02:27 +01004216 } else {
Denys Vlasenko9c541002015-10-07 15:44:36 +02004217 showjobs(mode);
Denys Vlasenko285ad152009-12-04 23:02:27 +01004218 }
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004219
4220 return 0;
4221}
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004222#endif /* JOBS */
4223
Michael Abbott359da5e2009-12-04 23:03:29 +01004224/* Called only on finished or stopped jobs (no members are running) */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004225static int
4226getstatus(struct job *job)
4227{
4228 int status;
4229 int retval;
Michael Abbott359da5e2009-12-04 23:03:29 +01004230 struct procstat *ps;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004231
Michael Abbott359da5e2009-12-04 23:03:29 +01004232 /* Fetch last member's status */
4233 ps = job->ps + job->nprocs - 1;
4234 status = ps->ps_status;
4235 if (pipefail) {
4236 /* "set -o pipefail" mode: use last _nonzero_ status */
4237 while (status == 0 && --ps >= job->ps)
4238 status = ps->ps_status;
4239 }
4240
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004241 retval = WEXITSTATUS(status);
4242 if (!WIFEXITED(status)) {
4243#if JOBS
4244 retval = WSTOPSIG(status);
4245 if (!WIFSTOPPED(status))
4246#endif
4247 {
4248 /* XXX: limits number of signals */
4249 retval = WTERMSIG(status);
4250#if JOBS
4251 if (retval == SIGINT)
4252 job->sigint = 1;
4253#endif
4254 }
4255 retval += 128;
4256 }
Denys Vlasenko883cea42009-07-11 15:31:59 +02004257 TRACE(("getstatus: job %d, nproc %d, status 0x%x, retval 0x%x\n",
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004258 jobno(job), job->nprocs, status, retval));
4259 return retval;
4260}
4261
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02004262static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00004263waitcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004264{
4265 struct job *job;
4266 int retval;
4267 struct job *jp;
4268
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004269 nextopt(nullstr);
4270 retval = 0;
4271
4272 argv = argptr;
4273 if (!*argv) {
4274 /* wait for all jobs */
4275 for (;;) {
4276 jp = curjob;
4277 while (1) {
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004278 if (!jp) /* no running procs */
4279 goto ret;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004280 if (jp->state == JOBRUNNING)
4281 break;
4282 jp->waited = 1;
4283 jp = jp->prev_job;
4284 }
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004285 /* man bash:
4286 * "When bash is waiting for an asynchronous command via
4287 * the wait builtin, the reception of a signal for which a trap
4288 * has been set will cause the wait builtin to return immediately
4289 * with an exit status greater than 128, immediately after which
4290 * the trap is executed."
Denys Vlasenko69188112016-10-27 20:18:18 +02004291 */
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004292 dowait(DOWAIT_BLOCK_OR_SIG, NULL);
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02004293 /* if child sends us a signal *and immediately exits*,
4294 * dowait() returns pid > 0. Check this case,
4295 * not "if (dowait() < 0)"!
4296 */
Denys Vlasenko7c1ed9f2010-05-17 04:42:40 +02004297 if (pending_sig)
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02004298 goto sigout;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004299 }
4300 }
4301
4302 retval = 127;
4303 do {
4304 if (**argv != '%') {
4305 pid_t pid = number(*argv);
4306 job = curjob;
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004307 while (1) {
4308 if (!job)
4309 goto repeat;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004310 if (job->ps[job->nprocs - 1].ps_pid == pid)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004311 break;
4312 job = job->prev_job;
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004313 }
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004314 } else {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004315 job = getjob(*argv, 0);
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004316 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004317 /* loop until process terminated or stopped */
Denys Vlasenko69188112016-10-27 20:18:18 +02004318 while (job->state == JOBRUNNING) {
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004319 dowait(DOWAIT_BLOCK_OR_SIG, NULL);
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02004320 if (pending_sig)
4321 goto sigout;
Denys Vlasenko69188112016-10-27 20:18:18 +02004322 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004323 job->waited = 1;
4324 retval = getstatus(job);
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004325 repeat: ;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004326 } while (*++argv);
4327
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004328 ret:
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004329 return retval;
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02004330 sigout:
4331 retval = 128 + pending_sig;
4332 return retval;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004333}
4334
4335static struct job *
4336growjobtab(void)
4337{
4338 size_t len;
4339 ptrdiff_t offset;
4340 struct job *jp, *jq;
4341
4342 len = njobs * sizeof(*jp);
4343 jq = jobtab;
4344 jp = ckrealloc(jq, len + 4 * sizeof(*jp));
4345
4346 offset = (char *)jp - (char *)jq;
4347 if (offset) {
4348 /* Relocate pointers */
4349 size_t l = len;
4350
4351 jq = (struct job *)((char *)jq + l);
4352 while (l) {
4353 l -= sizeof(*jp);
4354 jq--;
4355#define joff(p) ((struct job *)((char *)(p) + l))
4356#define jmove(p) (p) = (void *)((char *)(p) + offset)
4357 if (joff(jp)->ps == &jq->ps0)
4358 jmove(joff(jp)->ps);
4359 if (joff(jp)->prev_job)
4360 jmove(joff(jp)->prev_job);
4361 }
4362 if (curjob)
4363 jmove(curjob);
4364#undef joff
4365#undef jmove
4366 }
4367
4368 njobs += 4;
4369 jobtab = jp;
4370 jp = (struct job *)((char *)jp + len);
4371 jq = jp + 3;
4372 do {
4373 jq->used = 0;
4374 } while (--jq >= jp);
4375 return jp;
4376}
4377
4378/*
4379 * Return a new job structure.
4380 * Called with interrupts off.
4381 */
4382static struct job *
Denis Vlasenko68404f12008-03-17 09:00:54 +00004383makejob(/*union node *node,*/ int nprocs)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004384{
4385 int i;
4386 struct job *jp;
4387
4388 for (i = njobs, jp = jobtab; ; jp++) {
4389 if (--i < 0) {
4390 jp = growjobtab();
4391 break;
4392 }
4393 if (jp->used == 0)
4394 break;
4395 if (jp->state != JOBDONE || !jp->waited)
4396 continue;
4397#if JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +00004398 if (doing_jobctl)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004399 continue;
4400#endif
4401 freejob(jp);
4402 break;
4403 }
4404 memset(jp, 0, sizeof(*jp));
4405#if JOBS
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004406 /* jp->jobctl is a bitfield.
4407 * "jp->jobctl |= jobctl" likely to give awful code */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00004408 if (doing_jobctl)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004409 jp->jobctl = 1;
4410#endif
4411 jp->prev_job = curjob;
4412 curjob = jp;
4413 jp->used = 1;
4414 jp->ps = &jp->ps0;
4415 if (nprocs > 1) {
4416 jp->ps = ckmalloc(nprocs * sizeof(struct procstat));
4417 }
Denis Vlasenko68404f12008-03-17 09:00:54 +00004418 TRACE(("makejob(%d) returns %%%d\n", nprocs,
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004419 jobno(jp)));
4420 return jp;
4421}
4422
4423#if JOBS
4424/*
4425 * Return a string identifying a command (to be printed by the
4426 * jobs command).
4427 */
4428static char *cmdnextc;
4429
4430static void
4431cmdputs(const char *s)
4432{
Denis Vlasenko92e13c22008-03-25 01:17:40 +00004433 static const char vstype[VSTYPE + 1][3] = {
4434 "", "}", "-", "+", "?", "=",
4435 "%", "%%", "#", "##"
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00004436 IF_ASH_BASH_COMPAT(, ":", "/", "//")
Denis Vlasenko92e13c22008-03-25 01:17:40 +00004437 };
4438
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004439 const char *p, *str;
Denys Vlasenko46a14772009-12-10 21:27:13 +01004440 char cc[2];
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004441 char *nextc;
Denys Vlasenkocd716832009-11-28 22:14:02 +01004442 unsigned char c;
4443 unsigned char subtype = 0;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004444 int quoted = 0;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004445
Denys Vlasenko46a14772009-12-10 21:27:13 +01004446 cc[1] = '\0';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004447 nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
4448 p = s;
Denys Vlasenko46a14772009-12-10 21:27:13 +01004449 while ((c = *p++) != '\0') {
Denis Vlasenkoef527f52008-06-23 01:52:30 +00004450 str = NULL;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004451 switch (c) {
4452 case CTLESC:
4453 c = *p++;
4454 break;
4455 case CTLVAR:
4456 subtype = *p++;
4457 if ((subtype & VSTYPE) == VSLENGTH)
4458 str = "${#";
4459 else
4460 str = "${";
Ron Yorston549deab2015-05-18 09:57:51 +02004461 goto dostr;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004462 case CTLENDVAR:
4463 str = "\"}" + !(quoted & 1);
4464 quoted >>= 1;
4465 subtype = 0;
4466 goto dostr;
4467 case CTLBACKQ:
4468 str = "$(...)";
4469 goto dostr;
Mike Frysinger98c52642009-04-02 10:02:37 +00004470#if ENABLE_SH_MATH_SUPPORT
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004471 case CTLARI:
4472 str = "$((";
4473 goto dostr;
4474 case CTLENDARI:
4475 str = "))";
4476 goto dostr;
4477#endif
4478 case CTLQUOTEMARK:
4479 quoted ^= 1;
4480 c = '"';
4481 break;
4482 case '=':
4483 if (subtype == 0)
4484 break;
4485 if ((subtype & VSTYPE) != VSNORMAL)
4486 quoted <<= 1;
4487 str = vstype[subtype & VSTYPE];
4488 if (subtype & VSNUL)
4489 c = ':';
4490 else
4491 goto checkstr;
4492 break;
4493 case '\'':
4494 case '\\':
4495 case '"':
4496 case '$':
4497 /* These can only happen inside quotes */
4498 cc[0] = c;
4499 str = cc;
4500 c = '\\';
4501 break;
4502 default:
4503 break;
4504 }
4505 USTPUTC(c, nextc);
4506 checkstr:
4507 if (!str)
4508 continue;
4509 dostr:
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02004510 while ((c = *str++) != '\0') {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004511 USTPUTC(c, nextc);
4512 }
Denys Vlasenko46a14772009-12-10 21:27:13 +01004513 } /* while *p++ not NUL */
4514
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004515 if (quoted & 1) {
4516 USTPUTC('"', nextc);
4517 }
4518 *nextc = 0;
4519 cmdnextc = nextc;
4520}
4521
4522/* cmdtxt() and cmdlist() call each other */
4523static void cmdtxt(union node *n);
4524
4525static void
4526cmdlist(union node *np, int sep)
4527{
4528 for (; np; np = np->narg.next) {
4529 if (!sep)
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00004530 cmdputs(" ");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004531 cmdtxt(np);
4532 if (sep && np->narg.next)
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00004533 cmdputs(" ");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004534 }
4535}
4536
4537static void
4538cmdtxt(union node *n)
4539{
4540 union node *np;
4541 struct nodelist *lp;
4542 const char *p;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004543
4544 if (!n)
4545 return;
4546 switch (n->type) {
4547 default:
4548#if DEBUG
4549 abort();
4550#endif
4551 case NPIPE:
4552 lp = n->npipe.cmdlist;
4553 for (;;) {
4554 cmdtxt(lp->n);
4555 lp = lp->next;
4556 if (!lp)
4557 break;
4558 cmdputs(" | ");
4559 }
4560 break;
4561 case NSEMI:
4562 p = "; ";
4563 goto binop;
4564 case NAND:
4565 p = " && ";
4566 goto binop;
4567 case NOR:
4568 p = " || ";
4569 binop:
4570 cmdtxt(n->nbinary.ch1);
4571 cmdputs(p);
4572 n = n->nbinary.ch2;
4573 goto donode;
4574 case NREDIR:
4575 case NBACKGND:
4576 n = n->nredir.n;
4577 goto donode;
4578 case NNOT:
4579 cmdputs("!");
4580 n = n->nnot.com;
4581 donode:
4582 cmdtxt(n);
4583 break;
4584 case NIF:
4585 cmdputs("if ");
4586 cmdtxt(n->nif.test);
4587 cmdputs("; then ");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004588 if (n->nif.elsepart) {
Denys Vlasenko7cee00e2009-07-24 01:08:03 +02004589 cmdtxt(n->nif.ifpart);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004590 cmdputs("; else ");
4591 n = n->nif.elsepart;
Denys Vlasenko7cee00e2009-07-24 01:08:03 +02004592 } else {
4593 n = n->nif.ifpart;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004594 }
4595 p = "; fi";
4596 goto dotail;
4597 case NSUBSHELL:
4598 cmdputs("(");
4599 n = n->nredir.n;
4600 p = ")";
4601 goto dotail;
4602 case NWHILE:
4603 p = "while ";
4604 goto until;
4605 case NUNTIL:
4606 p = "until ";
4607 until:
4608 cmdputs(p);
4609 cmdtxt(n->nbinary.ch1);
4610 n = n->nbinary.ch2;
4611 p = "; done";
4612 dodo:
4613 cmdputs("; do ");
4614 dotail:
4615 cmdtxt(n);
4616 goto dotail2;
4617 case NFOR:
4618 cmdputs("for ");
4619 cmdputs(n->nfor.var);
4620 cmdputs(" in ");
4621 cmdlist(n->nfor.args, 1);
4622 n = n->nfor.body;
4623 p = "; done";
4624 goto dodo;
4625 case NDEFUN:
4626 cmdputs(n->narg.text);
4627 p = "() { ... }";
4628 goto dotail2;
4629 case NCMD:
4630 cmdlist(n->ncmd.args, 1);
4631 cmdlist(n->ncmd.redirect, 0);
4632 break;
4633 case NARG:
4634 p = n->narg.text;
4635 dotail2:
4636 cmdputs(p);
4637 break;
4638 case NHERE:
4639 case NXHERE:
4640 p = "<<...";
4641 goto dotail2;
4642 case NCASE:
4643 cmdputs("case ");
4644 cmdputs(n->ncase.expr->narg.text);
4645 cmdputs(" in ");
4646 for (np = n->ncase.cases; np; np = np->nclist.next) {
4647 cmdtxt(np->nclist.pattern);
4648 cmdputs(") ");
4649 cmdtxt(np->nclist.body);
4650 cmdputs(";; ");
4651 }
4652 p = "esac";
4653 goto dotail2;
4654 case NTO:
4655 p = ">";
4656 goto redir;
4657 case NCLOBBER:
4658 p = ">|";
4659 goto redir;
4660 case NAPPEND:
4661 p = ">>";
4662 goto redir;
Denis Vlasenko559691a2008-10-05 18:39:31 +00004663#if ENABLE_ASH_BASH_COMPAT
4664 case NTO2:
4665#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004666 case NTOFD:
4667 p = ">&";
4668 goto redir;
4669 case NFROM:
4670 p = "<";
4671 goto redir;
4672 case NFROMFD:
4673 p = "<&";
4674 goto redir;
4675 case NFROMTO:
4676 p = "<>";
4677 redir:
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00004678 cmdputs(utoa(n->nfile.fd));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004679 cmdputs(p);
4680 if (n->type == NTOFD || n->type == NFROMFD) {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00004681 cmdputs(utoa(n->ndup.dupfd));
4682 break;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004683 }
4684 n = n->nfile.fname;
4685 goto donode;
4686 }
4687}
4688
4689static char *
4690commandtext(union node *n)
4691{
4692 char *name;
4693
4694 STARTSTACKSTR(cmdnextc);
4695 cmdtxt(n);
4696 name = stackblock();
Denys Vlasenko6a94cee2016-10-25 17:40:25 +02004697 TRACE(("commandtext: name %p, end %p\n", name, cmdnextc));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004698 return ckstrdup(name);
4699}
4700#endif /* JOBS */
4701
4702/*
4703 * Fork off a subshell. If we are doing job control, give the subshell its
4704 * own process group. Jp is a job structure that the job is to be added to.
4705 * N is the command that will be evaluated by the child. Both jp and n may
4706 * be NULL. The mode parameter can be one of the following:
4707 * FORK_FG - Fork off a foreground process.
4708 * FORK_BG - Fork off a background process.
4709 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
4710 * process group even if job control is on.
4711 *
4712 * When job control is turned off, background processes have their standard
4713 * input redirected to /dev/null (except for the second and later processes
4714 * in a pipeline).
4715 *
4716 * Called with interrupts off.
4717 */
4718/*
4719 * Clear traps on a fork.
4720 */
4721static void
4722clear_traps(void)
4723{
4724 char **tp;
4725
Denys Vlasenkob4f51d32016-10-27 12:55:09 +02004726 INT_OFF;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004727 for (tp = trap; tp < &trap[NSIG]; tp++) {
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004728 if (*tp && **tp) { /* trap not NULL or "" (SIG_IGN) */
Denys Vlasenkoe305c282009-09-25 02:12:27 +02004729 if (trap_ptr == trap)
4730 free(*tp);
4731 /* else: it "belongs" to trap_ptr vector, don't free */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004732 *tp = NULL;
Denys Vlasenko0800e3a2009-09-24 03:09:26 +02004733 if ((tp - trap) != 0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004734 setsignal(tp - trap);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004735 }
4736 }
Alexander Shishkinccb97712010-07-25 13:07:39 +02004737 may_have_traps = 0;
Denys Vlasenkob4f51d32016-10-27 12:55:09 +02004738 INT_ON;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004739}
Denis Vlasenkobdc406d2007-07-15 01:13:25 +00004740
4741/* Lives far away from here, needed for forkchild */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004742static void closescript(void);
Denis Vlasenko41770222007-10-07 18:02:52 +00004743
Denis Vlasenkobdc406d2007-07-15 01:13:25 +00004744/* Called after fork(), in child */
Denys Vlasenko70392332016-10-27 02:31:55 +02004745/* jp and n are NULL when called by openhere() for heredoc support */
Denys Vlasenko21d87d42009-09-25 00:06:51 +02004746static NOINLINE void
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02004747forkchild(struct job *jp, union node *n, int mode)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004748{
4749 int oldlvl;
4750
4751 TRACE(("Child shell %d\n", getpid()));
4752 oldlvl = shlvl;
4753 shlvl++;
4754
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004755 /* man bash: "Non-builtin commands run by bash have signal handlers
4756 * set to the values inherited by the shell from its parent".
4757 * Do we do it correctly? */
4758
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004759 closescript();
Denys Vlasenko844f9902009-09-23 03:25:52 +02004760
4761 if (mode == FORK_NOJOB /* is it `xxx` ? */
4762 && n && n->type == NCMD /* is it single cmd? */
4763 /* && n->ncmd.args->type == NARG - always true? */
Denys Vlasenko74269202010-02-21 01:26:42 +01004764 && n->ncmd.args && strcmp(n->ncmd.args->narg.text, "trap") == 0
Denys Vlasenko844f9902009-09-23 03:25:52 +02004765 && n->ncmd.args->narg.next == NULL /* "trap" with no arguments */
4766 /* && n->ncmd.args->narg.backquote == NULL - do we need to check this? */
4767 ) {
4768 TRACE(("Trap hack\n"));
4769 /* Awful hack for `trap` or $(trap).
4770 *
4771 * http://www.opengroup.org/onlinepubs/009695399/utilities/trap.html
4772 * contains an example where "trap" is executed in a subshell:
4773 *
4774 * save_traps=$(trap)
4775 * ...
4776 * eval "$save_traps"
4777 *
4778 * Standard does not say that "trap" in subshell shall print
4779 * parent shell's traps. It only says that its output
4780 * must have suitable form, but then, in the above example
4781 * (which is not supposed to be normative), it implies that.
4782 *
4783 * bash (and probably other shell) does implement it
4784 * (traps are reset to defaults, but "trap" still shows them),
4785 * but as a result, "trap" logic is hopelessly messed up:
4786 *
4787 * # trap
4788 * trap -- 'echo Ho' SIGWINCH <--- we have a handler
4789 * # (trap) <--- trap is in subshell - no output (correct, traps are reset)
4790 * # true | trap <--- trap is in subshell - no output (ditto)
4791 * # echo `true | trap` <--- in subshell - output (but traps are reset!)
4792 * trap -- 'echo Ho' SIGWINCH
4793 * # echo `(trap)` <--- in subshell in subshell - output
4794 * trap -- 'echo Ho' SIGWINCH
4795 * # echo `true | (trap)` <--- in subshell in subshell in subshell - output!
4796 * trap -- 'echo Ho' SIGWINCH
4797 *
4798 * The rules when to forget and when to not forget traps
4799 * get really complex and nonsensical.
4800 *
4801 * Our solution: ONLY bare $(trap) or `trap` is special.
4802 */
Denys Vlasenko8f88d852009-09-25 12:12:53 +02004803 /* Save trap handler strings for trap builtin to print */
Ron Yorstond840c5d2015-07-19 23:05:20 +02004804 trap_ptr = xmemdup(trap, sizeof(trap));
Denys Vlasenko8f88d852009-09-25 12:12:53 +02004805 /* Fall through into clearing traps */
Denys Vlasenko844f9902009-09-23 03:25:52 +02004806 }
Denys Vlasenkoe305c282009-09-25 02:12:27 +02004807 clear_traps();
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004808#if JOBS
4809 /* do job control only in root shell */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00004810 doing_jobctl = 0;
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004811 if (mode != FORK_NOJOB && jp->jobctl && oldlvl == 0) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004812 pid_t pgrp;
4813
4814 if (jp->nprocs == 0)
4815 pgrp = getpid();
4816 else
Denys Vlasenko285ad152009-12-04 23:02:27 +01004817 pgrp = jp->ps[0].ps_pid;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004818 /* this can fail because we are doing it in the parent also */
4819 setpgid(0, pgrp);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004820 if (mode == FORK_FG)
4821 xtcsetpgrp(ttyfd, pgrp);
4822 setsignal(SIGTSTP);
4823 setsignal(SIGTTOU);
4824 } else
4825#endif
4826 if (mode == FORK_BG) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004827 /* man bash: "When job control is not in effect,
4828 * asynchronous commands ignore SIGINT and SIGQUIT" */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004829 ignoresig(SIGINT);
4830 ignoresig(SIGQUIT);
4831 if (jp->nprocs == 0) {
4832 close(0);
4833 if (open(bb_dev_null, O_RDONLY) != 0)
Denis Vlasenko9604e1b2009-03-03 18:47:56 +00004834 ash_msg_and_raise_error("can't open '%s'", bb_dev_null);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004835 }
4836 }
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004837 if (oldlvl == 0) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004838 if (iflag) { /* why if iflag only? */
4839 setsignal(SIGINT);
4840 setsignal(SIGTERM);
4841 }
4842 /* man bash:
4843 * "In all cases, bash ignores SIGQUIT. Non-builtin
4844 * commands run by bash have signal handlers
4845 * set to the values inherited by the shell
4846 * from its parent".
4847 * Take care of the second rule: */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004848 setsignal(SIGQUIT);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004849 }
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02004850#if JOBS
Denys Vlasenko844f9902009-09-23 03:25:52 +02004851 if (n && n->type == NCMD
Denys Vlasenko74269202010-02-21 01:26:42 +01004852 && n->ncmd.args && strcmp(n->ncmd.args->narg.text, "jobs") == 0
Denys Vlasenko844f9902009-09-23 03:25:52 +02004853 ) {
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02004854 TRACE(("Job hack\n"));
Denys Vlasenko844f9902009-09-23 03:25:52 +02004855 /* "jobs": we do not want to clear job list for it,
4856 * instead we remove only _its_ own_ job from job list.
4857 * This makes "jobs .... | cat" more useful.
4858 */
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02004859 freejob(curjob);
4860 return;
4861 }
4862#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004863 for (jp = curjob; jp; jp = jp->prev_job)
4864 freejob(jp);
4865 jobless = 0;
4866}
4867
Denis Vlasenkobdc406d2007-07-15 01:13:25 +00004868/* Called after fork(), in parent */
Denis Vlasenko85c24712008-03-17 09:04:04 +00004869#if !JOBS
4870#define forkparent(jp, n, mode, pid) forkparent(jp, mode, pid)
4871#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004872static void
4873forkparent(struct job *jp, union node *n, int mode, pid_t pid)
4874{
4875 TRACE(("In parent shell: child = %d\n", pid));
4876 if (!jp) {
Denys Vlasenko70392332016-10-27 02:31:55 +02004877 /* jp is NULL when called by openhere() for heredoc support */
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004878 while (jobless && dowait(DOWAIT_NONBLOCK, NULL) > 0)
4879 continue;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004880 jobless++;
4881 return;
4882 }
4883#if JOBS
4884 if (mode != FORK_NOJOB && jp->jobctl) {
4885 int pgrp;
4886
4887 if (jp->nprocs == 0)
4888 pgrp = pid;
4889 else
Denys Vlasenko285ad152009-12-04 23:02:27 +01004890 pgrp = jp->ps[0].ps_pid;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004891 /* This can fail because we are doing it in the child also */
4892 setpgid(pid, pgrp);
4893 }
4894#endif
4895 if (mode == FORK_BG) {
4896 backgndpid = pid; /* set $! */
4897 set_curjob(jp, CUR_RUNNING);
4898 }
4899 if (jp) {
4900 struct procstat *ps = &jp->ps[jp->nprocs++];
Denys Vlasenko285ad152009-12-04 23:02:27 +01004901 ps->ps_pid = pid;
4902 ps->ps_status = -1;
4903 ps->ps_cmd = nullstr;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004904#if JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +00004905 if (doing_jobctl && n)
Denys Vlasenko285ad152009-12-04 23:02:27 +01004906 ps->ps_cmd = commandtext(n);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004907#endif
4908 }
4909}
4910
Denys Vlasenko70392332016-10-27 02:31:55 +02004911/* jp and n are NULL when called by openhere() for heredoc support */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004912static int
4913forkshell(struct job *jp, union node *n, int mode)
4914{
4915 int pid;
4916
4917 TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
4918 pid = fork();
4919 if (pid < 0) {
4920 TRACE(("Fork failed, errno=%d", errno));
4921 if (jp)
4922 freejob(jp);
Denis Vlasenkofa0b56d2008-07-01 16:09:07 +00004923 ash_msg_and_raise_error("can't fork");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004924 }
Denys Vlasenko76ace252009-10-12 15:25:01 +02004925 if (pid == 0) {
4926 CLEAR_RANDOM_T(&random_gen); /* or else $RANDOM repeats in child */
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02004927 forkchild(jp, n, mode);
Denys Vlasenko76ace252009-10-12 15:25:01 +02004928 } else {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004929 forkparent(jp, n, mode, pid);
Denys Vlasenko76ace252009-10-12 15:25:01 +02004930 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004931 return pid;
4932}
4933
4934/*
4935 * Wait for job to finish.
4936 *
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004937 * Under job control we have the problem that while a child process
4938 * is running interrupts generated by the user are sent to the child
4939 * but not to the shell. This means that an infinite loop started by
4940 * an interactive user may be hard to kill. With job control turned off,
4941 * an interactive user may place an interactive program inside a loop.
4942 * If the interactive program catches interrupts, the user doesn't want
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004943 * these interrupts to also abort the loop. The approach we take here
4944 * is to have the shell ignore interrupt signals while waiting for a
4945 * foreground process to terminate, and then send itself an interrupt
4946 * signal if the child process was terminated by an interrupt signal.
4947 * Unfortunately, some programs want to do a bit of cleanup and then
4948 * exit on interrupt; unless these processes terminate themselves by
4949 * sending a signal to themselves (instead of calling exit) they will
4950 * confuse this approach.
4951 *
4952 * Called with interrupts off.
4953 */
4954static int
4955waitforjob(struct job *jp)
4956{
4957 int st;
4958
4959 TRACE(("waitforjob(%%%d) called\n", jobno(jp)));
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004960
4961 INT_OFF;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004962 while (jp->state == JOBRUNNING) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004963 /* In non-interactive shells, we _can_ get
4964 * a keyboard signal here and be EINTRed,
4965 * but we just loop back, waiting for command to complete.
4966 *
4967 * man bash:
4968 * "If bash is waiting for a command to complete and receives
4969 * a signal for which a trap has been set, the trap
4970 * will not be executed until the command completes."
4971 *
4972 * Reality is that even if trap is not set, bash
4973 * will not act on the signal until command completes.
4974 * Try this. sleep5intoff.c:
4975 * #include <signal.h>
4976 * #include <unistd.h>
4977 * int main() {
4978 * sigset_t set;
4979 * sigemptyset(&set);
4980 * sigaddset(&set, SIGINT);
4981 * sigaddset(&set, SIGQUIT);
4982 * sigprocmask(SIG_BLOCK, &set, NULL);
4983 * sleep(5);
4984 * return 0;
4985 * }
4986 * $ bash -c './sleep5intoff; echo hi'
4987 * ^C^C^C^C <--- pressing ^C once a second
4988 * $ _
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004989 * $ bash -c './sleep5intoff; echo hi'
4990 * ^\^\^\^\hi <--- pressing ^\ (SIGQUIT)
4991 * $ _
4992 */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004993 dowait(DOWAIT_BLOCK, jp);
4994 }
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004995 INT_ON;
4996
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004997 st = getstatus(jp);
4998#if JOBS
4999 if (jp->jobctl) {
5000 xtcsetpgrp(ttyfd, rootpid);
5001 /*
5002 * This is truly gross.
5003 * If we're doing job control, then we did a TIOCSPGRP which
5004 * caused us (the shell) to no longer be in the controlling
5005 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
5006 * intuit from the subprocess exit status whether a SIGINT
5007 * occurred, and if so interrupt ourselves. Yuck. - mycroft
5008 */
Denis Vlasenko991a1da2008-02-10 19:02:53 +00005009 if (jp->sigint) /* TODO: do the same with all signals */
5010 raise(SIGINT); /* ... by raise(jp->sig) instead? */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005011 }
5012 if (jp->state == JOBDONE)
5013#endif
5014 freejob(jp);
5015 return st;
5016}
5017
5018/*
5019 * return 1 if there are stopped jobs, otherwise 0
5020 */
5021static int
5022stoppedjobs(void)
5023{
5024 struct job *jp;
5025 int retval;
5026
5027 retval = 0;
5028 if (job_warning)
5029 goto out;
5030 jp = curjob;
5031 if (jp && jp->state == JOBSTOPPED) {
5032 out2str("You have stopped jobs.\n");
5033 job_warning = 2;
5034 retval++;
5035 }
5036 out:
5037 return retval;
5038}
5039
5040
Denys Vlasenko70392332016-10-27 02:31:55 +02005041/*
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005042 * Code for dealing with input/output redirection.
5043 */
5044
Denys Vlasenko8d0e0cd2011-01-25 23:21:46 +01005045#undef EMPTY
5046#undef CLOSED
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005047#define EMPTY -2 /* marks an unused slot in redirtab */
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005048#define CLOSED -3 /* marks a slot of previously-closed fd */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005049
5050/*
5051 * Open a file in noclobber mode.
5052 * The code was copied from bash.
5053 */
5054static int
5055noclobberopen(const char *fname)
5056{
5057 int r, fd;
5058 struct stat finfo, finfo2;
5059
5060 /*
5061 * If the file exists and is a regular file, return an error
5062 * immediately.
5063 */
5064 r = stat(fname, &finfo);
5065 if (r == 0 && S_ISREG(finfo.st_mode)) {
5066 errno = EEXIST;
5067 return -1;
5068 }
5069
5070 /*
5071 * If the file was not present (r != 0), make sure we open it
5072 * exclusively so that if it is created before we open it, our open
5073 * will fail. Make sure that we do not truncate an existing file.
5074 * Note that we don't turn on O_EXCL unless the stat failed -- if the
5075 * file was not a regular file, we leave O_EXCL off.
5076 */
5077 if (r != 0)
5078 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
5079 fd = open(fname, O_WRONLY|O_CREAT, 0666);
5080
5081 /* If the open failed, return the file descriptor right away. */
5082 if (fd < 0)
5083 return fd;
5084
5085 /*
5086 * OK, the open succeeded, but the file may have been changed from a
5087 * non-regular file to a regular file between the stat and the open.
5088 * We are assuming that the O_EXCL open handles the case where FILENAME
5089 * did not exist and is symlinked to an existing file between the stat
5090 * and open.
5091 */
5092
5093 /*
5094 * If we can open it and fstat the file descriptor, and neither check
5095 * revealed that it was a regular file, and the file has not been
5096 * replaced, return the file descriptor.
5097 */
Denys Vlasenko8d3e2252010-08-31 12:42:06 +02005098 if (fstat(fd, &finfo2) == 0
5099 && !S_ISREG(finfo2.st_mode)
5100 && finfo.st_dev == finfo2.st_dev
5101 && finfo.st_ino == finfo2.st_ino
5102 ) {
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005103 return fd;
Denys Vlasenko8d3e2252010-08-31 12:42:06 +02005104 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005105
5106 /* The file has been replaced. badness. */
5107 close(fd);
5108 errno = EEXIST;
5109 return -1;
5110}
5111
5112/*
5113 * Handle here documents. Normally we fork off a process to write the
5114 * data to a pipe. If the document is short, we can stuff the data in
5115 * the pipe without forking.
5116 */
5117/* openhere needs this forward reference */
5118static void expandhere(union node *arg, int fd);
5119static int
5120openhere(union node *redir)
5121{
5122 int pip[2];
5123 size_t len = 0;
5124
5125 if (pipe(pip) < 0)
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00005126 ash_msg_and_raise_error("pipe call failed");
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005127 if (redir->type == NHERE) {
5128 len = strlen(redir->nhere.doc->narg.text);
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005129 if (len <= PIPE_BUF) {
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005130 full_write(pip[1], redir->nhere.doc->narg.text, len);
5131 goto out;
5132 }
5133 }
5134 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
Denis Vlasenko0b769642008-07-24 07:54:57 +00005135 /* child */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005136 close(pip[0]);
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005137 ignoresig(SIGINT); //signal(SIGINT, SIG_IGN);
5138 ignoresig(SIGQUIT); //signal(SIGQUIT, SIG_IGN);
5139 ignoresig(SIGHUP); //signal(SIGHUP, SIG_IGN);
5140 ignoresig(SIGTSTP); //signal(SIGTSTP, SIG_IGN);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005141 signal(SIGPIPE, SIG_DFL);
5142 if (redir->type == NHERE)
5143 full_write(pip[1], redir->nhere.doc->narg.text, len);
Denis Vlasenko0b769642008-07-24 07:54:57 +00005144 else /* NXHERE */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005145 expandhere(redir->nhere.doc, pip[1]);
Bernhard Reutner-Fischer636a1f82008-05-19 09:29:47 +00005146 _exit(EXIT_SUCCESS);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005147 }
5148 out:
5149 close(pip[1]);
5150 return pip[0];
5151}
5152
5153static int
5154openredirect(union node *redir)
5155{
5156 char *fname;
5157 int f;
5158
5159 switch (redir->nfile.type) {
Denys Vlasenko557482c2016-09-25 21:24:04 +02005160/* Can't happen, our single caller does this itself */
5161// case NTOFD:
5162// case NFROMFD:
5163// return -1;
5164 case NHERE:
5165 case NXHERE:
5166 return openhere(redir);
5167 }
5168
5169 /* For N[X]HERE, reading redir->nfile.expfname would touch beyond
5170 * allocated space. Do it only when we know it is safe.
5171 */
5172 fname = redir->nfile.expfname;
5173
5174 switch (redir->nfile.type) {
5175 default:
5176#if DEBUG
5177 abort();
5178#endif
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005179 case NFROM:
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005180 f = open(fname, O_RDONLY);
5181 if (f < 0)
5182 goto eopen;
5183 break;
5184 case NFROMTO:
Andreas Bühmannda75f442010-06-24 04:32:37 +02005185 f = open(fname, O_RDWR|O_CREAT, 0666);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005186 if (f < 0)
5187 goto ecreate;
5188 break;
5189 case NTO:
Denis Vlasenko559691a2008-10-05 18:39:31 +00005190#if ENABLE_ASH_BASH_COMPAT
5191 case NTO2:
5192#endif
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005193 /* Take care of noclobber mode. */
5194 if (Cflag) {
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005195 f = noclobberopen(fname);
5196 if (f < 0)
5197 goto ecreate;
5198 break;
5199 }
5200 /* FALLTHROUGH */
5201 case NCLOBBER:
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005202 f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666);
5203 if (f < 0)
5204 goto ecreate;
5205 break;
5206 case NAPPEND:
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005207 f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666);
5208 if (f < 0)
5209 goto ecreate;
5210 break;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005211 }
5212
5213 return f;
5214 ecreate:
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +00005215 ash_msg_and_raise_error("can't create %s: %s", fname, errmsg(errno, "nonexistent directory"));
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005216 eopen:
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +00005217 ash_msg_and_raise_error("can't open %s: %s", fname, errmsg(errno, "no such file"));
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005218}
5219
5220/*
Denys Vlasenko64774602016-10-26 15:24:30 +02005221 * Copy a file descriptor to be >= 10. Throws exception on error.
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005222 */
5223static int
Denys Vlasenko64774602016-10-26 15:24:30 +02005224savefd(int from)
5225{
5226 int newfd;
5227 int err;
5228
5229 newfd = fcntl(from, F_DUPFD, 10);
5230 err = newfd < 0 ? errno : 0;
5231 if (err != EBADF) {
5232 if (err)
5233 ash_msg_and_raise_error("%d: %m", from);
5234 close(from);
5235 fcntl(newfd, F_SETFD, FD_CLOEXEC);
5236 }
5237
5238 return newfd;
5239}
5240static int
5241dup2_or_raise(int from, int to)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005242{
5243 int newfd;
5244
Denys Vlasenko64774602016-10-26 15:24:30 +02005245 newfd = (from != to) ? dup2(from, to) : to;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005246 if (newfd < 0) {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005247 /* Happens when source fd is not open: try "echo >&99" */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005248 ash_msg_and_raise_error("%d: %m", from);
5249 }
5250 return newfd;
5251}
5252
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005253/* Struct def and variable are moved down to the first usage site */
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005254struct two_fd_t {
5255 int orig, copy;
5256};
Denis Vlasenko0b769642008-07-24 07:54:57 +00005257struct redirtab {
5258 struct redirtab *next;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005259 int pair_count;
Denys Vlasenko606291b2009-09-23 23:15:43 +02005260 struct two_fd_t two_fd[];
Denis Vlasenko0b769642008-07-24 07:54:57 +00005261};
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005262#define redirlist (G_var.redirlist)
Denys Vlasenko64774602016-10-26 15:24:30 +02005263enum {
5264 COPYFD_RESTORE = (int)~(INT_MAX),
5265};
Denis Vlasenko0b769642008-07-24 07:54:57 +00005266
Denys Vlasenko37dc08b2016-10-02 04:38:07 +02005267static int
5268need_to_remember(struct redirtab *rp, int fd)
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005269{
5270 int i;
5271
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005272 if (!rp) /* remembering was not requested */
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005273 return 0;
5274
5275 for (i = 0; i < rp->pair_count; i++) {
5276 if (rp->two_fd[i].orig == fd) {
5277 /* already remembered */
5278 return 0;
5279 }
5280 }
5281 return 1;
5282}
5283
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005284/* "hidden" fd is a fd used to read scripts, or a copy of such */
Denys Vlasenko37dc08b2016-10-02 04:38:07 +02005285static int
5286is_hidden_fd(struct redirtab *rp, int fd)
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005287{
5288 int i;
Denis Vlasenko34c73c42008-08-16 11:48:02 +00005289 struct parsefile *pf;
5290
5291 if (fd == -1)
5292 return 0;
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005293 /* Check open scripts' fds */
Denis Vlasenko34c73c42008-08-16 11:48:02 +00005294 pf = g_parsefile;
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005295 while (pf) {
Denys Vlasenko79b3d422010-06-03 04:29:08 +02005296 /* We skip pf_fd == 0 case because of the following case:
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005297 * $ ash # running ash interactively
5298 * $ . ./script.sh
5299 * and in script.sh: "exec 9>&0".
Denys Vlasenko79b3d422010-06-03 04:29:08 +02005300 * Even though top-level pf_fd _is_ 0,
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005301 * it's still ok to use it: "read" builtin uses it,
5302 * why should we cripple "exec" builtin?
5303 */
Denys Vlasenko79b3d422010-06-03 04:29:08 +02005304 if (pf->pf_fd > 0 && fd == pf->pf_fd) {
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005305 return 1;
5306 }
5307 pf = pf->prev;
5308 }
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005309
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005310 if (!rp)
5311 return 0;
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005312 /* Check saved fds of redirects */
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005313 fd |= COPYFD_RESTORE;
5314 for (i = 0; i < rp->pair_count; i++) {
5315 if (rp->two_fd[i].copy == fd) {
5316 return 1;
5317 }
5318 }
5319 return 0;
5320}
5321
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005322/*
5323 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
5324 * old file descriptors are stashed away so that the redirection can be
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005325 * undone by calling popredir.
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005326 */
5327/* flags passed to redirect */
5328#define REDIR_PUSH 01 /* save previous values of file descriptors */
5329#define REDIR_SAVEFD2 03 /* set preverrout */
5330static void
5331redirect(union node *redir, int flags)
5332{
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005333 struct redirtab *sv;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005334 int sv_pos;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005335 int i;
5336 int fd;
5337 int newfd;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005338 int copied_fd2 = -1;
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005339
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005340 if (!redir) {
5341 return;
5342 }
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005343
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005344 sv = NULL;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005345 sv_pos = 0;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005346 INT_OFF;
5347 if (flags & REDIR_PUSH) {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005348 union node *tmp = redir;
5349 do {
5350 sv_pos++;
Denis Vlasenko559691a2008-10-05 18:39:31 +00005351#if ENABLE_ASH_BASH_COMPAT
Chris Metcalfc3c1fb62010-01-08 13:18:06 +01005352 if (tmp->nfile.type == NTO2)
Denis Vlasenko559691a2008-10-05 18:39:31 +00005353 sv_pos++;
5354#endif
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005355 tmp = tmp->nfile.next;
5356 } while (tmp);
5357 sv = ckmalloc(sizeof(*sv) + sv_pos * sizeof(sv->two_fd[0]));
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005358 sv->next = redirlist;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005359 sv->pair_count = sv_pos;
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005360 redirlist = sv;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005361 while (sv_pos > 0) {
5362 sv_pos--;
5363 sv->two_fd[sv_pos].orig = sv->two_fd[sv_pos].copy = EMPTY;
5364 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005365 }
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005366
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005367 do {
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005368 int right_fd = -1;
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00005369 fd = redir->nfile.fd;
Denis Vlasenko0b769642008-07-24 07:54:57 +00005370 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005371 right_fd = redir->ndup.dupfd;
5372 //bb_error_msg("doing %d > %d", fd, right_fd);
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005373 /* redirect from/to same file descriptor? */
5374 if (right_fd == fd)
5375 continue;
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005376 /* "echo >&10" and 10 is a fd opened to a sh script? */
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005377 if (is_hidden_fd(sv, right_fd)) {
5378 errno = EBADF; /* as if it is closed */
5379 ash_msg_and_raise_error("%d: %m", right_fd);
5380 }
Denis Vlasenko0b769642008-07-24 07:54:57 +00005381 newfd = -1;
5382 } else {
5383 newfd = openredirect(redir); /* always >= 0 */
5384 if (fd == newfd) {
5385 /* Descriptor wasn't open before redirect.
5386 * Mark it for close in the future */
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005387 if (need_to_remember(sv, fd)) {
Denis Vlasenko5a867312008-07-24 19:46:38 +00005388 goto remember_to_close;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005389 }
Denis Vlasenko0b769642008-07-24 07:54:57 +00005390 continue;
5391 }
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005392 }
Denis Vlasenko559691a2008-10-05 18:39:31 +00005393#if ENABLE_ASH_BASH_COMPAT
5394 redirect_more:
5395#endif
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005396 if (need_to_remember(sv, fd)) {
Denis Vlasenko0b769642008-07-24 07:54:57 +00005397 /* Copy old descriptor */
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005398 /* Careful to not accidentally "save"
5399 * to the same fd as right side fd in N>&M */
5400 int minfd = right_fd < 10 ? 10 : right_fd + 1;
5401 i = fcntl(fd, F_DUPFD, minfd);
Denis Vlasenko5a867312008-07-24 19:46:38 +00005402/* You'd expect copy to be CLOEXECed. Currently these extra "saved" fds
5403 * are closed in popredir() in the child, preventing them from leaking
5404 * into child. (popredir() also cleans up the mess in case of failures)
5405 */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005406 if (i == -1) {
5407 i = errno;
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005408 if (i != EBADF) {
5409 /* Strange error (e.g. "too many files" EMFILE?) */
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005410 if (newfd >= 0)
5411 close(newfd);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005412 errno = i;
5413 ash_msg_and_raise_error("%d: %m", fd);
5414 /* NOTREACHED */
5415 }
Denis Vlasenko5a867312008-07-24 19:46:38 +00005416 /* EBADF: it is not open - good, remember to close it */
5417 remember_to_close:
5418 i = CLOSED;
Denis Vlasenko22f74142008-07-24 22:34:43 +00005419 } else { /* fd is open, save its copy */
5420 /* "exec fd>&-" should not close fds
5421 * which point to script file(s).
5422 * Force them to be restored afterwards */
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005423 if (is_hidden_fd(sv, fd))
5424 i |= COPYFD_RESTORE;
Denis Vlasenko22f74142008-07-24 22:34:43 +00005425 }
Denis Vlasenko5a867312008-07-24 19:46:38 +00005426 if (fd == 2)
5427 copied_fd2 = i;
5428 sv->two_fd[sv_pos].orig = fd;
5429 sv->two_fd[sv_pos].copy = i;
5430 sv_pos++;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005431 }
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005432 if (newfd < 0) {
5433 /* NTOFD/NFROMFD: copy redir->ndup.dupfd to fd */
Denis Vlasenko22f74142008-07-24 22:34:43 +00005434 if (redir->ndup.dupfd < 0) { /* "fd>&-" */
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +00005435 /* Don't want to trigger debugging */
5436 if (fd != -1)
5437 close(fd);
Denis Vlasenko5a867312008-07-24 19:46:38 +00005438 } else {
Denys Vlasenko64774602016-10-26 15:24:30 +02005439 dup2_or_raise(redir->ndup.dupfd, fd);
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005440 }
Denis Vlasenko5a867312008-07-24 19:46:38 +00005441 } else if (fd != newfd) { /* move newfd to fd */
Denys Vlasenko64774602016-10-26 15:24:30 +02005442 dup2_or_raise(newfd, fd);
Denis Vlasenko559691a2008-10-05 18:39:31 +00005443#if ENABLE_ASH_BASH_COMPAT
5444 if (!(redir->nfile.type == NTO2 && fd == 2))
5445#endif
5446 close(newfd);
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005447 }
Denis Vlasenko559691a2008-10-05 18:39:31 +00005448#if ENABLE_ASH_BASH_COMPAT
5449 if (redir->nfile.type == NTO2 && fd == 1) {
5450 /* We already redirected it to fd 1, now copy it to 2 */
5451 newfd = 1;
5452 fd = 2;
5453 goto redirect_more;
5454 }
5455#endif
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00005456 } while ((redir = redir->nfile.next) != NULL);
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005457
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005458 INT_ON;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005459 if ((flags & REDIR_SAVEFD2) && copied_fd2 >= 0)
5460 preverrout_fd = copied_fd2;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005461}
5462
5463/*
5464 * Undo the effects of the last redirection.
5465 */
5466static void
Denis Vlasenko34c73c42008-08-16 11:48:02 +00005467popredir(int drop, int restore)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005468{
5469 struct redirtab *rp;
5470 int i;
5471
Denys Vlasenkoeaf94362016-10-25 21:46:03 +02005472 if (redirlist == NULL)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005473 return;
5474 INT_OFF;
5475 rp = redirlist;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005476 for (i = 0; i < rp->pair_count; i++) {
5477 int fd = rp->two_fd[i].orig;
Denis Vlasenko22f74142008-07-24 22:34:43 +00005478 int copy = rp->two_fd[i].copy;
5479 if (copy == CLOSED) {
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005480 if (!drop)
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005481 close(fd);
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005482 continue;
5483 }
Denis Vlasenko22f74142008-07-24 22:34:43 +00005484 if (copy != EMPTY) {
Denis Vlasenko34c73c42008-08-16 11:48:02 +00005485 if (!drop || (restore && (copy & COPYFD_RESTORE))) {
Denis Vlasenko22f74142008-07-24 22:34:43 +00005486 copy &= ~COPYFD_RESTORE;
Denis Vlasenko5a867312008-07-24 19:46:38 +00005487 /*close(fd);*/
Denys Vlasenko64774602016-10-26 15:24:30 +02005488 dup2_or_raise(copy, fd);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005489 }
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +00005490 close(copy & ~COPYFD_RESTORE);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005491 }
5492 }
5493 redirlist = rp->next;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005494 free(rp);
5495 INT_ON;
5496}
5497
5498/*
5499 * Undo all redirections. Called on error or interrupt.
5500 */
5501
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005502static int
5503redirectsafe(union node *redir, int flags)
5504{
5505 int err;
5506 volatile int saveint;
5507 struct jmploc *volatile savehandler = exception_handler;
5508 struct jmploc jmploc;
5509
5510 SAVE_INT(saveint);
Denis Vlasenko5a867312008-07-24 19:46:38 +00005511 /* "echo 9>/dev/null; echo >&9; echo result: $?" - result should be 1, not 2! */
5512 err = setjmp(jmploc.loc); // huh?? was = setjmp(jmploc.loc) * 2;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005513 if (!err) {
5514 exception_handler = &jmploc;
5515 redirect(redir, flags);
5516 }
5517 exception_handler = savehandler;
Denis Vlasenko7f88e342009-03-19 03:36:18 +00005518 if (err && exception_type != EXERROR)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005519 longjmp(exception_handler->loc, 1);
5520 RESTORE_INT(saveint);
5521 return err;
5522}
5523
5524
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005525/* ============ Routines to expand arguments to commands
5526 *
5527 * We have to deal with backquotes, shell variables, and file metacharacters.
5528 */
5529
Mike Frysinger98c52642009-04-02 10:02:37 +00005530#if ENABLE_SH_MATH_SUPPORT
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005531static arith_t
5532ash_arith(const char *s)
5533{
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005534 arith_state_t math_state;
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005535 arith_t result;
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005536
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005537 math_state.lookupvar = lookupvar;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02005538 math_state.setvar = setvar0;
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005539 //math_state.endofname = endofname;
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005540
5541 INT_OFF;
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005542 result = arith(&math_state, s);
Denys Vlasenko063847d2010-09-15 13:33:02 +02005543 if (math_state.errmsg)
5544 ash_msg_and_raise_error(math_state.errmsg);
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005545 INT_ON;
5546
5547 return result;
5548}
Denis Vlasenko448d30e2008-06-27 00:24:11 +00005549#endif
5550
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005551/*
5552 * expandarg flags
5553 */
5554#define EXP_FULL 0x1 /* perform word splitting & file globbing */
5555#define EXP_TILDE 0x2 /* do normal tilde expansion */
5556#define EXP_VARTILDE 0x4 /* expand tildes in an assignment */
5557#define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */
Denys Vlasenkodb74c6c2016-10-24 21:12:33 +02005558/* ^^^^^^^^^^^^^^ this is meant to support constructs such as "cmd >file*.txt"
5559 * POSIX says for this case:
5560 * Pathname expansion shall not be performed on the word by a
5561 * non-interactive shell; an interactive shell may perform it, but shall
5562 * do so only when the expansion would result in one word.
5563 * Currently, our code complies to the above rule by never globbing
5564 * redirection filenames.
5565 * Bash performs globbing, unless it is non-interactive and in POSIX mode.
5566 * (this means that on a typical Linux distro, bash almost always
5567 * performs globbing, and thus diverges from what we do).
5568 */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005569#define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */
Ron Yorston549deab2015-05-18 09:57:51 +02005570#define EXP_QPAT 0x20 /* pattern in quoted parameter expansion */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005571#define EXP_VARTILDE2 0x40 /* expand tildes after colons only */
5572#define EXP_WORD 0x80 /* expand word in parameter expansion */
Ron Yorston3df47f92015-05-18 09:53:26 +02005573#define EXP_QUOTED 0x100 /* expand word in double quotes */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005574/*
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005575 * rmescape() flags
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005576 */
5577#define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
5578#define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005579#define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */
5580#define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */
Ron Yorston417622c2015-05-18 09:59:14 +02005581#define RMESCAPE_SLASH 0x20 /* Stop globbing after slash */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005582
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005583/* Add CTLESC when necessary. */
Ron Yorston549deab2015-05-18 09:57:51 +02005584#define QUOTES_ESC (EXP_FULL | EXP_CASE | EXP_QPAT | EXP_REDIR)
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005585/* Do not skip NUL characters. */
5586#define QUOTES_KEEPNUL EXP_TILDE
5587
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005588/*
5589 * Structure specifying which parts of the string should be searched
5590 * for IFS characters.
5591 */
5592struct ifsregion {
5593 struct ifsregion *next; /* next region in list */
5594 int begoff; /* offset of start of region */
5595 int endoff; /* offset of end of region */
5596 int nulonly; /* search for nul bytes only */
5597};
5598
5599struct arglist {
5600 struct strlist *list;
5601 struct strlist **lastp;
5602};
5603
5604/* output of current string */
5605static char *expdest;
5606/* list of back quote expressions */
5607static struct nodelist *argbackq;
5608/* first struct in list of ifs regions */
5609static struct ifsregion ifsfirst;
5610/* last struct in list */
5611static struct ifsregion *ifslastp;
5612/* holds expanded arg list */
5613static struct arglist exparg;
5614
5615/*
5616 * Our own itoa().
5617 */
Denys Vlasenko26777aa2010-11-22 23:49:10 +01005618#if !ENABLE_SH_MATH_SUPPORT
5619/* cvtnum() is used even if math support is off (to prepare $? values and such) */
5620typedef long arith_t;
5621# define ARITH_FMT "%ld"
5622#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005623static int
5624cvtnum(arith_t num)
5625{
5626 int len;
5627
Denys Vlasenko9c541002015-10-07 15:44:36 +02005628 expdest = makestrspace(sizeof(arith_t)*3 + 2, expdest);
5629 len = fmtstr(expdest, sizeof(arith_t)*3 + 2, ARITH_FMT, num);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005630 STADJUST(len, expdest);
5631 return len;
5632}
5633
Denys Vlasenko455e4222016-10-27 14:45:13 +02005634/*
5635 * Break the argument string into pieces based upon IFS and add the
5636 * strings to the argument list. The regions of the string to be
5637 * searched for IFS characters have been stored by recordregion.
5638 */
5639static void
5640ifsbreakup(char *string, struct arglist *arglist)
5641{
5642 struct ifsregion *ifsp;
5643 struct strlist *sp;
5644 char *start;
5645 char *p;
5646 char *q;
5647 const char *ifs, *realifs;
5648 int ifsspc;
5649 int nulonly;
5650
5651 start = string;
5652 if (ifslastp != NULL) {
5653 ifsspc = 0;
5654 nulonly = 0;
5655 realifs = ifsset() ? ifsval() : defifs;
5656 ifsp = &ifsfirst;
5657 do {
5658 p = string + ifsp->begoff;
5659 nulonly = ifsp->nulonly;
5660 ifs = nulonly ? nullstr : realifs;
5661 ifsspc = 0;
5662 while (p < string + ifsp->endoff) {
5663 q = p;
5664 if ((unsigned char)*p == CTLESC)
5665 p++;
5666 if (!strchr(ifs, *p)) {
5667 p++;
5668 continue;
5669 }
5670 if (!nulonly)
5671 ifsspc = (strchr(defifs, *p) != NULL);
5672 /* Ignore IFS whitespace at start */
5673 if (q == start && ifsspc) {
5674 p++;
5675 start = p;
5676 continue;
5677 }
5678 *q = '\0';
5679 sp = stzalloc(sizeof(*sp));
5680 sp->text = start;
5681 *arglist->lastp = sp;
5682 arglist->lastp = &sp->next;
5683 p++;
5684 if (!nulonly) {
5685 for (;;) {
5686 if (p >= string + ifsp->endoff) {
5687 break;
5688 }
5689 q = p;
5690 if ((unsigned char)*p == CTLESC)
5691 p++;
5692 if (strchr(ifs, *p) == NULL) {
5693 p = q;
5694 break;
5695 }
5696 if (strchr(defifs, *p) == NULL) {
5697 if (ifsspc) {
5698 p++;
5699 ifsspc = 0;
5700 } else {
5701 p = q;
5702 break;
5703 }
5704 } else
5705 p++;
5706 }
5707 }
5708 start = p;
5709 } /* while */
5710 ifsp = ifsp->next;
5711 } while (ifsp != NULL);
5712 if (nulonly)
5713 goto add;
5714 }
5715
5716 if (!*start)
5717 return;
5718
5719 add:
5720 sp = stzalloc(sizeof(*sp));
5721 sp->text = start;
5722 *arglist->lastp = sp;
5723 arglist->lastp = &sp->next;
5724}
5725
5726static void
5727ifsfree(void)
5728{
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02005729 struct ifsregion *p = ifsfirst.next;
5730
5731 if (!p)
5732 goto out;
Denys Vlasenko455e4222016-10-27 14:45:13 +02005733
5734 INT_OFF;
Denys Vlasenko455e4222016-10-27 14:45:13 +02005735 do {
5736 struct ifsregion *ifsp;
5737 ifsp = p->next;
5738 free(p);
5739 p = ifsp;
5740 } while (p);
Denys Vlasenko455e4222016-10-27 14:45:13 +02005741 ifsfirst.next = NULL;
5742 INT_ON;
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02005743 out:
5744 ifslastp = NULL;
Denys Vlasenko455e4222016-10-27 14:45:13 +02005745}
5746
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005747static size_t
5748esclen(const char *start, const char *p)
5749{
5750 size_t esc = 0;
5751
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005752 while (p > start && (unsigned char)*--p == CTLESC) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005753 esc++;
5754 }
5755 return esc;
5756}
5757
5758/*
5759 * Remove any CTLESC characters from a string.
5760 */
5761static char *
Denys Vlasenkob6c84342009-08-29 20:23:20 +02005762rmescapes(char *str, int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005763{
Ron Yorston417622c2015-05-18 09:59:14 +02005764 static const char qchars[] ALIGN1 = {
5765 IF_ASH_BASH_COMPAT('/',) CTLESC, CTLQUOTEMARK, '\0' };
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00005766
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005767 char *p, *q, *r;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005768 unsigned inquotes;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005769 unsigned protect_against_glob;
5770 unsigned globbing;
Ron Yorston417622c2015-05-18 09:59:14 +02005771 IF_ASH_BASH_COMPAT(unsigned slash = flag & RMESCAPE_SLASH;)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005772
Ron Yorston417622c2015-05-18 09:59:14 +02005773 p = strpbrk(str, qchars IF_ASH_BASH_COMPAT(+ !slash));
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005774 if (!p)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005775 return str;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005776
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005777 q = p;
5778 r = str;
5779 if (flag & RMESCAPE_ALLOC) {
5780 size_t len = p - str;
5781 size_t fulllen = len + strlen(p) + 1;
5782
5783 if (flag & RMESCAPE_GROW) {
Colin Watson3963d942010-04-26 14:21:27 +02005784 int strloc = str - (char *)stackblock();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005785 r = makestrspace(fulllen, expdest);
Colin Watson3963d942010-04-26 14:21:27 +02005786 /* p and str may be invalidated by makestrspace */
5787 str = (char *)stackblock() + strloc;
5788 p = str + len;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005789 } else if (flag & RMESCAPE_HEAP) {
5790 r = ckmalloc(fulllen);
5791 } else {
5792 r = stalloc(fulllen);
5793 }
5794 q = r;
5795 if (len > 0) {
Denis Vlasenko29eb3592008-05-18 14:06:08 +00005796 q = (char *)memcpy(q, str, len) + len;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005797 }
5798 }
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005799
Ron Yorston549deab2015-05-18 09:57:51 +02005800 inquotes = 0;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005801 globbing = flag & RMESCAPE_GLOB;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005802 protect_against_glob = globbing;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005803 while (*p) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01005804 if ((unsigned char)*p == CTLQUOTEMARK) {
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005805// Note: both inquotes and protect_against_glob only affect whether
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005806 inquotes = ~inquotes;
5807 p++;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005808 protect_against_glob = globbing;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005809 continue;
5810 }
Ron Yorston549deab2015-05-18 09:57:51 +02005811 if ((unsigned char)*p == CTLESC) {
5812 p++;
Denys Vlasenko13f20912016-09-25 20:54:25 +02005813#if DEBUG
5814 if (*p == '\0')
5815 ash_msg_and_raise_error("CTLESC at EOL (shouldn't happen)");
5816#endif
Ron Yorston549deab2015-05-18 09:57:51 +02005817 if (protect_against_glob) {
5818 *q++ = '\\';
5819 }
5820 } else if (*p == '\\' && !inquotes) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005821 /* naked back slash */
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005822 protect_against_glob = 0;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005823 goto copy;
5824 }
Ron Yorston417622c2015-05-18 09:59:14 +02005825#if ENABLE_ASH_BASH_COMPAT
5826 else if (*p == '/' && slash) {
5827 /* stop handling globbing and mark location of slash */
5828 globbing = slash = 0;
5829 *p = CTLESC;
5830 }
5831#endif
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005832 protect_against_glob = globbing;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005833 copy:
5834 *q++ = *p++;
5835 }
5836 *q = '\0';
5837 if (flag & RMESCAPE_GROW) {
5838 expdest = r;
5839 STADJUST(q - r + 1, expdest);
5840 }
5841 return r;
5842}
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005843#define pmatch(a, b) !fnmatch((a), (b), 0)
5844
5845/*
5846 * Prepare a pattern for a expmeta (internal glob(3)) call.
5847 *
5848 * Returns an stalloced string.
5849 */
5850static char *
Ron Yorston549deab2015-05-18 09:57:51 +02005851preglob(const char *pattern, int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005852{
Ron Yorston549deab2015-05-18 09:57:51 +02005853 return rmescapes((char *)pattern, flag | RMESCAPE_GLOB);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005854}
5855
5856/*
5857 * Put a string on the stack.
5858 */
5859static void
5860memtodest(const char *p, size_t len, int syntax, int quotes)
5861{
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005862 char *q;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005863
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005864 if (!len)
5865 return;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005866
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005867 q = makestrspace((quotes & QUOTES_ESC) ? len * 2 : len, expdest);
5868
5869 do {
Denys Vlasenkocd716832009-11-28 22:14:02 +01005870 unsigned char c = *p++;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005871 if (c) {
Denys Vlasenkob6c84342009-08-29 20:23:20 +02005872 int n = SIT(c, syntax);
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02005873 if ((quotes & QUOTES_ESC)
5874 && ((n == CCTL)
5875 || (((quotes & EXP_FULL) || syntax != BASESYNTAX)
5876 && n == CBACK)
5877 )
5878 ) {
Denys Vlasenkob6c84342009-08-29 20:23:20 +02005879 USTPUTC(CTLESC, q);
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02005880 }
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005881 } else if (!(quotes & QUOTES_KEEPNUL))
5882 continue;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005883 USTPUTC(c, q);
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005884 } while (--len);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005885
5886 expdest = q;
5887}
5888
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005889static size_t
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005890strtodest(const char *p, int syntax, int quotes)
5891{
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005892 size_t len = strlen(p);
5893 memtodest(p, len, syntax, quotes);
5894 return len;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005895}
5896
5897/*
5898 * Record the fact that we have to scan this region of the
5899 * string for IFS characters.
5900 */
5901static void
5902recordregion(int start, int end, int nulonly)
5903{
5904 struct ifsregion *ifsp;
5905
5906 if (ifslastp == NULL) {
5907 ifsp = &ifsfirst;
5908 } else {
5909 INT_OFF;
Denis Vlasenko597906c2008-02-20 16:38:54 +00005910 ifsp = ckzalloc(sizeof(*ifsp));
5911 /*ifsp->next = NULL; - ckzalloc did it */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005912 ifslastp->next = ifsp;
5913 INT_ON;
5914 }
5915 ifslastp = ifsp;
5916 ifslastp->begoff = start;
5917 ifslastp->endoff = end;
5918 ifslastp->nulonly = nulonly;
5919}
5920
5921static void
5922removerecordregions(int endoff)
5923{
5924 if (ifslastp == NULL)
5925 return;
5926
5927 if (ifsfirst.endoff > endoff) {
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02005928 while (ifsfirst.next) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005929 struct ifsregion *ifsp;
5930 INT_OFF;
5931 ifsp = ifsfirst.next->next;
5932 free(ifsfirst.next);
5933 ifsfirst.next = ifsp;
5934 INT_ON;
5935 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02005936 if (ifsfirst.begoff > endoff) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005937 ifslastp = NULL;
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02005938 } else {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005939 ifslastp = &ifsfirst;
5940 ifsfirst.endoff = endoff;
5941 }
5942 return;
5943 }
5944
5945 ifslastp = &ifsfirst;
5946 while (ifslastp->next && ifslastp->next->begoff < endoff)
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02005947 ifslastp = ifslastp->next;
5948 while (ifslastp->next) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005949 struct ifsregion *ifsp;
5950 INT_OFF;
5951 ifsp = ifslastp->next->next;
5952 free(ifslastp->next);
5953 ifslastp->next = ifsp;
5954 INT_ON;
5955 }
5956 if (ifslastp->endoff > endoff)
5957 ifslastp->endoff = endoff;
5958}
5959
5960static char *
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005961exptilde(char *startp, char *p, int flags)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005962{
Denys Vlasenkocd716832009-11-28 22:14:02 +01005963 unsigned char c;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005964 char *name;
5965 struct passwd *pw;
5966 const char *home;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005967 int quotes = flags & QUOTES_ESC;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005968
5969 name = p + 1;
5970
5971 while ((c = *++p) != '\0') {
5972 switch (c) {
5973 case CTLESC:
5974 return startp;
5975 case CTLQUOTEMARK:
5976 return startp;
5977 case ':':
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005978 if (flags & EXP_VARTILDE)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005979 goto done;
5980 break;
5981 case '/':
5982 case CTLENDVAR:
5983 goto done;
5984 }
5985 }
5986 done:
5987 *p = '\0';
5988 if (*name == '\0') {
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02005989 home = lookupvar("HOME");
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005990 } else {
5991 pw = getpwnam(name);
5992 if (pw == NULL)
5993 goto lose;
5994 home = pw->pw_dir;
5995 }
5996 if (!home || !*home)
5997 goto lose;
5998 *p = c;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005999 strtodest(home, SQSYNTAX, quotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006000 return p;
6001 lose:
6002 *p = c;
6003 return startp;
6004}
6005
6006/*
6007 * Execute a command inside back quotes. If it's a builtin command, we
6008 * want to save its output in a block obtained from malloc. Otherwise
6009 * we fork off a subprocess and get the output of the command via a pipe.
6010 * Should be called with interrupts off.
6011 */
6012struct backcmd { /* result of evalbackcmd */
6013 int fd; /* file descriptor to read from */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006014 int nleft; /* number of chars in buffer */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00006015 char *buf; /* buffer */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006016 struct job *jp; /* job structure for command */
6017};
6018
6019/* These forward decls are needed to use "eval" code for backticks handling: */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006020#define EV_EXIT 01 /* exit after evaluating tree */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02006021static int evaltree(union node *, int);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006022
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02006023static void FAST_FUNC
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006024evalbackcmd(union node *n, struct backcmd *result)
6025{
Denys Vlasenko579ad102016-10-25 21:10:20 +02006026 int pip[2];
6027 struct job *jp;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006028
6029 result->fd = -1;
6030 result->buf = NULL;
6031 result->nleft = 0;
6032 result->jp = NULL;
Denys Vlasenko579ad102016-10-25 21:10:20 +02006033 if (n == NULL) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006034 goto out;
Denys Vlasenko579ad102016-10-25 21:10:20 +02006035 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006036
Denys Vlasenko579ad102016-10-25 21:10:20 +02006037 if (pipe(pip) < 0)
6038 ash_msg_and_raise_error("pipe call failed");
6039 jp = makejob(/*n,*/ 1);
6040 if (forkshell(jp, n, FORK_NOJOB) == 0) {
Denys Vlasenko70392332016-10-27 02:31:55 +02006041 /* child */
Denys Vlasenko579ad102016-10-25 21:10:20 +02006042 FORCE_INT_ON;
6043 close(pip[0]);
6044 if (pip[1] != 1) {
6045 /*close(1);*/
Denys Vlasenko64774602016-10-26 15:24:30 +02006046 dup2_or_raise(pip[1], 1);
Denys Vlasenko579ad102016-10-25 21:10:20 +02006047 close(pip[1]);
6048 }
Denys Vlasenko960ca382016-10-25 18:12:15 +02006049/* TODO: eflag clearing makes the following not abort:
6050 * ash -c 'set -e; z=$(false;echo foo); echo $z'
6051 * which is what bash does (unless it is in POSIX mode).
6052 * dash deleted "eflag = 0" line in the commit
6053 * Date: Mon, 28 Jun 2010 17:11:58 +1000
6054 * [EVAL] Don't clear eflag in evalbackcmd
6055 * For now, preserve bash-like behavior, it seems to be somewhat more useful:
6056 */
Denys Vlasenko579ad102016-10-25 21:10:20 +02006057 eflag = 0;
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02006058 ifsfree();
Denys Vlasenko579ad102016-10-25 21:10:20 +02006059 evaltree(n, EV_EXIT); /* actually evaltreenr... */
6060 /* NOTREACHED */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006061 }
Denys Vlasenko70392332016-10-27 02:31:55 +02006062 /* parent */
Denys Vlasenko579ad102016-10-25 21:10:20 +02006063 close(pip[1]);
6064 result->fd = pip[0];
6065 result->jp = jp;
6066
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006067 out:
6068 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
6069 result->fd, result->buf, result->nleft, result->jp));
6070}
6071
6072/*
6073 * Expand stuff in backwards quotes.
6074 */
6075static void
Ron Yorston549deab2015-05-18 09:57:51 +02006076expbackq(union node *cmd, int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006077{
6078 struct backcmd in;
6079 int i;
6080 char buf[128];
6081 char *p;
6082 char *dest;
6083 int startloc;
Ron Yorston549deab2015-05-18 09:57:51 +02006084 int syntax = flag & EXP_QUOTED ? DQSYNTAX : BASESYNTAX;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006085 struct stackmark smark;
6086
6087 INT_OFF;
Denys Vlasenko60ca8342016-09-30 11:21:21 +02006088 startloc = expdest - (char *)stackblock();
6089 pushstackmark(&smark, startloc);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006090 evalbackcmd(cmd, &in);
6091 popstackmark(&smark);
6092
6093 p = in.buf;
6094 i = in.nleft;
6095 if (i == 0)
6096 goto read;
6097 for (;;) {
Ron Yorston549deab2015-05-18 09:57:51 +02006098 memtodest(p, i, syntax, flag & QUOTES_ESC);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006099 read:
6100 if (in.fd < 0)
6101 break;
Ron Yorston61d6ae22015-04-19 10:50:25 +01006102 i = nonblock_immune_read(in.fd, buf, sizeof(buf));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006103 TRACE(("expbackq: read returns %d\n", i));
6104 if (i <= 0)
6105 break;
6106 p = buf;
6107 }
6108
Denis Vlasenko60818682007-09-28 22:07:23 +00006109 free(in.buf);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006110 if (in.fd >= 0) {
6111 close(in.fd);
6112 back_exitstatus = waitforjob(in.jp);
6113 }
6114 INT_ON;
6115
6116 /* Eat all trailing newlines */
6117 dest = expdest;
6118 for (; dest > (char *)stackblock() && dest[-1] == '\n';)
6119 STUNPUTC(dest);
6120 expdest = dest;
6121
Ron Yorston549deab2015-05-18 09:57:51 +02006122 if (!(flag & EXP_QUOTED))
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006123 recordregion(startloc, dest - (char *)stackblock(), 0);
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006124 TRACE(("evalbackq: size:%d:'%.*s'\n",
6125 (int)((dest - (char *)stackblock()) - startloc),
6126 (int)((dest - (char *)stackblock()) - startloc),
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006127 stackblock() + startloc));
6128}
6129
Mike Frysinger98c52642009-04-02 10:02:37 +00006130#if ENABLE_SH_MATH_SUPPORT
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006131/*
6132 * Expand arithmetic expression. Backup to start of expression,
6133 * evaluate, place result in (backed up) result, adjust string position.
6134 */
6135static void
Ron Yorston549deab2015-05-18 09:57:51 +02006136expari(int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006137{
6138 char *p, *start;
6139 int begoff;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006140 int len;
6141
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006142 /* ifsfree(); */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006143
6144 /*
6145 * This routine is slightly over-complicated for
6146 * efficiency. Next we scan backwards looking for the
6147 * start of arithmetic.
6148 */
6149 start = stackblock();
6150 p = expdest - 1;
6151 *p = '\0';
6152 p--;
Denys Vlasenko940c7202011-03-02 04:07:14 +01006153 while (1) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006154 int esc;
6155
Denys Vlasenkocd716832009-11-28 22:14:02 +01006156 while ((unsigned char)*p != CTLARI) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006157 p--;
6158#if DEBUG
6159 if (p < start) {
6160 ash_msg_and_raise_error("missing CTLARI (shouldn't happen)");
6161 }
6162#endif
6163 }
6164
6165 esc = esclen(start, p);
6166 if (!(esc % 2)) {
6167 break;
6168 }
6169
6170 p -= esc + 1;
Denys Vlasenko940c7202011-03-02 04:07:14 +01006171 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006172
6173 begoff = p - start;
6174
6175 removerecordregions(begoff);
6176
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006177 expdest = p;
6178
Ron Yorston549deab2015-05-18 09:57:51 +02006179 if (flag & QUOTES_ESC)
6180 rmescapes(p + 1, 0);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006181
Ron Yorston549deab2015-05-18 09:57:51 +02006182 len = cvtnum(ash_arith(p + 1));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006183
Ron Yorston549deab2015-05-18 09:57:51 +02006184 if (!(flag & EXP_QUOTED))
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006185 recordregion(begoff, begoff + len, 0);
6186}
6187#endif
6188
6189/* argstr needs it */
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006190static char *evalvar(char *p, int flags, struct strlist *var_str_list);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006191
6192/*
6193 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
6194 * characters to allow for further processing. Otherwise treat
6195 * $@ like $* since no splitting will be performed.
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006196 *
6197 * var_str_list (can be NULL) is a list of "VAR=val" strings which take precedence
6198 * over shell varables. Needed for "A=a B=$A; echo $B" case - we use it
6199 * for correct expansion of "B=$A" word.
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006200 */
6201static void
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006202argstr(char *p, int flags, struct strlist *var_str_list)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006203{
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00006204 static const char spclchars[] ALIGN1 = {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006205 '=',
6206 ':',
6207 CTLQUOTEMARK,
6208 CTLENDVAR,
6209 CTLESC,
6210 CTLVAR,
6211 CTLBACKQ,
Mike Frysinger98c52642009-04-02 10:02:37 +00006212#if ENABLE_SH_MATH_SUPPORT
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006213 CTLENDARI,
6214#endif
Denys Vlasenkocd716832009-11-28 22:14:02 +01006215 '\0'
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006216 };
6217 const char *reject = spclchars;
Ron Yorston3df47f92015-05-18 09:53:26 +02006218 int breakall = (flags & (EXP_WORD | EXP_QUOTED)) == EXP_WORD;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006219 int inquotes;
6220 size_t length;
6221 int startloc;
6222
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006223 if (!(flags & EXP_VARTILDE)) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006224 reject += 2;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006225 } else if (flags & EXP_VARTILDE2) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006226 reject++;
6227 }
6228 inquotes = 0;
6229 length = 0;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006230 if (flags & EXP_TILDE) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006231 char *q;
6232
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006233 flags &= ~EXP_TILDE;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006234 tilde:
6235 q = p;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006236 if (*q == '~')
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006237 p = exptilde(p, q, flags);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006238 }
6239 start:
6240 startloc = expdest - (char *)stackblock();
6241 for (;;) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006242 unsigned char c;
6243
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006244 length += strcspn(p + length, reject);
Denys Vlasenkocd716832009-11-28 22:14:02 +01006245 c = p[length];
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006246 if (c) {
6247 if (!(c & 0x80)
Denys Vlasenko958581a2010-09-12 15:04:27 +02006248 IF_SH_MATH_SUPPORT(|| c == CTLENDARI)
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006249 ) {
6250 /* c == '=' || c == ':' || c == CTLENDARI */
6251 length++;
6252 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006253 }
6254 if (length > 0) {
6255 int newloc;
6256 expdest = stack_nputstr(p, length, expdest);
6257 newloc = expdest - (char *)stackblock();
6258 if (breakall && !inquotes && newloc > startloc) {
6259 recordregion(startloc, newloc, 0);
6260 }
6261 startloc = newloc;
6262 }
6263 p += length + 1;
6264 length = 0;
6265
6266 switch (c) {
6267 case '\0':
6268 goto breakloop;
6269 case '=':
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006270 if (flags & EXP_VARTILDE2) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006271 p--;
6272 continue;
6273 }
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006274 flags |= EXP_VARTILDE2;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006275 reject++;
6276 /* fall through */
6277 case ':':
6278 /*
6279 * sort of a hack - expand tildes in variable
6280 * assignments (after the first '=' and after ':'s).
6281 */
6282 if (*--p == '~') {
6283 goto tilde;
6284 }
6285 continue;
6286 }
6287
6288 switch (c) {
6289 case CTLENDVAR: /* ??? */
6290 goto breakloop;
6291 case CTLQUOTEMARK:
Ron Yorston549deab2015-05-18 09:57:51 +02006292 inquotes ^= EXP_QUOTED;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006293 /* "$@" syntax adherence hack */
Ron Yorston549deab2015-05-18 09:57:51 +02006294 if (inquotes && !memcmp(p, dolatstr + 1, DOLATSTRLEN - 1)) {
6295 p = evalvar(p + 1, flags | inquotes, /* var_str_list: */ NULL) + 1;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006296 goto start;
6297 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006298 addquote:
Ron Yorston549deab2015-05-18 09:57:51 +02006299 if (flags & QUOTES_ESC) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006300 p--;
6301 length++;
6302 startloc++;
6303 }
6304 break;
6305 case CTLESC:
6306 startloc++;
6307 length++;
Ron Yorston549deab2015-05-18 09:57:51 +02006308
6309 /*
6310 * Quoted parameter expansion pattern: remove quote
6311 * unless inside inner quotes or we have a literal
6312 * backslash.
6313 */
6314 if (((flags | inquotes) & (EXP_QPAT | EXP_QUOTED)) ==
6315 EXP_QPAT && *p != '\\')
6316 break;
6317
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006318 goto addquote;
6319 case CTLVAR:
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02006320 TRACE(("argstr: evalvar('%s')\n", p));
Ron Yorston549deab2015-05-18 09:57:51 +02006321 p = evalvar(p, flags | inquotes, var_str_list);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02006322 TRACE(("argstr: evalvar:'%s'\n", (char *)stackblock()));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006323 goto start;
6324 case CTLBACKQ:
Ron Yorston549deab2015-05-18 09:57:51 +02006325 expbackq(argbackq->n, flags | inquotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006326 argbackq = argbackq->next;
6327 goto start;
Mike Frysinger98c52642009-04-02 10:02:37 +00006328#if ENABLE_SH_MATH_SUPPORT
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006329 case CTLENDARI:
6330 p--;
Ron Yorston549deab2015-05-18 09:57:51 +02006331 expari(flags | inquotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006332 goto start;
6333#endif
6334 }
6335 }
Denys Vlasenko958581a2010-09-12 15:04:27 +02006336 breakloop: ;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006337}
6338
6339static char *
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006340scanleft(char *startp, char *rmesc, char *rmescend UNUSED_PARAM,
6341 char *pattern, int quotes, int zero)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006342{
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006343 char *loc, *loc2;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006344 char c;
6345
6346 loc = startp;
6347 loc2 = rmesc;
6348 do {
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006349 int match;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006350 const char *s = loc2;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006351
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006352 c = *loc2;
6353 if (zero) {
6354 *loc2 = '\0';
6355 s = rmesc;
6356 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006357 match = pmatch(pattern, s);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006358
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006359 *loc2 = c;
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006360 if (match)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006361 return loc;
Denys Vlasenkocd716832009-11-28 22:14:02 +01006362 if (quotes && (unsigned char)*loc == CTLESC)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006363 loc++;
6364 loc++;
6365 loc2++;
6366 } while (c);
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006367 return NULL;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006368}
6369
6370static char *
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006371scanright(char *startp, char *rmesc, char *rmescend,
6372 char *pattern, int quotes, int match_at_start)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006373{
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006374#if !ENABLE_ASH_OPTIMIZE_FOR_SIZE
6375 int try2optimize = match_at_start;
6376#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006377 int esc = 0;
6378 char *loc;
6379 char *loc2;
6380
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006381 /* If we called by "${v/pattern/repl}" or "${v//pattern/repl}":
6382 * startp="escaped_value_of_v" rmesc="raw_value_of_v"
6383 * rmescend=""(ptr to NUL in rmesc) pattern="pattern" quotes=match_at_start=1
6384 * Logic:
6385 * loc starts at NUL at the end of startp, loc2 starts at the end of rmesc,
6386 * and on each iteration they go back two/one char until they reach the beginning.
6387 * We try to find a match in "raw_value_of_v", "raw_value_of_", "raw_value_of" etc.
6388 */
6389 /* TODO: document in what other circumstances we are called. */
6390
6391 for (loc = pattern - 1, loc2 = rmescend; loc >= startp; loc2--) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006392 int match;
6393 char c = *loc2;
6394 const char *s = loc2;
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006395 if (match_at_start) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006396 *loc2 = '\0';
6397 s = rmesc;
6398 }
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006399 match = pmatch(pattern, s);
6400 //bb_error_msg("pmatch(pattern:'%s',s:'%s'):%d", pattern, s, match);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006401 *loc2 = c;
6402 if (match)
6403 return loc;
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006404#if !ENABLE_ASH_OPTIMIZE_FOR_SIZE
6405 if (try2optimize) {
6406 /* Maybe we can optimize this:
6407 * if pattern ends with unescaped *, we can avoid checking
6408 * shorter strings: if "foo*" doesnt match "raw_value_of_v",
6409 * it wont match truncated "raw_value_of_" strings too.
6410 */
6411 unsigned plen = strlen(pattern);
6412 /* Does it end with "*"? */
6413 if (plen != 0 && pattern[--plen] == '*') {
6414 /* "xxxx*" is not escaped */
6415 /* "xxx\*" is escaped */
6416 /* "xx\\*" is not escaped */
6417 /* "x\\\*" is escaped */
6418 int slashes = 0;
6419 while (plen != 0 && pattern[--plen] == '\\')
6420 slashes++;
6421 if (!(slashes & 1))
6422 break; /* ends with unescaped "*" */
6423 }
6424 try2optimize = 0;
6425 }
6426#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006427 loc--;
6428 if (quotes) {
6429 if (--esc < 0) {
6430 esc = esclen(startp, loc);
6431 }
6432 if (esc % 2) {
6433 esc--;
6434 loc--;
6435 }
6436 }
6437 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006438 return NULL;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006439}
6440
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00006441static void varunset(const char *, const char *, const char *, int) NORETURN;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006442static void
6443varunset(const char *end, const char *var, const char *umsg, int varflags)
6444{
6445 const char *msg;
6446 const char *tail;
6447
6448 tail = nullstr;
6449 msg = "parameter not set";
6450 if (umsg) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006451 if ((unsigned char)*end == CTLENDVAR) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006452 if (varflags & VSNUL)
6453 tail = " or null";
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006454 } else {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006455 msg = umsg;
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006456 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006457 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006458 ash_msg_and_raise_error("%.*s: %s%s", (int)(end - var - 1), var, msg, tail);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006459}
6460
6461static const char *
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006462subevalvar(char *p, char *varname, int strloc, int subtype,
Ron Yorston549deab2015-05-18 09:57:51 +02006463 int startloc, int varflags, int flag, struct strlist *var_str_list)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006464{
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006465 struct nodelist *saveargbackq = argbackq;
Ron Yorston549deab2015-05-18 09:57:51 +02006466 int quotes = flag & QUOTES_ESC;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006467 char *startp;
6468 char *loc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006469 char *rmesc, *rmescend;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006470 char *str;
Ron Yorston417622c2015-05-18 09:59:14 +02006471 IF_ASH_BASH_COMPAT(char *repl = NULL;)
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00006472 IF_ASH_BASH_COMPAT(int pos, len, orig_len;)
Denys Vlasenko0b4980c2012-09-25 12:49:29 +02006473 int amount, resetloc;
6474 IF_ASH_BASH_COMPAT(int workloc;)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006475 int zero;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006476 char *(*scan)(char*, char*, char*, char*, int, int);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006477
Denys Vlasenko6040fe82010-09-12 15:03:16 +02006478 //bb_error_msg("subevalvar(p:'%s',varname:'%s',strloc:%d,subtype:%d,startloc:%d,varflags:%x,quotes:%d)",
6479 // p, varname, strloc, subtype, startloc, varflags, quotes);
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006480
Ron Yorstoneb6b48b2015-05-18 09:51:35 +02006481 argstr(p, EXP_TILDE | (subtype != VSASSIGN && subtype != VSQUESTION ?
Ron Yorston549deab2015-05-18 09:57:51 +02006482 (flag & (EXP_QUOTED | EXP_QPAT) ? EXP_QPAT : EXP_CASE) : 0),
6483 var_str_list);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006484 STPUTC('\0', expdest);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006485 argbackq = saveargbackq;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006486 startp = (char *)stackblock() + startloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006487
6488 switch (subtype) {
6489 case VSASSIGN:
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02006490 setvar0(varname, startp);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006491 amount = startp - expdest;
6492 STADJUST(amount, expdest);
6493 return startp;
6494
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006495 case VSQUESTION:
6496 varunset(p, varname, startp, varflags);
6497 /* NOTREACHED */
6498
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006499#if ENABLE_ASH_BASH_COMPAT
6500 case VSSUBSTR:
Denys Vlasenkof8ddbe12016-07-25 03:56:00 +02006501//TODO: support more general format ${v:EXPR:EXPR},
6502// where EXPR follows $(()) rules
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006503 loc = str = stackblock() + strloc;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006504 /* Read POS in ${var:POS:LEN} */
6505 pos = atoi(loc); /* number(loc) errors out on "1:4" */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006506 len = str - startp - 1;
6507
6508 /* *loc != '\0', guaranteed by parser */
6509 if (quotes) {
6510 char *ptr;
6511
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006512 /* Adjust the length by the number of escapes */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006513 for (ptr = startp; ptr < (str - 1); ptr++) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006514 if ((unsigned char)*ptr == CTLESC) {
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006515 len--;
6516 ptr++;
6517 }
6518 }
6519 }
6520 orig_len = len;
6521
6522 if (*loc++ == ':') {
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006523 /* ${var::LEN} */
6524 len = number(loc);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006525 } else {
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006526 /* Skip POS in ${var:POS:LEN} */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006527 len = orig_len;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006528 while (*loc && *loc != ':') {
6529 /* TODO?
6530 * bash complains on: var=qwe; echo ${var:1a:123}
6531 if (!isdigit(*loc))
6532 ash_msg_and_raise_error(msg_illnum, str);
6533 */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006534 loc++;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006535 }
6536 if (*loc++ == ':') {
6537 len = number(loc);
6538 }
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006539 }
Denys Vlasenko08a5dab2014-11-17 20:27:18 +01006540 if (pos < 0) {
6541 /* ${VAR:$((-n)):l} starts n chars from the end */
6542 pos = orig_len + pos;
6543 }
6544 if ((unsigned)pos >= orig_len) {
6545 /* apart from obvious ${VAR:999999:l},
6546 * covers ${VAR:$((-9999999)):l} - result is ""
6547 * (bash-compat)
6548 */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006549 pos = 0;
6550 len = 0;
6551 }
6552 if (len > (orig_len - pos))
6553 len = orig_len - pos;
6554
6555 for (str = startp; pos; str++, pos--) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006556 if (quotes && (unsigned char)*str == CTLESC)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006557 str++;
6558 }
6559 for (loc = startp; len; len--) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006560 if (quotes && (unsigned char)*str == CTLESC)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006561 *loc++ = *str++;
6562 *loc++ = *str++;
6563 }
6564 *loc = '\0';
6565 amount = loc - expdest;
6566 STADJUST(amount, expdest);
6567 return loc;
6568#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006569 }
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006570
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006571 resetloc = expdest - (char *)stackblock();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006572
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006573 /* We'll comeback here if we grow the stack while handling
6574 * a VSREPLACE or VSREPLACEALL, since our pointers into the
6575 * stack will need rebasing, and we'll need to remove our work
6576 * areas each time
6577 */
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00006578 IF_ASH_BASH_COMPAT(restart:)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006579
6580 amount = expdest - ((char *)stackblock() + resetloc);
6581 STADJUST(-amount, expdest);
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006582 startp = (char *)stackblock() + startloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006583
6584 rmesc = startp;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006585 rmescend = (char *)stackblock() + strloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006586 if (quotes) {
Denys Vlasenkob6c84342009-08-29 20:23:20 +02006587 rmesc = rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006588 if (rmesc != startp) {
6589 rmescend = expdest;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006590 startp = (char *)stackblock() + startloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006591 }
6592 }
6593 rmescend--;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006594 str = (char *)stackblock() + strloc;
Ron Yorston417622c2015-05-18 09:59:14 +02006595 /*
6596 * Example: v='a\bc'; echo ${v/\\b/_\\_\z_}
6597 * The result is a_\_z_c (not a\_\_z_c)!
6598 *
6599 * The search pattern and replace string treat backslashes differently!
6600 * RMESCAPE_SLASH causes preglob to work differently on the pattern
6601 * and string. It's only used on the first call.
6602 */
6603 preglob(str, IF_ASH_BASH_COMPAT(
6604 (subtype == VSREPLACE || subtype == VSREPLACEALL) && !repl ?
6605 RMESCAPE_SLASH :) 0);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006606
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006607#if ENABLE_ASH_BASH_COMPAT
Denys Vlasenko0b4980c2012-09-25 12:49:29 +02006608 workloc = expdest - (char *)stackblock();
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006609 if (subtype == VSREPLACE || subtype == VSREPLACEALL) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006610 char *idx, *end;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006611
Denis Vlasenkod6855d12008-09-27 14:03:25 +00006612 if (!repl) {
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02006613 repl = strchr(str, CTLESC);
6614 if (repl)
Ron Yorston417622c2015-05-18 09:59:14 +02006615 *repl++ = '\0';
6616 else
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006617 repl = nullstr;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006618 }
Ron Yorston417622c2015-05-18 09:59:14 +02006619 //bb_error_msg("str:'%s' repl:'%s'", str, repl);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006620
6621 /* If there's no pattern to match, return the expansion unmolested */
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006622 if (str[0] == '\0')
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006623 return NULL;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006624
6625 len = 0;
6626 idx = startp;
6627 end = str - 1;
6628 while (idx < end) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006629 try_to_match:
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006630 loc = scanright(idx, rmesc, rmescend, str, quotes, 1);
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006631 //bb_error_msg("scanright('%s'):'%s'", str, loc);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006632 if (!loc) {
6633 /* No match, advance */
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006634 char *restart_detect = stackblock();
6635 skip_matching:
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006636 STPUTC(*idx, expdest);
Denys Vlasenkocd716832009-11-28 22:14:02 +01006637 if (quotes && (unsigned char)*idx == CTLESC) {
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006638 idx++;
6639 len++;
6640 STPUTC(*idx, expdest);
6641 }
6642 if (stackblock() != restart_detect)
6643 goto restart;
6644 idx++;
6645 len++;
6646 rmesc++;
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006647 /* continue; - prone to quadratic behavior, smarter code: */
6648 if (idx >= end)
6649 break;
6650 if (str[0] == '*') {
6651 /* Pattern is "*foo". If "*foo" does not match "long_string",
6652 * it would never match "ong_string" etc, no point in trying.
6653 */
6654 goto skip_matching;
6655 }
6656 goto try_to_match;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006657 }
6658
6659 if (subtype == VSREPLACEALL) {
6660 while (idx < loc) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006661 if (quotes && (unsigned char)*idx == CTLESC)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006662 idx++;
6663 idx++;
6664 rmesc++;
6665 }
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006666 } else {
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006667 idx = loc;
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006668 }
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006669
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006670 //bb_error_msg("repl:'%s'", repl);
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006671 for (loc = (char*)repl; *loc; loc++) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006672 char *restart_detect = stackblock();
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006673 if (quotes && *loc == '\\') {
6674 STPUTC(CTLESC, expdest);
6675 len++;
6676 }
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006677 STPUTC(*loc, expdest);
6678 if (stackblock() != restart_detect)
6679 goto restart;
6680 len++;
6681 }
6682
6683 if (subtype == VSREPLACE) {
Denys Vlasenkof02c82f2010-08-06 19:14:47 +02006684 //bb_error_msg("tail:'%s', quotes:%x", idx, quotes);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006685 while (*idx) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006686 char *restart_detect = stackblock();
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006687 STPUTC(*idx, expdest);
6688 if (stackblock() != restart_detect)
6689 goto restart;
6690 len++;
6691 idx++;
6692 }
6693 break;
6694 }
6695 }
6696
6697 /* We've put the replaced text into a buffer at workloc, now
6698 * move it to the right place and adjust the stack.
6699 */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006700 STPUTC('\0', expdest);
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006701 startp = (char *)stackblock() + startloc;
6702 memmove(startp, (char *)stackblock() + workloc, len + 1);
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006703 //bb_error_msg("startp:'%s'", startp);
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006704 amount = expdest - (startp + len);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006705 STADJUST(-amount, expdest);
6706 return startp;
6707 }
6708#endif /* ENABLE_ASH_BASH_COMPAT */
6709
6710 subtype -= VSTRIMRIGHT;
6711#if DEBUG
6712 if (subtype < 0 || subtype > 7)
6713 abort();
6714#endif
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006715 /* zero = (subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX) */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006716 zero = subtype >> 1;
6717 /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */
6718 scan = (subtype & 1) ^ zero ? scanleft : scanright;
6719
6720 loc = scan(startp, rmesc, rmescend, str, quotes, zero);
6721 if (loc) {
6722 if (zero) {
6723 memmove(startp, loc, str - loc);
6724 loc = startp + (str - loc) - 1;
6725 }
6726 *loc = '\0';
6727 amount = loc - expdest;
6728 STADJUST(amount, expdest);
6729 }
6730 return loc;
6731}
6732
6733/*
6734 * Add the value of a specialized variable to the stack string.
Denys Vlasenko4d8873f2009-10-04 03:14:41 +02006735 * name parameter (examples):
6736 * ash -c 'echo $1' name:'1='
6737 * ash -c 'echo $qwe' name:'qwe='
6738 * ash -c 'echo $$' name:'$='
6739 * ash -c 'echo ${$}' name:'$='
6740 * ash -c 'echo ${$##q}' name:'$=q'
6741 * ash -c 'echo ${#$}' name:'$='
6742 * note: examples with bad shell syntax:
6743 * ash -c 'echo ${#$1}' name:'$=1'
6744 * ash -c 'echo ${#1#}' name:'1=#'
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006745 */
Denys Vlasenkoadf922e2009-10-08 14:35:37 +02006746static NOINLINE ssize_t
Denys Vlasenko0dd8e452016-10-01 21:02:06 +02006747varvalue(char *name, int varflags, int flags, struct strlist *var_str_list, int *quotedp)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006748{
Mike Frysinger98c52642009-04-02 10:02:37 +00006749 const char *p;
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006750 int num;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006751 int i;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006752 ssize_t len = 0;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006753 int sep;
Denys Vlasenko0dd8e452016-10-01 21:02:06 +02006754 int quoted = *quotedp;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006755 int subtype = varflags & VSTYPE;
6756 int discard = subtype == VSPLUS || subtype == VSLENGTH;
6757 int quotes = (discard ? 0 : (flags & QUOTES_ESC)) | QUOTES_KEEPNUL;
Denys Vlasenko0aaaa502016-10-02 02:46:56 +02006758 int syntax;
6759
6760 sep = (flags & EXP_FULL) << CHAR_BIT;
6761 syntax = quoted ? DQSYNTAX : BASESYNTAX;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006762
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006763 switch (*name) {
6764 case '$':
6765 num = rootpid;
6766 goto numvar;
6767 case '?':
6768 num = exitstatus;
6769 goto numvar;
6770 case '#':
6771 num = shellparam.nparam;
6772 goto numvar;
6773 case '!':
6774 num = backgndpid;
6775 if (num == 0)
6776 return -1;
6777 numvar:
6778 len = cvtnum(num);
Denys Vlasenko4d8873f2009-10-04 03:14:41 +02006779 goto check_1char_name;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006780 case '-':
Mike Frysinger98c52642009-04-02 10:02:37 +00006781 expdest = makestrspace(NOPTS, expdest);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006782 for (i = NOPTS - 1; i >= 0; i--) {
6783 if (optlist[i]) {
Mike Frysinger98c52642009-04-02 10:02:37 +00006784 USTPUTC(optletters(i), expdest);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006785 len++;
6786 }
6787 }
Denys Vlasenko4d8873f2009-10-04 03:14:41 +02006788 check_1char_name:
6789#if 0
6790 /* handles cases similar to ${#$1} */
6791 if (name[2] != '\0')
6792 raise_error_syntax("bad substitution");
6793#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006794 break;
Denys Vlasenko0aaaa502016-10-02 02:46:56 +02006795 case '@':
6796 if (quoted && sep)
6797 goto param;
6798 /* fall through */
6799 case '*': {
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006800 char **ap;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006801 char sepc;
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006802
Denys Vlasenko0aaaa502016-10-02 02:46:56 +02006803 if (quoted)
6804 sep = 0;
6805 sep |= ifsset() ? ifsval()[0] : ' ';
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006806 param:
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006807 sepc = sep;
Denys Vlasenko0dd8e452016-10-01 21:02:06 +02006808 *quotedp = !sepc;
6809 ap = shellparam.p;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006810 if (!ap)
6811 return -1;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006812 while ((p = *ap++) != NULL) {
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006813 len += strtodest(p, syntax, quotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006814
6815 if (*ap && sep) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006816 len++;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006817 memtodest(&sepc, 1, syntax, quotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006818 }
6819 }
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006820 break;
Denys Vlasenko0aaaa502016-10-02 02:46:56 +02006821 } /* case '*' */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006822 case '0':
6823 case '1':
6824 case '2':
6825 case '3':
6826 case '4':
6827 case '5':
6828 case '6':
6829 case '7':
6830 case '8':
6831 case '9':
Denys Vlasenkoa00329c2009-08-30 20:05:10 +02006832 num = atoi(name); /* number(name) fails on ${N#str} etc */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006833 if (num < 0 || num > shellparam.nparam)
6834 return -1;
6835 p = num ? shellparam.p[num - 1] : arg0;
6836 goto value;
6837 default:
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006838 /* NB: name has form "VAR=..." */
6839
6840 /* "A=a B=$A" case: var_str_list is a list of "A=a" strings
6841 * which should be considered before we check variables. */
6842 if (var_str_list) {
6843 unsigned name_len = (strchrnul(name, '=') - name) + 1;
6844 p = NULL;
6845 do {
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00006846 char *str, *eq;
6847 str = var_str_list->text;
6848 eq = strchr(str, '=');
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006849 if (!eq) /* stop at first non-assignment */
6850 break;
6851 eq++;
Denis Vlasenko6b06cb82008-05-15 21:30:45 +00006852 if (name_len == (unsigned)(eq - str)
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006853 && strncmp(str, name, name_len) == 0
6854 ) {
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006855 p = eq;
6856 /* goto value; - WRONG! */
6857 /* think "A=1 A=2 B=$A" */
6858 }
6859 var_str_list = var_str_list->next;
6860 } while (var_str_list);
6861 if (p)
6862 goto value;
6863 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006864 p = lookupvar(name);
6865 value:
6866 if (!p)
6867 return -1;
6868
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006869 len = strtodest(p, syntax, quotes);
Denys Vlasenkoc76236f2014-12-29 00:04:18 +01006870#if ENABLE_UNICODE_SUPPORT
6871 if (subtype == VSLENGTH && len > 0) {
6872 reinit_unicode_for_ash();
6873 if (unicode_status == UNICODE_ON) {
Ron Yorston3e3bfb82016-03-18 11:29:19 +00006874 STADJUST(-len, expdest);
6875 discard = 0;
Denys Vlasenkoc76236f2014-12-29 00:04:18 +01006876 len = unicode_strlen(p);
6877 }
6878 }
6879#endif
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006880 break;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006881 }
6882
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006883 if (discard)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006884 STADJUST(-len, expdest);
6885 return len;
6886}
6887
6888/*
6889 * Expand a variable, and return a pointer to the next character in the
6890 * input string.
6891 */
6892static char *
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02006893evalvar(char *p, int flag, struct strlist *var_str_list)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006894{
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006895 char varflags;
6896 char subtype;
Ron Yorston549deab2015-05-18 09:57:51 +02006897 int quoted;
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006898 char easy;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006899 char *var;
6900 int patloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006901 int startloc;
6902 ssize_t varlen;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006903
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006904 varflags = (unsigned char) *p++;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006905 subtype = varflags & VSTYPE;
Denys Vlasenko88e15702016-10-26 01:55:56 +02006906
6907 if (!subtype)
6908 raise_error_syntax("bad substitution");
6909
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02006910 quoted = flag & EXP_QUOTED;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006911 var = p;
6912 easy = (!quoted || (*var == '@' && shellparam.nparam));
6913 startloc = expdest - (char *)stackblock();
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02006914 p = strchr(p, '=') + 1; //TODO: use var_end(p)?
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006915
6916 again:
Denys Vlasenko0dd8e452016-10-01 21:02:06 +02006917 varlen = varvalue(var, varflags, flag, var_str_list, &quoted);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006918 if (varflags & VSNUL)
6919 varlen--;
6920
6921 if (subtype == VSPLUS) {
6922 varlen = -1 - varlen;
6923 goto vsplus;
6924 }
6925
6926 if (subtype == VSMINUS) {
6927 vsplus:
6928 if (varlen < 0) {
6929 argstr(
Denys Vlasenko6040fe82010-09-12 15:03:16 +02006930 p,
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02006931 flag | EXP_TILDE | EXP_WORD,
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006932 var_str_list
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006933 );
6934 goto end;
6935 }
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02006936 goto record;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006937 }
6938
6939 if (subtype == VSASSIGN || subtype == VSQUESTION) {
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02006940 if (varlen >= 0)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006941 goto record;
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02006942
6943 subevalvar(p, var, 0, subtype, startloc, varflags,
6944 flag & ~QUOTES_ESC, var_str_list);
6945 varflags &= ~VSNUL;
6946 /*
6947 * Remove any recorded regions beyond
6948 * start of variable
6949 */
6950 removerecordregions(startloc);
6951 goto again;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006952 }
6953
6954 if (varlen < 0 && uflag)
6955 varunset(p, var, 0, 0);
6956
6957 if (subtype == VSLENGTH) {
Denys Vlasenkoc76236f2014-12-29 00:04:18 +01006958 cvtnum(varlen > 0 ? varlen : 0);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006959 goto record;
6960 }
6961
6962 if (subtype == VSNORMAL) {
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02006963 record:
6964 if (!easy)
6965 goto end;
Denys Vlasenko0dd8e452016-10-01 21:02:06 +02006966 recordregion(startloc, expdest - (char *)stackblock(), quoted);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006967 goto end;
6968 }
6969
6970#if DEBUG
6971 switch (subtype) {
6972 case VSTRIMLEFT:
6973 case VSTRIMLEFTMAX:
6974 case VSTRIMRIGHT:
6975 case VSTRIMRIGHTMAX:
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006976#if ENABLE_ASH_BASH_COMPAT
6977 case VSSUBSTR:
6978 case VSREPLACE:
6979 case VSREPLACEALL:
6980#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006981 break;
6982 default:
6983 abort();
6984 }
6985#endif
6986
6987 if (varlen >= 0) {
6988 /*
6989 * Terminate the string and start recording the pattern
6990 * right after it
6991 */
6992 STPUTC('\0', expdest);
6993 patloc = expdest - (char *)stackblock();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006994 if (NULL == subevalvar(p, /* varname: */ NULL, patloc, subtype,
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02006995 startloc, varflags, flag, var_str_list)) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006996 int amount = expdest - (
6997 (char *)stackblock() + patloc - 1
6998 );
6999 STADJUST(-amount, expdest);
7000 }
7001 /* Remove any recorded regions beyond start of variable */
7002 removerecordregions(startloc);
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007003 goto record;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007004 }
7005
7006 end:
7007 if (subtype != VSNORMAL) { /* skip to end of alternative */
7008 int nesting = 1;
7009 for (;;) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01007010 unsigned char c = *p++;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007011 if (c == CTLESC)
7012 p++;
Ron Yorston549deab2015-05-18 09:57:51 +02007013 else if (c == CTLBACKQ) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007014 if (varlen >= 0)
7015 argbackq = argbackq->next;
7016 } else if (c == CTLVAR) {
7017 if ((*p++ & VSTYPE) != VSNORMAL)
7018 nesting++;
7019 } else if (c == CTLENDVAR) {
7020 if (--nesting == 0)
7021 break;
7022 }
7023 }
7024 }
7025 return p;
7026}
7027
7028/*
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007029 * Add a file name to the list.
7030 */
7031static void
7032addfname(const char *name)
7033{
7034 struct strlist *sp;
7035
Denis Vlasenko597906c2008-02-20 16:38:54 +00007036 sp = stzalloc(sizeof(*sp));
Denys Vlasenko8e2bc472016-09-28 23:02:57 +02007037 sp->text = sstrdup(name);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007038 *exparg.lastp = sp;
7039 exparg.lastp = &sp->next;
7040}
7041
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007042/* If we want to use glob() from libc... */
Denys Vlasenko514b51d2016-10-01 14:33:08 +02007043#if !ENABLE_ASH_INTERNAL_GLOB
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007044
7045/* Add the result of glob() to the list */
7046static void
7047addglob(const glob_t *pglob)
7048{
7049 char **p = pglob->gl_pathv;
7050
7051 do {
7052 addfname(*p);
7053 } while (*++p);
7054}
7055static void
7056expandmeta(struct strlist *str /*, int flag*/)
7057{
7058 /* TODO - EXP_REDIR */
7059
7060 while (str) {
7061 char *p;
7062 glob_t pglob;
7063 int i;
7064
7065 if (fflag)
7066 goto nometa;
Denys Vlasenkod4f3db92016-10-30 18:41:01 +01007067
7068 /* Avoid glob() (and thus, stat() et al) for words like "echo" */
7069 p = str->text;
7070 while (*p) {
7071 if (*p == '*')
7072 goto need_glob;
7073 if (*p == '?')
7074 goto need_glob;
7075 if (*p == '[')
7076 goto need_glob;
7077 p++;
7078 }
7079 goto nometa;
7080
7081 need_glob:
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007082 INT_OFF;
7083 p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP);
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007084// GLOB_NOMAGIC (GNU): if no *?[ chars in pattern, return it even if no match
7085// GLOB_NOCHECK: if no match, return unchanged pattern (sans \* escapes?)
7086//
7087// glibc 2.24.90 glob(GLOB_NOMAGIC) does not remove backslashes used for escaping:
7088// if you pass it "file\?", it returns "file\?", not "file?", if no match.
7089// Which means you need to unescape the string, right? Not so fast:
7090// if there _is_ a file named "file\?" (with backslash), it is returned
7091// as "file\?" too (whichever pattern you used to find it, say, "file*").
7092// You DONT KNOW by looking at the result whether you need to unescape it.
7093//
7094// Worse, globbing of "file\?" in a directory with two files, "file?" and "file\?",
7095// returns "file\?" - which is WRONG: "file\?" pattern matches "file?" file.
7096// Without GLOB_NOMAGIC, this works correctly ("file?" is returned as a match).
7097// With GLOB_NOMAGIC | GLOB_NOCHECK, this also works correctly.
7098// i = glob(p, GLOB_NOMAGIC | GLOB_NOCHECK, NULL, &pglob);
7099// i = glob(p, GLOB_NOMAGIC, NULL, &pglob);
7100 i = glob(p, 0, NULL, &pglob);
7101 //bb_error_msg("glob('%s'):%d '%s'...", p, i, pglob.gl_pathv ? pglob.gl_pathv[0] : "-");
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007102 if (p != str->text)
7103 free(p);
7104 switch (i) {
7105 case 0:
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007106#if 0 // glibc 2.24.90 bug? Patterns like "*/file", when match, don't set GLOB_MAGCHAR
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007107 /* GLOB_MAGCHAR is set if *?[ chars were seen (GNU) */
7108 if (!(pglob.gl_flags & GLOB_MAGCHAR))
7109 goto nometa2;
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007110#endif
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007111 addglob(&pglob);
7112 globfree(&pglob);
7113 INT_ON;
7114 break;
7115 case GLOB_NOMATCH:
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007116 //nometa2:
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007117 globfree(&pglob);
7118 INT_ON;
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007119 nometa:
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007120 *exparg.lastp = str;
7121 rmescapes(str->text, 0);
7122 exparg.lastp = &str->next;
7123 break;
7124 default: /* GLOB_NOSPACE */
7125 globfree(&pglob);
7126 INT_ON;
7127 ash_msg_and_raise_error(bb_msg_memory_exhausted);
7128 }
7129 str = str->next;
7130 }
7131}
7132
7133#else
Denys Vlasenko514b51d2016-10-01 14:33:08 +02007134/* ENABLE_ASH_INTERNAL_GLOB: Homegrown globbing code. (dash also has both, uses homegrown one.) */
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007135
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007136/*
7137 * Do metacharacter (i.e. *, ?, [...]) expansion.
7138 */
7139static void
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007140expmeta(char *expdir, char *enddir, char *name)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007141{
7142 char *p;
7143 const char *cp;
7144 char *start;
7145 char *endname;
7146 int metaflag;
7147 struct stat statb;
7148 DIR *dirp;
7149 struct dirent *dp;
7150 int atend;
7151 int matchdot;
Ron Yorstonca25af92015-09-04 10:32:41 +01007152 int esc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007153
7154 metaflag = 0;
7155 start = name;
Ron Yorstonca25af92015-09-04 10:32:41 +01007156 for (p = name; esc = 0, *p; p += esc + 1) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007157 if (*p == '*' || *p == '?')
7158 metaflag = 1;
7159 else if (*p == '[') {
7160 char *q = p + 1;
7161 if (*q == '!')
7162 q++;
7163 for (;;) {
7164 if (*q == '\\')
7165 q++;
7166 if (*q == '/' || *q == '\0')
7167 break;
7168 if (*++q == ']') {
7169 metaflag = 1;
7170 break;
7171 }
7172 }
Ron Yorstonca25af92015-09-04 10:32:41 +01007173 } else {
7174 if (*p == '\\')
7175 esc++;
7176 if (p[esc] == '/') {
7177 if (metaflag)
7178 break;
7179 start = p + esc + 1;
7180 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007181 }
7182 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007183 if (metaflag == 0) { /* we've reached the end of the file name */
7184 if (enddir != expdir)
7185 metaflag++;
7186 p = name;
7187 do {
7188 if (*p == '\\')
7189 p++;
7190 *enddir++ = *p;
7191 } while (*p++);
7192 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
7193 addfname(expdir);
7194 return;
7195 }
7196 endname = p;
7197 if (name < start) {
7198 p = name;
7199 do {
7200 if (*p == '\\')
7201 p++;
7202 *enddir++ = *p++;
7203 } while (p < start);
7204 }
7205 if (enddir == expdir) {
7206 cp = ".";
7207 } else if (enddir == expdir + 1 && *expdir == '/') {
7208 cp = "/";
7209 } else {
7210 cp = expdir;
7211 enddir[-1] = '\0';
7212 }
7213 dirp = opendir(cp);
7214 if (dirp == NULL)
7215 return;
7216 if (enddir != expdir)
7217 enddir[-1] = '/';
7218 if (*endname == 0) {
7219 atend = 1;
7220 } else {
7221 atend = 0;
Ron Yorstonca25af92015-09-04 10:32:41 +01007222 *endname = '\0';
7223 endname += esc + 1;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007224 }
7225 matchdot = 0;
7226 p = start;
7227 if (*p == '\\')
7228 p++;
7229 if (*p == '.')
7230 matchdot++;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02007231 while (!pending_int && (dp = readdir(dirp)) != NULL) {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00007232 if (dp->d_name[0] == '.' && !matchdot)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007233 continue;
7234 if (pmatch(start, dp->d_name)) {
7235 if (atend) {
7236 strcpy(enddir, dp->d_name);
7237 addfname(expdir);
7238 } else {
7239 for (p = enddir, cp = dp->d_name; (*p++ = *cp++) != '\0';)
7240 continue;
7241 p[-1] = '/';
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007242 expmeta(expdir, p, endname);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007243 }
7244 }
7245 }
7246 closedir(dirp);
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00007247 if (!atend)
Ron Yorstonca25af92015-09-04 10:32:41 +01007248 endname[-esc - 1] = esc ? '\\' : '/';
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007249}
7250
7251static struct strlist *
7252msort(struct strlist *list, int len)
7253{
7254 struct strlist *p, *q = NULL;
7255 struct strlist **lpp;
7256 int half;
7257 int n;
7258
7259 if (len <= 1)
7260 return list;
7261 half = len >> 1;
7262 p = list;
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +00007263 for (n = half; --n >= 0;) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007264 q = p;
7265 p = p->next;
7266 }
7267 q->next = NULL; /* terminate first half of list */
7268 q = msort(list, half); /* sort first half of list */
7269 p = msort(p, len - half); /* sort second half */
7270 lpp = &list;
7271 for (;;) {
7272#if ENABLE_LOCALE_SUPPORT
7273 if (strcoll(p->text, q->text) < 0)
7274#else
7275 if (strcmp(p->text, q->text) < 0)
7276#endif
7277 {
7278 *lpp = p;
7279 lpp = &p->next;
7280 p = *lpp;
7281 if (p == NULL) {
7282 *lpp = q;
7283 break;
7284 }
7285 } else {
7286 *lpp = q;
7287 lpp = &q->next;
7288 q = *lpp;
7289 if (q == NULL) {
7290 *lpp = p;
7291 break;
7292 }
7293 }
7294 }
7295 return list;
7296}
7297
7298/*
7299 * Sort the results of file name expansion. It calculates the number of
7300 * strings to sort and then calls msort (short for merge sort) to do the
7301 * work.
7302 */
7303static struct strlist *
7304expsort(struct strlist *str)
7305{
7306 int len;
7307 struct strlist *sp;
7308
7309 len = 0;
7310 for (sp = str; sp; sp = sp->next)
7311 len++;
7312 return msort(str, len);
7313}
7314
7315static void
Denis Vlasenko68404f12008-03-17 09:00:54 +00007316expandmeta(struct strlist *str /*, int flag*/)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007317{
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00007318 static const char metachars[] ALIGN1 = {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007319 '*', '?', '[', 0
7320 };
7321 /* TODO - EXP_REDIR */
7322
7323 while (str) {
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007324 char *expdir;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007325 struct strlist **savelastp;
7326 struct strlist *sp;
7327 char *p;
7328
7329 if (fflag)
7330 goto nometa;
7331 if (!strpbrk(str->text, metachars))
7332 goto nometa;
7333 savelastp = exparg.lastp;
7334
7335 INT_OFF;
Ron Yorston549deab2015-05-18 09:57:51 +02007336 p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007337 {
7338 int i = strlen(str->text);
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007339//BUGGY estimation of how long expanded name can be
7340 expdir = ckmalloc(i < 2048 ? 2048 : i+1);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007341 }
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007342 expmeta(expdir, expdir, p);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007343 free(expdir);
7344 if (p != str->text)
7345 free(p);
7346 INT_ON;
7347 if (exparg.lastp == savelastp) {
7348 /*
7349 * no matches
7350 */
7351 nometa:
7352 *exparg.lastp = str;
Denys Vlasenkob6c84342009-08-29 20:23:20 +02007353 rmescapes(str->text, 0);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007354 exparg.lastp = &str->next;
7355 } else {
7356 *exparg.lastp = NULL;
7357 *savelastp = sp = expsort(*savelastp);
7358 while (sp->next != NULL)
7359 sp = sp->next;
7360 exparg.lastp = &sp->next;
7361 }
7362 str = str->next;
7363 }
7364}
Denys Vlasenko514b51d2016-10-01 14:33:08 +02007365#endif /* ENABLE_ASH_INTERNAL_GLOB */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007366
7367/*
7368 * Perform variable substitution and command substitution on an argument,
7369 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
7370 * perform splitting and file name expansion. When arglist is NULL, perform
7371 * here document expansion.
7372 */
7373static void
7374expandarg(union node *arg, struct arglist *arglist, int flag)
7375{
7376 struct strlist *sp;
7377 char *p;
7378
7379 argbackq = arg->narg.backquote;
7380 STARTSTACKSTR(expdest);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02007381 TRACE(("expandarg: argstr('%s',flags:%x)\n", arg->narg.text, flag));
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00007382 argstr(arg->narg.text, flag,
7383 /* var_str_list: */ arglist ? arglist->list : NULL);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007384 p = _STPUTC('\0', expdest);
7385 expdest = p - 1;
7386 if (arglist == NULL) {
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02007387 /* here document expanded */
7388 goto out;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007389 }
7390 p = grabstackstr(p);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02007391 TRACE(("expandarg: p:'%s'\n", p));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007392 exparg.lastp = &exparg.list;
7393 /*
7394 * TODO - EXP_REDIR
7395 */
7396 if (flag & EXP_FULL) {
7397 ifsbreakup(p, &exparg);
7398 *exparg.lastp = NULL;
7399 exparg.lastp = &exparg.list;
Denis Vlasenko68404f12008-03-17 09:00:54 +00007400 expandmeta(exparg.list /*, flag*/);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007401 } else {
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02007402 if (flag & EXP_REDIR) { /*XXX - for now, just remove escapes */
Denys Vlasenkob6c84342009-08-29 20:23:20 +02007403 rmescapes(p, 0);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02007404 TRACE(("expandarg: rmescapes:'%s'\n", p));
7405 }
Denis Vlasenko597906c2008-02-20 16:38:54 +00007406 sp = stzalloc(sizeof(*sp));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007407 sp->text = p;
7408 *exparg.lastp = sp;
7409 exparg.lastp = &sp->next;
7410 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007411 *exparg.lastp = NULL;
7412 if (exparg.list) {
7413 *arglist->lastp = exparg.list;
7414 arglist->lastp = exparg.lastp;
7415 }
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02007416
7417 out:
7418 ifsfree();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007419}
7420
7421/*
7422 * Expand shell variables and backquotes inside a here document.
7423 */
7424static void
7425expandhere(union node *arg, int fd)
7426{
Ron Yorston549deab2015-05-18 09:57:51 +02007427 expandarg(arg, (struct arglist *)NULL, EXP_QUOTED);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007428 full_write(fd, stackblock(), expdest - (char *)stackblock());
7429}
7430
7431/*
7432 * Returns true if the pattern matches the string.
7433 */
7434static int
7435patmatch(char *pattern, const char *string)
7436{
Ron Yorston549deab2015-05-18 09:57:51 +02007437 return pmatch(preglob(pattern, 0), string);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007438}
7439
7440/*
7441 * See if a pattern matches in a case statement.
7442 */
7443static int
7444casematch(union node *pattern, char *val)
7445{
7446 struct stackmark smark;
7447 int result;
7448
7449 setstackmark(&smark);
7450 argbackq = pattern->narg.backquote;
7451 STARTSTACKSTR(expdest);
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00007452 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE,
7453 /* var_str_list: */ NULL);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007454 STACKSTRNUL(expdest);
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02007455 ifsfree();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007456 result = patmatch(stackblock(), val);
7457 popstackmark(&smark);
7458 return result;
7459}
7460
7461
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007462/* ============ find_command */
7463
7464struct builtincmd {
7465 const char *name;
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02007466 int (*builtin)(int, char **) FAST_FUNC;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007467 /* unsigned flags; */
7468};
7469#define IS_BUILTIN_SPECIAL(b) ((b)->name[0] & 1)
Denis Vlasenkoe26b2782008-02-12 07:40:29 +00007470/* "regular" builtins always take precedence over commands,
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007471 * regardless of PATH=....%builtin... position */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007472#define IS_BUILTIN_REGULAR(b) ((b)->name[0] & 2)
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007473#define IS_BUILTIN_ASSIGN(b) ((b)->name[0] & 4)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007474
7475struct cmdentry {
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00007476 smallint cmdtype; /* CMDxxx */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007477 union param {
7478 int index;
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00007479 /* index >= 0 for commands without path (slashes) */
7480 /* (TODO: what exactly does the value mean? PATH position?) */
7481 /* index == -1 for commands with slashes */
7482 /* index == (-2 - applet_no) for NOFORK applets */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007483 const struct builtincmd *cmd;
7484 struct funcnode *func;
7485 } u;
7486};
7487/* values of cmdtype */
7488#define CMDUNKNOWN -1 /* no entry in table for command */
7489#define CMDNORMAL 0 /* command is an executable program */
7490#define CMDFUNCTION 1 /* command is a shell function */
7491#define CMDBUILTIN 2 /* command is a shell builtin */
7492
7493/* action to find_command() */
7494#define DO_ERR 0x01 /* prints errors */
7495#define DO_ABS 0x02 /* checks absolute paths */
7496#define DO_NOFUNC 0x04 /* don't return shell functions, for command */
7497#define DO_ALTPATH 0x08 /* using alternate path */
7498#define DO_ALTBLTIN 0x20 /* %builtin in alt. path */
7499
7500static void find_command(char *, struct cmdentry *, int, const char *);
7501
7502
7503/* ============ Hashing commands */
7504
7505/*
7506 * When commands are first encountered, they are entered in a hash table.
7507 * This ensures that a full path search will not have to be done for them
7508 * on each invocation.
7509 *
7510 * We should investigate converting to a linear search, even though that
7511 * would make the command name "hash" a misnomer.
7512 */
7513
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007514struct tblentry {
7515 struct tblentry *next; /* next entry in hash chain */
7516 union param param; /* definition of builtin function */
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00007517 smallint cmdtype; /* CMDxxx */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007518 char rehash; /* if set, cd done since entry created */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00007519 char cmdname[1]; /* name of command */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007520};
7521
Denis Vlasenko01631112007-12-16 17:20:38 +00007522static struct tblentry **cmdtable;
7523#define INIT_G_cmdtable() do { \
7524 cmdtable = xzalloc(CMDTABLESIZE * sizeof(cmdtable[0])); \
7525} while (0)
7526
7527static int builtinloc = -1; /* index in path of %builtin, or -1 */
7528
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007529
7530static void
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00007531tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) char *cmd, char **argv, char **envp)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007532{
Denis Vlasenko80d14be2007-04-10 23:03:30 +00007533#if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007534 if (applet_no >= 0) {
Denis Vlasenkob7304742008-10-20 08:15:51 +00007535 if (APPLET_IS_NOEXEC(applet_no)) {
Denys Vlasenko7df28bb2010-06-18 14:23:47 +02007536 clearenv();
Denis Vlasenkob7304742008-10-20 08:15:51 +00007537 while (*envp)
7538 putenv(*envp++);
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007539 run_applet_no_and_exit(applet_no, argv);
Denis Vlasenkob7304742008-10-20 08:15:51 +00007540 }
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007541 /* re-exec ourselves with the new arguments */
7542 execve(bb_busybox_exec_path, argv, envp);
7543 /* If they called chroot or otherwise made the binary no longer
7544 * executable, fall through */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007545 }
7546#endif
7547
7548 repeat:
7549#ifdef SYSV
7550 do {
7551 execve(cmd, argv, envp);
7552 } while (errno == EINTR);
7553#else
7554 execve(cmd, argv, envp);
7555#endif
Denys Vlasenko65a8b852016-10-26 22:29:11 +02007556 if (cmd != (char*) bb_busybox_exec_path && errno == ENOEXEC) {
Denys Vlasenkoaefe1c22011-03-07 12:02:40 +01007557 /* Run "cmd" as a shell script:
7558 * http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html
7559 * "If the execve() function fails with ENOEXEC, the shell
7560 * shall execute a command equivalent to having a shell invoked
7561 * with the command name as its first operand,
7562 * with any remaining arguments passed to the new shell"
7563 *
7564 * That is, do not use $SHELL, user's shell, or /bin/sh;
7565 * just call ourselves.
Denys Vlasenko2bef5262011-12-16 00:25:17 +01007566 *
7567 * Note that bash reads ~80 chars of the file, and if it sees
7568 * a zero byte before it sees newline, it doesn't try to
7569 * interpret it, but fails with "cannot execute binary file"
Denys Vlasenkocda6ea92011-12-16 00:44:36 +01007570 * message and exit code 126. For one, this prevents attempts
7571 * to interpret foreign ELF binaries as shell scripts.
Denys Vlasenkoaefe1c22011-03-07 12:02:40 +01007572 */
Denys Vlasenko65a8b852016-10-26 22:29:11 +02007573 argv[0] = cmd;
Denys Vlasenkoaefe1c22011-03-07 12:02:40 +01007574 cmd = (char*) bb_busybox_exec_path;
Denys Vlasenko65a8b852016-10-26 22:29:11 +02007575 /* NB: this is only possible because all callers of shellexec()
7576 * ensure that the argv[-1] slot exists!
7577 */
7578 argv--;
7579 argv[0] = (char*) "ash";
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007580 goto repeat;
7581 }
7582}
7583
7584/*
7585 * Exec a program. Never returns. If you change this routine, you may
7586 * have to change the find_command routine as well.
Denys Vlasenko65a8b852016-10-26 22:29:11 +02007587 * argv[-1] must exist and be writable! See tryexec() for why.
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007588 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00007589static void shellexec(char **, const char *, int) NORETURN;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007590static void
7591shellexec(char **argv, const char *path, int idx)
7592{
7593 char *cmdname;
7594 int e;
7595 char **envp;
7596 int exerrno;
Denys Vlasenko83f103b2011-12-20 06:10:35 +01007597 int applet_no = -1; /* used only by FEATURE_SH_STANDALONE */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007598
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +02007599 envp = listvars(VEXPORT, VUNSET, /*end:*/ NULL);
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007600 if (strchr(argv[0], '/') != NULL
Denis Vlasenko80d14be2007-04-10 23:03:30 +00007601#if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007602 || (applet_no = find_applet_by_name(argv[0])) >= 0
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007603#endif
7604 ) {
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00007605 tryexec(IF_FEATURE_SH_STANDALONE(applet_no,) argv[0], argv, envp);
Denys Vlasenko83f103b2011-12-20 06:10:35 +01007606 if (applet_no >= 0) {
7607 /* We tried execing ourself, but it didn't work.
7608 * Maybe /proc/self/exe doesn't exist?
7609 * Try $PATH search.
7610 */
7611 goto try_PATH;
7612 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007613 e = errno;
7614 } else {
Denys Vlasenko83f103b2011-12-20 06:10:35 +01007615 try_PATH:
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007616 e = ENOENT;
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02007617 while ((cmdname = path_advance(&path, argv[0])) != NULL) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007618 if (--idx < 0 && pathopt == NULL) {
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00007619 tryexec(IF_FEATURE_SH_STANDALONE(-1,) cmdname, argv, envp);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007620 if (errno != ENOENT && errno != ENOTDIR)
7621 e = errno;
7622 }
7623 stunalloc(cmdname);
7624 }
7625 }
7626
7627 /* Map to POSIX errors */
7628 switch (e) {
7629 case EACCES:
7630 exerrno = 126;
7631 break;
7632 case ENOENT:
7633 exerrno = 127;
7634 break;
7635 default:
7636 exerrno = 2;
7637 break;
7638 }
7639 exitstatus = exerrno;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02007640 TRACE(("shellexec failed for %s, errno %d, suppress_int %d\n",
7641 argv[0], e, suppress_int));
Denys Vlasenko061a0902016-10-25 17:24:25 +02007642 ash_msg_and_raise(EXEXIT, "%s: %s", argv[0], errmsg(e, "not found"));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007643 /* NOTREACHED */
7644}
7645
7646static void
7647printentry(struct tblentry *cmdp)
7648{
7649 int idx;
7650 const char *path;
7651 char *name;
7652
7653 idx = cmdp->param.index;
7654 path = pathval();
7655 do {
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02007656 name = path_advance(&path, cmdp->cmdname);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007657 stunalloc(name);
7658 } while (--idx >= 0);
7659 out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr));
7660}
7661
7662/*
7663 * Clear out command entries. The argument specifies the first entry in
7664 * PATH which has changed.
7665 */
7666static void
7667clearcmdentry(int firstchange)
7668{
7669 struct tblentry **tblp;
7670 struct tblentry **pp;
7671 struct tblentry *cmdp;
7672
7673 INT_OFF;
7674 for (tblp = cmdtable; tblp < &cmdtable[CMDTABLESIZE]; tblp++) {
7675 pp = tblp;
7676 while ((cmdp = *pp) != NULL) {
7677 if ((cmdp->cmdtype == CMDNORMAL &&
7678 cmdp->param.index >= firstchange)
7679 || (cmdp->cmdtype == CMDBUILTIN &&
7680 builtinloc >= firstchange)
7681 ) {
7682 *pp = cmdp->next;
7683 free(cmdp);
7684 } else {
7685 pp = &cmdp->next;
7686 }
7687 }
7688 }
7689 INT_ON;
7690}
7691
7692/*
7693 * Locate a command in the command hash table. If "add" is nonzero,
7694 * add the command to the table if it is not already present. The
7695 * variable "lastcmdentry" is set to point to the address of the link
7696 * pointing to the entry, so that delete_cmd_entry can delete the
7697 * entry.
7698 *
7699 * Interrupts must be off if called with add != 0.
7700 */
7701static struct tblentry **lastcmdentry;
7702
7703static struct tblentry *
7704cmdlookup(const char *name, int add)
7705{
7706 unsigned int hashval;
7707 const char *p;
7708 struct tblentry *cmdp;
7709 struct tblentry **pp;
7710
7711 p = name;
7712 hashval = (unsigned char)*p << 4;
7713 while (*p)
7714 hashval += (unsigned char)*p++;
7715 hashval &= 0x7FFF;
7716 pp = &cmdtable[hashval % CMDTABLESIZE];
7717 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
7718 if (strcmp(cmdp->cmdname, name) == 0)
7719 break;
7720 pp = &cmdp->next;
7721 }
7722 if (add && cmdp == NULL) {
Denis Vlasenkob07a4962008-06-22 13:16:23 +00007723 cmdp = *pp = ckzalloc(sizeof(struct tblentry)
7724 + strlen(name)
7725 /* + 1 - already done because
7726 * tblentry::cmdname is char[1] */);
Denis Vlasenko597906c2008-02-20 16:38:54 +00007727 /*cmdp->next = NULL; - ckzalloc did it */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007728 cmdp->cmdtype = CMDUNKNOWN;
7729 strcpy(cmdp->cmdname, name);
7730 }
7731 lastcmdentry = pp;
7732 return cmdp;
7733}
7734
7735/*
7736 * Delete the command entry returned on the last lookup.
7737 */
7738static void
7739delete_cmd_entry(void)
7740{
7741 struct tblentry *cmdp;
7742
7743 INT_OFF;
7744 cmdp = *lastcmdentry;
7745 *lastcmdentry = cmdp->next;
7746 if (cmdp->cmdtype == CMDFUNCTION)
7747 freefunc(cmdp->param.func);
7748 free(cmdp);
7749 INT_ON;
7750}
7751
7752/*
7753 * Add a new command entry, replacing any existing command entry for
7754 * the same name - except special builtins.
7755 */
7756static void
7757addcmdentry(char *name, struct cmdentry *entry)
7758{
7759 struct tblentry *cmdp;
7760
7761 cmdp = cmdlookup(name, 1);
7762 if (cmdp->cmdtype == CMDFUNCTION) {
7763 freefunc(cmdp->param.func);
7764 }
7765 cmdp->cmdtype = entry->cmdtype;
7766 cmdp->param = entry->u;
7767 cmdp->rehash = 0;
7768}
7769
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02007770static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00007771hashcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007772{
7773 struct tblentry **pp;
7774 struct tblentry *cmdp;
7775 int c;
7776 struct cmdentry entry;
7777 char *name;
7778
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007779 if (nextopt("r") != '\0') {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007780 clearcmdentry(0);
7781 return 0;
7782 }
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007783
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007784 if (*argptr == NULL) {
7785 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
7786 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
7787 if (cmdp->cmdtype == CMDNORMAL)
7788 printentry(cmdp);
7789 }
7790 }
7791 return 0;
7792 }
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007793
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007794 c = 0;
7795 while ((name = *argptr) != NULL) {
7796 cmdp = cmdlookup(name, 0);
7797 if (cmdp != NULL
7798 && (cmdp->cmdtype == CMDNORMAL
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007799 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))
7800 ) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007801 delete_cmd_entry();
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007802 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007803 find_command(name, &entry, DO_ERR, pathval());
7804 if (entry.cmdtype == CMDUNKNOWN)
7805 c = 1;
7806 argptr++;
7807 }
7808 return c;
7809}
7810
7811/*
7812 * Called when a cd is done. Marks all commands so the next time they
7813 * are executed they will be rehashed.
7814 */
7815static void
7816hashcd(void)
7817{
7818 struct tblentry **pp;
7819 struct tblentry *cmdp;
7820
7821 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
7822 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007823 if (cmdp->cmdtype == CMDNORMAL
7824 || (cmdp->cmdtype == CMDBUILTIN
Denys Vlasenkoe4dcba12010-10-28 18:57:19 +02007825 && !IS_BUILTIN_REGULAR(cmdp->param.cmd)
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007826 && builtinloc > 0)
7827 ) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007828 cmdp->rehash = 1;
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007829 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007830 }
7831 }
7832}
7833
7834/*
7835 * Fix command hash table when PATH changed.
7836 * Called before PATH is changed. The argument is the new value of PATH;
7837 * pathval() still returns the old value at this point.
7838 * Called with interrupts off.
7839 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02007840static void FAST_FUNC
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007841changepath(const char *new)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007842{
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007843 const char *old;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007844 int firstchange;
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007845 int idx;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007846 int idx_bltin;
7847
7848 old = pathval();
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007849 firstchange = 9999; /* assume no change */
7850 idx = 0;
7851 idx_bltin = -1;
7852 for (;;) {
7853 if (*old != *new) {
7854 firstchange = idx;
7855 if ((*old == '\0' && *new == ':')
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +02007856 || (*old == ':' && *new == '\0')
7857 ) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007858 firstchange++;
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +02007859 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007860 old = new; /* ignore subsequent differences */
7861 }
7862 if (*new == '\0')
7863 break;
7864 if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin"))
7865 idx_bltin = idx;
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007866 if (*new == ':')
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007867 idx++;
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +02007868 new++;
7869 old++;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007870 }
7871 if (builtinloc < 0 && idx_bltin >= 0)
7872 builtinloc = idx_bltin; /* zap builtins */
7873 if (builtinloc >= 0 && idx_bltin < 0)
7874 firstchange = 0;
7875 clearcmdentry(firstchange);
7876 builtinloc = idx_bltin;
7877}
Ron Yorston95ebcf72015-11-03 09:42:23 +00007878enum {
7879 TEOF,
7880 TNL,
7881 TREDIR,
7882 TWORD,
7883 TSEMI,
7884 TBACKGND,
7885 TAND,
7886 TOR,
7887 TPIPE,
7888 TLP,
7889 TRP,
7890 TENDCASE,
7891 TENDBQUOTE,
7892 TNOT,
7893 TCASE,
7894 TDO,
7895 TDONE,
7896 TELIF,
7897 TELSE,
7898 TESAC,
7899 TFI,
7900 TFOR,
7901#if ENABLE_ASH_BASH_COMPAT
7902 TFUNCTION,
7903#endif
7904 TIF,
7905 TIN,
7906 TTHEN,
7907 TUNTIL,
7908 TWHILE,
7909 TBEGIN,
7910 TEND
7911};
Denis Vlasenkob07a4962008-06-22 13:16:23 +00007912typedef smallint token_id_t;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007913
Denys Vlasenko888527c2016-10-02 16:54:17 +02007914/* Nth bit indicates if token marks the end of a list */
7915enum {
7916 tokendlist = 0
7917 /* 0 */ | (1u << TEOF)
7918 /* 1 */ | (0u << TNL)
7919 /* 2 */ | (0u << TREDIR)
7920 /* 3 */ | (0u << TWORD)
7921 /* 4 */ | (0u << TSEMI)
7922 /* 5 */ | (0u << TBACKGND)
7923 /* 6 */ | (0u << TAND)
7924 /* 7 */ | (0u << TOR)
7925 /* 8 */ | (0u << TPIPE)
7926 /* 9 */ | (0u << TLP)
7927 /* 10 */ | (1u << TRP)
7928 /* 11 */ | (1u << TENDCASE)
7929 /* 12 */ | (1u << TENDBQUOTE)
7930 /* 13 */ | (0u << TNOT)
7931 /* 14 */ | (0u << TCASE)
7932 /* 15 */ | (1u << TDO)
7933 /* 16 */ | (1u << TDONE)
7934 /* 17 */ | (1u << TELIF)
7935 /* 18 */ | (1u << TELSE)
7936 /* 19 */ | (1u << TESAC)
7937 /* 20 */ | (1u << TFI)
7938 /* 21 */ | (0u << TFOR)
7939#if ENABLE_ASH_BASH_COMPAT
7940 /* 22 */ | (0u << TFUNCTION)
Denys Vlasenko80729a42016-10-02 22:33:15 +02007941#endif
Denys Vlasenko888527c2016-10-02 16:54:17 +02007942 /* 23 */ | (0u << TIF)
7943 /* 24 */ | (0u << TIN)
7944 /* 25 */ | (1u << TTHEN)
7945 /* 26 */ | (0u << TUNTIL)
7946 /* 27 */ | (0u << TWHILE)
7947 /* 28 */ | (0u << TBEGIN)
7948 /* 29 */ | (1u << TEND)
7949 , /* thus far 29 bits used */
7950};
7951
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007952static const char *const tokname_array[] = {
Denys Vlasenko888527c2016-10-02 16:54:17 +02007953 "end of file",
7954 "newline",
7955 "redirection",
7956 "word",
7957 ";",
7958 "&",
7959 "&&",
7960 "||",
7961 "|",
7962 "(",
7963 ")",
7964 ";;",
7965 "`",
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007966#define KWDOFFSET 13
7967 /* the following are keywords */
Denys Vlasenko888527c2016-10-02 16:54:17 +02007968 "!",
7969 "case",
7970 "do",
7971 "done",
7972 "elif",
7973 "else",
7974 "esac",
7975 "fi",
7976 "for",
Ron Yorston95ebcf72015-11-03 09:42:23 +00007977#if ENABLE_ASH_BASH_COMPAT
Denys Vlasenko888527c2016-10-02 16:54:17 +02007978 "function",
Ron Yorston95ebcf72015-11-03 09:42:23 +00007979#endif
Denys Vlasenko888527c2016-10-02 16:54:17 +02007980 "if",
7981 "in",
7982 "then",
7983 "until",
7984 "while",
7985 "{",
7986 "}",
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007987};
7988
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007989/* Wrapper around strcmp for qsort/bsearch/... */
7990static int
7991pstrcmp(const void *a, const void *b)
7992{
Denys Vlasenko888527c2016-10-02 16:54:17 +02007993 return strcmp((char*)a, *(char**)b);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007994}
7995
7996static const char *const *
7997findkwd(const char *s)
7998{
7999 return bsearch(s, tokname_array + KWDOFFSET,
Denis Vlasenko80b8b392007-06-25 10:55:35 +00008000 ARRAY_SIZE(tokname_array) - KWDOFFSET,
8001 sizeof(tokname_array[0]), pstrcmp);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008002}
8003
8004/*
8005 * Locate and print what a word is...
8006 */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008007static int
Ron Yorston3f221112015-08-03 13:47:33 +01008008describe_command(char *command, const char *path, int describe_command_verbose)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008009{
8010 struct cmdentry entry;
8011 struct tblentry *cmdp;
8012#if ENABLE_ASH_ALIAS
8013 const struct alias *ap;
8014#endif
Ron Yorston3f221112015-08-03 13:47:33 +01008015
8016 path = path ? path : pathval();
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008017
8018 if (describe_command_verbose) {
8019 out1str(command);
8020 }
8021
8022 /* First look at the keywords */
8023 if (findkwd(command)) {
8024 out1str(describe_command_verbose ? " is a shell keyword" : command);
8025 goto out;
8026 }
8027
8028#if ENABLE_ASH_ALIAS
8029 /* Then look at the aliases */
8030 ap = lookupalias(command, 0);
8031 if (ap != NULL) {
Denis Vlasenko46846e22007-05-20 13:08:31 +00008032 if (!describe_command_verbose) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008033 out1str("alias ");
8034 printalias(ap);
8035 return 0;
8036 }
Denis Vlasenko46846e22007-05-20 13:08:31 +00008037 out1fmt(" is an alias for %s", ap->val);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008038 goto out;
8039 }
8040#endif
8041 /* Then check if it is a tracked alias */
8042 cmdp = cmdlookup(command, 0);
8043 if (cmdp != NULL) {
8044 entry.cmdtype = cmdp->cmdtype;
8045 entry.u = cmdp->param;
8046 } else {
8047 /* Finally use brute force */
8048 find_command(command, &entry, DO_ABS, path);
8049 }
8050
8051 switch (entry.cmdtype) {
8052 case CMDNORMAL: {
8053 int j = entry.u.index;
8054 char *p;
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00008055 if (j < 0) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008056 p = command;
8057 } else {
8058 do {
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02008059 p = path_advance(&path, command);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008060 stunalloc(p);
8061 } while (--j >= 0);
8062 }
8063 if (describe_command_verbose) {
8064 out1fmt(" is%s %s",
8065 (cmdp ? " a tracked alias for" : nullstr), p
8066 );
8067 } else {
8068 out1str(p);
8069 }
8070 break;
8071 }
8072
8073 case CMDFUNCTION:
8074 if (describe_command_verbose) {
8075 out1str(" is a shell function");
8076 } else {
8077 out1str(command);
8078 }
8079 break;
8080
8081 case CMDBUILTIN:
8082 if (describe_command_verbose) {
8083 out1fmt(" is a %sshell builtin",
8084 IS_BUILTIN_SPECIAL(entry.u.cmd) ?
8085 "special " : nullstr
8086 );
8087 } else {
8088 out1str(command);
8089 }
8090 break;
8091
8092 default:
8093 if (describe_command_verbose) {
8094 out1str(": not found\n");
8095 }
8096 return 127;
8097 }
8098 out:
Denys Vlasenko285ad152009-12-04 23:02:27 +01008099 out1str("\n");
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008100 return 0;
8101}
8102
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02008103static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00008104typecmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008105{
Denis Vlasenko46846e22007-05-20 13:08:31 +00008106 int i = 1;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008107 int err = 0;
Denis Vlasenko46846e22007-05-20 13:08:31 +00008108 int verbose = 1;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008109
Denis Vlasenko46846e22007-05-20 13:08:31 +00008110 /* type -p ... ? (we don't bother checking for 'p') */
Denis Vlasenko1fc62382007-06-25 22:55:34 +00008111 if (argv[1] && argv[1][0] == '-') {
Denis Vlasenko46846e22007-05-20 13:08:31 +00008112 i++;
8113 verbose = 0;
8114 }
Denis Vlasenko68404f12008-03-17 09:00:54 +00008115 while (argv[i]) {
Ron Yorston3f221112015-08-03 13:47:33 +01008116 err |= describe_command(argv[i++], NULL, verbose);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008117 }
8118 return err;
8119}
8120
8121#if ENABLE_ASH_CMDCMD
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008122/* Is it "command [-p] PROG ARGS" bltin, no other opts? Return ptr to "PROG" if yes */
8123static char **
8124parse_command_args(char **argv, const char **path)
8125{
8126 char *cp, c;
8127
8128 for (;;) {
8129 cp = *++argv;
8130 if (!cp)
8131 return NULL;
8132 if (*cp++ != '-')
8133 break;
8134 c = *cp++;
8135 if (!c)
8136 break;
8137 if (c == '-' && !*cp) {
8138 if (!*++argv)
8139 return NULL;
8140 break;
8141 }
8142 do {
8143 switch (c) {
8144 case 'p':
8145 *path = bb_default_path;
8146 break;
8147 default:
8148 /* run 'typecmd' for other options */
8149 return NULL;
8150 }
8151 c = *cp++;
8152 } while (c);
8153 }
8154 return argv;
8155}
8156
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02008157static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00008158commandcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008159{
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008160 char *cmd;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008161 int c;
8162 enum {
8163 VERIFY_BRIEF = 1,
8164 VERIFY_VERBOSE = 2,
8165 } verify = 0;
Ron Yorston3f221112015-08-03 13:47:33 +01008166 const char *path = NULL;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008167
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008168 /* "command [-p] PROG ARGS" (that is, without -V or -v)
8169 * never reaches this function.
8170 */
8171
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008172 while ((c = nextopt("pvV")) != '\0')
8173 if (c == 'V')
8174 verify |= VERIFY_VERBOSE;
8175 else if (c == 'v')
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008176 /*verify |= VERIFY_BRIEF*/;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008177#if DEBUG
8178 else if (c != 'p')
8179 abort();
8180#endif
Ron Yorston3f221112015-08-03 13:47:33 +01008181 else
8182 path = bb_default_path;
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008183
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00008184 /* Mimic bash: just "command -v" doesn't complain, it's a nop */
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008185 cmd = *argptr;
8186 if (/*verify && */ cmd)
8187 return describe_command(cmd, path, verify /* - VERIFY_BRIEF*/);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008188
8189 return 0;
8190}
8191#endif
8192
8193
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008194/*static int funcblocksize; // size of structures in function */
8195/*static int funcstringsize; // size of strings in node */
Denis Vlasenko340299a2008-11-21 10:36:36 +00008196static void *funcblock; /* block to allocate function from */
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008197static char *funcstring_end; /* end of block to allocate strings from */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008198
Eric Andersencb57d552001-06-28 07:25:16 +00008199/* flags in argument to evaltree */
Denis Vlasenko340299a2008-11-21 10:36:36 +00008200#define EV_EXIT 01 /* exit after evaluating tree */
8201#define EV_TESTED 02 /* exit status is checked; ignore -e flag */
Eric Andersencb57d552001-06-28 07:25:16 +00008202
Denys Vlasenko3e134eb2016-04-22 18:09:21 +02008203static const uint8_t nodesize[N_NUMBER] ALIGN1 = {
Denis Vlasenko340299a2008-11-21 10:36:36 +00008204 [NCMD ] = SHELL_ALIGN(sizeof(struct ncmd)),
8205 [NPIPE ] = SHELL_ALIGN(sizeof(struct npipe)),
8206 [NREDIR ] = SHELL_ALIGN(sizeof(struct nredir)),
8207 [NBACKGND ] = SHELL_ALIGN(sizeof(struct nredir)),
8208 [NSUBSHELL] = SHELL_ALIGN(sizeof(struct nredir)),
8209 [NAND ] = SHELL_ALIGN(sizeof(struct nbinary)),
8210 [NOR ] = SHELL_ALIGN(sizeof(struct nbinary)),
8211 [NSEMI ] = SHELL_ALIGN(sizeof(struct nbinary)),
8212 [NIF ] = SHELL_ALIGN(sizeof(struct nif)),
8213 [NWHILE ] = SHELL_ALIGN(sizeof(struct nbinary)),
8214 [NUNTIL ] = SHELL_ALIGN(sizeof(struct nbinary)),
8215 [NFOR ] = SHELL_ALIGN(sizeof(struct nfor)),
8216 [NCASE ] = SHELL_ALIGN(sizeof(struct ncase)),
8217 [NCLIST ] = SHELL_ALIGN(sizeof(struct nclist)),
8218 [NDEFUN ] = SHELL_ALIGN(sizeof(struct narg)),
8219 [NARG ] = SHELL_ALIGN(sizeof(struct narg)),
8220 [NTO ] = SHELL_ALIGN(sizeof(struct nfile)),
Denis Vlasenkocc5feab2008-11-22 01:32:40 +00008221#if ENABLE_ASH_BASH_COMPAT
Denis Vlasenko340299a2008-11-21 10:36:36 +00008222 [NTO2 ] = SHELL_ALIGN(sizeof(struct nfile)),
Denis Vlasenkocc5feab2008-11-22 01:32:40 +00008223#endif
Denis Vlasenko340299a2008-11-21 10:36:36 +00008224 [NCLOBBER ] = SHELL_ALIGN(sizeof(struct nfile)),
8225 [NFROM ] = SHELL_ALIGN(sizeof(struct nfile)),
8226 [NFROMTO ] = SHELL_ALIGN(sizeof(struct nfile)),
8227 [NAPPEND ] = SHELL_ALIGN(sizeof(struct nfile)),
8228 [NTOFD ] = SHELL_ALIGN(sizeof(struct ndup)),
8229 [NFROMFD ] = SHELL_ALIGN(sizeof(struct ndup)),
8230 [NHERE ] = SHELL_ALIGN(sizeof(struct nhere)),
8231 [NXHERE ] = SHELL_ALIGN(sizeof(struct nhere)),
8232 [NNOT ] = SHELL_ALIGN(sizeof(struct nnot)),
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008233};
8234
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008235static int calcsize(int funcblocksize, union node *n);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008236
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008237static int
8238sizenodelist(int funcblocksize, struct nodelist *lp)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008239{
8240 while (lp) {
8241 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008242 funcblocksize = calcsize(funcblocksize, lp->n);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008243 lp = lp->next;
8244 }
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008245 return funcblocksize;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008246}
8247
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008248static int
8249calcsize(int funcblocksize, union node *n)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008250{
8251 if (n == NULL)
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008252 return funcblocksize;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008253 funcblocksize += nodesize[n->type];
8254 switch (n->type) {
8255 case NCMD:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008256 funcblocksize = calcsize(funcblocksize, n->ncmd.redirect);
8257 funcblocksize = calcsize(funcblocksize, n->ncmd.args);
8258 funcblocksize = calcsize(funcblocksize, n->ncmd.assign);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008259 break;
8260 case NPIPE:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008261 funcblocksize = sizenodelist(funcblocksize, n->npipe.cmdlist);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008262 break;
8263 case NREDIR:
8264 case NBACKGND:
8265 case NSUBSHELL:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008266 funcblocksize = calcsize(funcblocksize, n->nredir.redirect);
8267 funcblocksize = calcsize(funcblocksize, n->nredir.n);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008268 break;
8269 case NAND:
8270 case NOR:
8271 case NSEMI:
8272 case NWHILE:
8273 case NUNTIL:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008274 funcblocksize = calcsize(funcblocksize, n->nbinary.ch2);
8275 funcblocksize = calcsize(funcblocksize, n->nbinary.ch1);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008276 break;
8277 case NIF:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008278 funcblocksize = calcsize(funcblocksize, n->nif.elsepart);
8279 funcblocksize = calcsize(funcblocksize, n->nif.ifpart);
8280 funcblocksize = calcsize(funcblocksize, n->nif.test);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008281 break;
8282 case NFOR:
Denys Vlasenko561639a2016-10-07 04:28:33 +02008283 funcblocksize += SHELL_ALIGN(strlen(n->nfor.var) + 1); /* was funcstringsize += ... */
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008284 funcblocksize = calcsize(funcblocksize, n->nfor.body);
8285 funcblocksize = calcsize(funcblocksize, n->nfor.args);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008286 break;
8287 case NCASE:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008288 funcblocksize = calcsize(funcblocksize, n->ncase.cases);
8289 funcblocksize = calcsize(funcblocksize, n->ncase.expr);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008290 break;
8291 case NCLIST:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008292 funcblocksize = calcsize(funcblocksize, n->nclist.body);
8293 funcblocksize = calcsize(funcblocksize, n->nclist.pattern);
8294 funcblocksize = calcsize(funcblocksize, n->nclist.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008295 break;
8296 case NDEFUN:
8297 case NARG:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008298 funcblocksize = sizenodelist(funcblocksize, n->narg.backquote);
Denys Vlasenko561639a2016-10-07 04:28:33 +02008299 funcblocksize += SHELL_ALIGN(strlen(n->narg.text) + 1); /* was funcstringsize += ... */
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008300 funcblocksize = calcsize(funcblocksize, n->narg.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008301 break;
8302 case NTO:
Denis Vlasenko559691a2008-10-05 18:39:31 +00008303#if ENABLE_ASH_BASH_COMPAT
8304 case NTO2:
8305#endif
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008306 case NCLOBBER:
8307 case NFROM:
8308 case NFROMTO:
8309 case NAPPEND:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008310 funcblocksize = calcsize(funcblocksize, n->nfile.fname);
8311 funcblocksize = calcsize(funcblocksize, n->nfile.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008312 break;
8313 case NTOFD:
8314 case NFROMFD:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008315 funcblocksize = calcsize(funcblocksize, n->ndup.vname);
8316 funcblocksize = calcsize(funcblocksize, n->ndup.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008317 break;
8318 case NHERE:
8319 case NXHERE:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008320 funcblocksize = calcsize(funcblocksize, n->nhere.doc);
8321 funcblocksize = calcsize(funcblocksize, n->nhere.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008322 break;
8323 case NNOT:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008324 funcblocksize = calcsize(funcblocksize, n->nnot.com);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008325 break;
8326 };
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008327 return funcblocksize;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008328}
8329
8330static char *
8331nodeckstrdup(char *s)
8332{
Denys Vlasenko561639a2016-10-07 04:28:33 +02008333 funcstring_end -= SHELL_ALIGN(strlen(s) + 1);
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008334 return strcpy(funcstring_end, s);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008335}
8336
8337static union node *copynode(union node *);
8338
8339static struct nodelist *
8340copynodelist(struct nodelist *lp)
8341{
8342 struct nodelist *start;
8343 struct nodelist **lpp;
8344
8345 lpp = &start;
8346 while (lp) {
8347 *lpp = funcblock;
8348 funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist));
8349 (*lpp)->n = copynode(lp->n);
8350 lp = lp->next;
8351 lpp = &(*lpp)->next;
8352 }
8353 *lpp = NULL;
8354 return start;
8355}
8356
8357static union node *
8358copynode(union node *n)
8359{
8360 union node *new;
8361
8362 if (n == NULL)
8363 return NULL;
8364 new = funcblock;
8365 funcblock = (char *) funcblock + nodesize[n->type];
8366
8367 switch (n->type) {
8368 case NCMD:
8369 new->ncmd.redirect = copynode(n->ncmd.redirect);
8370 new->ncmd.args = copynode(n->ncmd.args);
8371 new->ncmd.assign = copynode(n->ncmd.assign);
8372 break;
8373 case NPIPE:
8374 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00008375 new->npipe.pipe_backgnd = n->npipe.pipe_backgnd;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008376 break;
8377 case NREDIR:
8378 case NBACKGND:
8379 case NSUBSHELL:
8380 new->nredir.redirect = copynode(n->nredir.redirect);
8381 new->nredir.n = copynode(n->nredir.n);
8382 break;
8383 case NAND:
8384 case NOR:
8385 case NSEMI:
8386 case NWHILE:
8387 case NUNTIL:
8388 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8389 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8390 break;
8391 case NIF:
8392 new->nif.elsepart = copynode(n->nif.elsepart);
8393 new->nif.ifpart = copynode(n->nif.ifpart);
8394 new->nif.test = copynode(n->nif.test);
8395 break;
8396 case NFOR:
8397 new->nfor.var = nodeckstrdup(n->nfor.var);
8398 new->nfor.body = copynode(n->nfor.body);
8399 new->nfor.args = copynode(n->nfor.args);
8400 break;
8401 case NCASE:
8402 new->ncase.cases = copynode(n->ncase.cases);
8403 new->ncase.expr = copynode(n->ncase.expr);
8404 break;
8405 case NCLIST:
8406 new->nclist.body = copynode(n->nclist.body);
8407 new->nclist.pattern = copynode(n->nclist.pattern);
8408 new->nclist.next = copynode(n->nclist.next);
8409 break;
8410 case NDEFUN:
8411 case NARG:
8412 new->narg.backquote = copynodelist(n->narg.backquote);
8413 new->narg.text = nodeckstrdup(n->narg.text);
8414 new->narg.next = copynode(n->narg.next);
8415 break;
8416 case NTO:
Denis Vlasenko559691a2008-10-05 18:39:31 +00008417#if ENABLE_ASH_BASH_COMPAT
8418 case NTO2:
8419#endif
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008420 case NCLOBBER:
8421 case NFROM:
8422 case NFROMTO:
8423 case NAPPEND:
8424 new->nfile.fname = copynode(n->nfile.fname);
8425 new->nfile.fd = n->nfile.fd;
8426 new->nfile.next = copynode(n->nfile.next);
8427 break;
8428 case NTOFD:
8429 case NFROMFD:
8430 new->ndup.vname = copynode(n->ndup.vname);
8431 new->ndup.dupfd = n->ndup.dupfd;
8432 new->ndup.fd = n->ndup.fd;
8433 new->ndup.next = copynode(n->ndup.next);
8434 break;
8435 case NHERE:
8436 case NXHERE:
8437 new->nhere.doc = copynode(n->nhere.doc);
8438 new->nhere.fd = n->nhere.fd;
8439 new->nhere.next = copynode(n->nhere.next);
8440 break;
8441 case NNOT:
8442 new->nnot.com = copynode(n->nnot.com);
8443 break;
8444 };
8445 new->type = n->type;
8446 return new;
8447}
8448
8449/*
8450 * Make a copy of a parse tree.
8451 */
8452static struct funcnode *
8453copyfunc(union node *n)
8454{
8455 struct funcnode *f;
8456 size_t blocksize;
8457
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008458 /*funcstringsize = 0;*/
8459 blocksize = offsetof(struct funcnode, n) + calcsize(0, n);
8460 f = ckzalloc(blocksize /* + funcstringsize */);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008461 funcblock = (char *) f + offsetof(struct funcnode, n);
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008462 funcstring_end = (char *) f + blocksize;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008463 copynode(n);
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008464 /* f->count = 0; - ckzalloc did it */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008465 return f;
8466}
8467
8468/*
8469 * Define a shell function.
8470 */
8471static void
Denys Vlasenko7aec8682016-10-25 20:26:02 +02008472defun(union node *func)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008473{
8474 struct cmdentry entry;
8475
8476 INT_OFF;
8477 entry.cmdtype = CMDFUNCTION;
8478 entry.u.func = copyfunc(func);
Denys Vlasenko7aec8682016-10-25 20:26:02 +02008479 addcmdentry(func->narg.text, &entry);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008480 INT_ON;
8481}
8482
Denis Vlasenko4b875702009-03-19 13:30:04 +00008483/* Reasons for skipping commands (see comment on breakcmd routine) */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008484#define SKIPBREAK (1 << 0)
8485#define SKIPCONT (1 << 1)
8486#define SKIPFUNC (1 << 2)
Denis Vlasenko4b875702009-03-19 13:30:04 +00008487static smallint evalskip; /* set to SKIPxxx if we are skipping commands */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008488static int skipcount; /* number of levels to skip */
8489static int funcnest; /* depth of function calls */
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +00008490static int loopnest; /* current loop nesting level */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008491
Denis Vlasenko4b875702009-03-19 13:30:04 +00008492/* Forward decl way out to parsing code - dotrap needs it */
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02008493static int evalstring(char *s, int flags);
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008494
Denis Vlasenko4b875702009-03-19 13:30:04 +00008495/* Called to execute a trap.
8496 * Single callsite - at the end of evaltree().
Denys Vlasenkob563f622010-09-25 17:15:13 +02008497 * If we return non-zero, evaltree raises EXEXIT exception.
Denis Vlasenko4b875702009-03-19 13:30:04 +00008498 *
8499 * Perhaps we should avoid entering new trap handlers
8500 * while we are executing a trap handler. [is it a TODO?]
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008501 */
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008502static void
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008503dotrap(void)
8504{
Denis Vlasenko4b875702009-03-19 13:30:04 +00008505 uint8_t *g;
8506 int sig;
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008507 uint8_t last_status;
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008508
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008509 if (!pending_sig)
8510 return;
8511
8512 last_status = exitstatus;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02008513 pending_sig = 0;
Denys Vlasenkode892052016-10-02 01:49:13 +02008514 barrier();
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008515
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008516 TRACE(("dotrap entered\n"));
Denis Vlasenko4b875702009-03-19 13:30:04 +00008517 for (sig = 1, g = gotsig; sig < NSIG; sig++, g++) {
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008518 char *p;
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008519
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008520 if (!*g)
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008521 continue;
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008522
8523 if (evalskip) {
8524 pending_sig = sig;
8525 break;
8526 }
8527
8528 p = trap[sig];
Denis Vlasenko4b875702009-03-19 13:30:04 +00008529 /* non-trapped SIGINT is handled separately by raise_interrupt,
8530 * don't upset it by resetting gotsig[SIGINT-1] */
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008531 if (sig == SIGINT && !p)
Denis Vlasenko4b875702009-03-19 13:30:04 +00008532 continue;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008533
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008534 TRACE(("sig %d is active, will run handler '%s'\n", sig, p));
Denis Vlasenko4b875702009-03-19 13:30:04 +00008535 *g = 0;
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008536 if (!p)
Denis Vlasenko4b875702009-03-19 13:30:04 +00008537 continue;
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008538 evalstring(p, 0);
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008539 }
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008540 exitstatus = last_status;
8541 TRACE(("dotrap returns\n"));
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008542}
8543
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00008544/* forward declarations - evaluation is fairly recursive business... */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008545static int evalloop(union node *, int);
8546static int evalfor(union node *, int);
8547static int evalcase(union node *, int);
8548static int evalsubshell(union node *, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008549static void expredir(union node *);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008550static int evalpipe(union node *, int);
8551static int evalcommand(union node *, int);
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02008552static int evalbltin(const struct builtincmd *, int, char **, int);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008553static void prehash(union node *);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008554
Eric Andersen62483552001-07-10 06:09:16 +00008555/*
Eric Andersenc470f442003-07-28 09:56:35 +00008556 * Evaluate a parse tree. The value is left in the global variable
8557 * exitstatus.
Eric Andersen62483552001-07-10 06:09:16 +00008558 */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008559static int
Eric Andersenc470f442003-07-28 09:56:35 +00008560evaltree(union node *n, int flags)
Eric Andersen62483552001-07-10 06:09:16 +00008561{
Eric Andersenc470f442003-07-28 09:56:35 +00008562 int checkexit = 0;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008563 int (*evalfn)(union node *, int);
8564 int status = 0;
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008565
Eric Andersenc470f442003-07-28 09:56:35 +00008566 if (n == NULL) {
8567 TRACE(("evaltree(NULL) called\n"));
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02008568 goto out;
Eric Andersen62483552001-07-10 06:09:16 +00008569 }
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008570 TRACE(("evaltree(%p: %d, %d) called\n", n, n->type, flags));
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008571
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008572 dotrap();
8573
Eric Andersenc470f442003-07-28 09:56:35 +00008574 switch (n->type) {
8575 default:
Denis Vlasenkoa7189f02006-11-17 20:29:00 +00008576#if DEBUG
Eric Andersenc470f442003-07-28 09:56:35 +00008577 out1fmt("Node type = %d\n", n->type);
Denys Vlasenko8131eea2009-11-02 14:19:51 +01008578 fflush_all();
Eric Andersenc470f442003-07-28 09:56:35 +00008579 break;
8580#endif
8581 case NNOT:
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008582 status = !evaltree(n->nnot.com, EV_TESTED);
Eric Andersenc470f442003-07-28 09:56:35 +00008583 goto setstatus;
8584 case NREDIR:
8585 expredir(n->nredir.redirect);
8586 status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
8587 if (!status) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008588 status = evaltree(n->nredir.n, flags & EV_TESTED);
Eric Andersenc470f442003-07-28 09:56:35 +00008589 }
Denys Vlasenkoeaf94362016-10-25 21:46:03 +02008590 if (n->nredir.redirect)
8591 popredir(/*drop:*/ 0, /*restore:*/ 0 /* not sure */);
Eric Andersenc470f442003-07-28 09:56:35 +00008592 goto setstatus;
8593 case NCMD:
8594 evalfn = evalcommand;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008595 checkexit:
Eric Andersenc470f442003-07-28 09:56:35 +00008596 if (eflag && !(flags & EV_TESTED))
8597 checkexit = ~0;
8598 goto calleval;
8599 case NFOR:
8600 evalfn = evalfor;
8601 goto calleval;
8602 case NWHILE:
8603 case NUNTIL:
8604 evalfn = evalloop;
8605 goto calleval;
8606 case NSUBSHELL:
8607 case NBACKGND:
8608 evalfn = evalsubshell;
Denys Vlasenkocf98b0c2016-10-25 18:19:39 +02008609 goto checkexit;
Eric Andersenc470f442003-07-28 09:56:35 +00008610 case NPIPE:
8611 evalfn = evalpipe;
8612 goto checkexit;
8613 case NCASE:
8614 evalfn = evalcase;
8615 goto calleval;
8616 case NAND:
8617 case NOR:
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008618 case NSEMI: {
8619
Eric Andersenc470f442003-07-28 09:56:35 +00008620#if NAND + 1 != NOR
8621#error NAND + 1 != NOR
8622#endif
8623#if NOR + 1 != NSEMI
8624#error NOR + 1 != NSEMI
8625#endif
Denis Vlasenko87d5fd92008-07-26 13:48:35 +00008626 unsigned is_or = n->type - NAND;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008627 status = evaltree(
Eric Andersenc470f442003-07-28 09:56:35 +00008628 n->nbinary.ch1,
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008629 (flags | ((is_or >> 1) - 1)) & EV_TESTED
Eric Andersenc470f442003-07-28 09:56:35 +00008630 );
Denys Vlasenkobc1a0082016-10-02 15:31:33 +02008631 if ((!status) == is_or || evalskip)
Eric Andersenc470f442003-07-28 09:56:35 +00008632 break;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008633 n = n->nbinary.ch2;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008634 evaln:
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008635 evalfn = evaltree;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008636 calleval:
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008637 status = evalfn(n, flags);
8638 goto setstatus;
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008639 }
Eric Andersenc470f442003-07-28 09:56:35 +00008640 case NIF:
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008641 status = evaltree(n->nif.test, EV_TESTED);
Eric Andersenc470f442003-07-28 09:56:35 +00008642 if (evalskip)
8643 break;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008644 if (!status) {
Eric Andersenc470f442003-07-28 09:56:35 +00008645 n = n->nif.ifpart;
8646 goto evaln;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008647 }
8648 if (n->nif.elsepart) {
Eric Andersenc470f442003-07-28 09:56:35 +00008649 n = n->nif.elsepart;
8650 goto evaln;
8651 }
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008652 status = 0;
8653 goto setstatus;
Eric Andersenc470f442003-07-28 09:56:35 +00008654 case NDEFUN:
Denys Vlasenko7aec8682016-10-25 20:26:02 +02008655 defun(n);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008656 /* Not necessary. To test it:
8657 * "false; f() { qwerty; }; echo $?" should print 0.
8658 */
8659 /* status = 0; */
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008660 setstatus:
Eric Andersenc470f442003-07-28 09:56:35 +00008661 exitstatus = status;
8662 break;
8663 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008664 out:
Denys Vlasenkob563f622010-09-25 17:15:13 +02008665 /* Order of checks below is important:
8666 * signal handlers trigger before exit caused by "set -e".
8667 */
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008668 dotrap();
8669
8670 if (checkexit & status)
Denis Vlasenkob012b102007-02-19 22:43:01 +00008671 raise_exception(EXEXIT);
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008672 if (flags & EV_EXIT)
8673 raise_exception(EXEXIT);
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008674
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008675 TRACE(("leaving evaltree (no interrupts)\n"));
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008676 return exitstatus;
Eric Andersen62483552001-07-10 06:09:16 +00008677}
8678
Eric Andersenc470f442003-07-28 09:56:35 +00008679#if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3)
8680static
8681#endif
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008682int evaltreenr(union node *, int) __attribute__ ((alias("evaltree"),__noreturn__));
Eric Andersenc470f442003-07-28 09:56:35 +00008683
Denys Vlasenko37dc08b2016-10-02 04:38:07 +02008684static int
8685skiploop(void)
Denys Vlasenko35ec8182016-10-01 19:56:52 +02008686{
8687 int skip = evalskip;
8688
8689 switch (skip) {
8690 case 0:
8691 break;
8692 case SKIPBREAK:
8693 case SKIPCONT:
8694 if (--skipcount <= 0) {
8695 evalskip = 0;
8696 break;
8697 }
8698 skip = SKIPBREAK;
8699 break;
8700 }
8701 return skip;
8702}
8703
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008704static int
Eric Andersenc470f442003-07-28 09:56:35 +00008705evalloop(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00008706{
Denys Vlasenko35ec8182016-10-01 19:56:52 +02008707 int skip;
Eric Andersencb57d552001-06-28 07:25:16 +00008708 int status;
8709
8710 loopnest++;
8711 status = 0;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008712 flags &= EV_TESTED;
Denys Vlasenko35ec8182016-10-01 19:56:52 +02008713 do {
Eric Andersenc470f442003-07-28 09:56:35 +00008714 int i;
8715
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008716 i = evaltree(n->nbinary.ch1, EV_TESTED);
Denys Vlasenko35ec8182016-10-01 19:56:52 +02008717 skip = skiploop();
8718 if (skip == SKIPFUNC)
8719 status = i;
8720 if (skip)
8721 continue;
Eric Andersenc470f442003-07-28 09:56:35 +00008722 if (n->type != NWHILE)
8723 i = !i;
8724 if (i != 0)
8725 break;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008726 status = evaltree(n->nbinary.ch2, flags);
Denys Vlasenko35ec8182016-10-01 19:56:52 +02008727 skip = skiploop();
8728 } while (!(skip & ~SKIPCONT));
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008729 loopnest--;
8730
8731 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00008732}
8733
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008734static int
Eric Andersenc470f442003-07-28 09:56:35 +00008735evalfor(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00008736{
8737 struct arglist arglist;
8738 union node *argp;
8739 struct strlist *sp;
8740 struct stackmark smark;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008741 int status = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00008742
8743 setstackmark(&smark);
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00008744 arglist.list = NULL;
Eric Andersencb57d552001-06-28 07:25:16 +00008745 arglist.lastp = &arglist.list;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008746 for (argp = n->nfor.args; argp; argp = argp->narg.next) {
Ron Yorston549deab2015-05-18 09:57:51 +02008747 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
Eric Andersencb57d552001-06-28 07:25:16 +00008748 }
8749 *arglist.lastp = NULL;
8750
Eric Andersencb57d552001-06-28 07:25:16 +00008751 loopnest++;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008752 flags &= EV_TESTED;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008753 for (sp = arglist.list; sp; sp = sp->next) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02008754 setvar0(n->nfor.var, sp->text);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008755 status = evaltree(n->nfor.body, flags);
Denys Vlasenko35ec8182016-10-01 19:56:52 +02008756 if (skiploop() & ~SKIPCONT)
Eric Andersencb57d552001-06-28 07:25:16 +00008757 break;
Eric Andersencb57d552001-06-28 07:25:16 +00008758 }
8759 loopnest--;
Eric Andersencb57d552001-06-28 07:25:16 +00008760 popstackmark(&smark);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008761
8762 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00008763}
8764
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008765static int
Eric Andersenc470f442003-07-28 09:56:35 +00008766evalcase(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00008767{
8768 union node *cp;
8769 union node *patp;
8770 struct arglist arglist;
8771 struct stackmark smark;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008772 int status = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00008773
8774 setstackmark(&smark);
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00008775 arglist.list = NULL;
Eric Andersencb57d552001-06-28 07:25:16 +00008776 arglist.lastp = &arglist.list;
Eric Andersencb57d552001-06-28 07:25:16 +00008777 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008778 for (cp = n->ncase.cases; cp && evalskip == 0; cp = cp->nclist.next) {
8779 for (patp = cp->nclist.pattern; patp; patp = patp->narg.next) {
Eric Andersencb57d552001-06-28 07:25:16 +00008780 if (casematch(patp, arglist.list->text)) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008781 /* Ensure body is non-empty as otherwise
8782 * EV_EXIT may prevent us from setting the
8783 * exit status.
8784 */
8785 if (evalskip == 0 && cp->nclist.body) {
8786 status = evaltree(cp->nclist.body, flags);
Eric Andersencb57d552001-06-28 07:25:16 +00008787 }
8788 goto out;
8789 }
8790 }
8791 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008792 out:
Eric Andersencb57d552001-06-28 07:25:16 +00008793 popstackmark(&smark);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008794
8795 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00008796}
8797
Eric Andersenc470f442003-07-28 09:56:35 +00008798/*
8799 * Kick off a subshell to evaluate a tree.
8800 */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008801static int
Eric Andersenc470f442003-07-28 09:56:35 +00008802evalsubshell(union node *n, int flags)
8803{
8804 struct job *jp;
8805 int backgnd = (n->type == NBACKGND);
8806 int status;
8807
8808 expredir(n->nredir.redirect);
Denys Vlasenko238bf182010-05-18 15:49:07 +02008809 if (!backgnd && (flags & EV_EXIT) && !may_have_traps)
Eric Andersenc470f442003-07-28 09:56:35 +00008810 goto nofork;
Denis Vlasenkob012b102007-02-19 22:43:01 +00008811 INT_OFF;
Denis Vlasenko68404f12008-03-17 09:00:54 +00008812 jp = makejob(/*n,*/ 1);
Eric Andersenc470f442003-07-28 09:56:35 +00008813 if (forkshell(jp, n, backgnd) == 0) {
Denys Vlasenko238bf182010-05-18 15:49:07 +02008814 /* child */
Denis Vlasenkob012b102007-02-19 22:43:01 +00008815 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +00008816 flags |= EV_EXIT;
8817 if (backgnd)
Denys Vlasenko238bf182010-05-18 15:49:07 +02008818 flags &= ~EV_TESTED;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00008819 nofork:
Eric Andersenc470f442003-07-28 09:56:35 +00008820 redirect(n->nredir.redirect, 0);
8821 evaltreenr(n->nredir.n, flags);
8822 /* never returns */
8823 }
Denys Vlasenko70392332016-10-27 02:31:55 +02008824 /* parent */
Eric Andersenc470f442003-07-28 09:56:35 +00008825 status = 0;
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00008826 if (!backgnd)
Eric Andersenc470f442003-07-28 09:56:35 +00008827 status = waitforjob(jp);
Denis Vlasenkob012b102007-02-19 22:43:01 +00008828 INT_ON;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008829 return status;
Eric Andersenc470f442003-07-28 09:56:35 +00008830}
8831
Eric Andersenc470f442003-07-28 09:56:35 +00008832/*
8833 * Compute the names of the files in a redirection list.
8834 */
Denis Vlasenko99eb8502007-02-23 21:09:49 +00008835static void fixredir(union node *, const char *, int);
Eric Andersenc470f442003-07-28 09:56:35 +00008836static void
8837expredir(union node *n)
8838{
8839 union node *redir;
8840
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008841 for (redir = n; redir; redir = redir->nfile.next) {
Eric Andersenc470f442003-07-28 09:56:35 +00008842 struct arglist fn;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008843
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00008844 fn.list = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00008845 fn.lastp = &fn.list;
8846 switch (redir->type) {
8847 case NFROMTO:
8848 case NFROM:
8849 case NTO:
Denis Vlasenko559691a2008-10-05 18:39:31 +00008850#if ENABLE_ASH_BASH_COMPAT
8851 case NTO2:
8852#endif
Eric Andersenc470f442003-07-28 09:56:35 +00008853 case NCLOBBER:
8854 case NAPPEND:
8855 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02008856 TRACE(("expredir expanded to '%s'\n", fn.list->text));
Denis Vlasenko559691a2008-10-05 18:39:31 +00008857#if ENABLE_ASH_BASH_COMPAT
8858 store_expfname:
8859#endif
Denys Vlasenko7c4b13e2013-01-17 13:02:27 +01008860#if 0
8861// By the design of stack allocator, the loop of this kind:
8862// while true; do while true; do break; done </dev/null; done
8863// will look like a memory leak: ash plans to free expfname's
8864// of "/dev/null" as soon as it finishes running the loop
8865// (in this case, never).
8866// This "fix" is wrong:
Jon Tollefson4ba6c5d2012-11-13 19:26:53 +01008867 if (redir->nfile.expfname)
8868 stunalloc(redir->nfile.expfname);
Denys Vlasenko7c4b13e2013-01-17 13:02:27 +01008869// It results in corrupted state of stacked allocations.
8870#endif
Eric Andersenc470f442003-07-28 09:56:35 +00008871 redir->nfile.expfname = fn.list->text;
8872 break;
8873 case NFROMFD:
Denis Vlasenko559691a2008-10-05 18:39:31 +00008874 case NTOFD: /* >& */
Eric Andersenc470f442003-07-28 09:56:35 +00008875 if (redir->ndup.vname) {
8876 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008877 if (fn.list == NULL)
Denis Vlasenkob012b102007-02-19 22:43:01 +00008878 ash_msg_and_raise_error("redir error");
Denis Vlasenko559691a2008-10-05 18:39:31 +00008879#if ENABLE_ASH_BASH_COMPAT
8880//FIXME: we used expandarg with different args!
8881 if (!isdigit_str9(fn.list->text)) {
8882 /* >&file, not >&fd */
8883 if (redir->nfile.fd != 1) /* 123>&file - BAD */
8884 ash_msg_and_raise_error("redir error");
8885 redir->type = NTO2;
8886 goto store_expfname;
8887 }
8888#endif
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008889 fixredir(redir, fn.list->text, 1);
Eric Andersenc470f442003-07-28 09:56:35 +00008890 }
8891 break;
8892 }
8893 }
8894}
8895
Eric Andersencb57d552001-06-28 07:25:16 +00008896/*
Eric Andersencb57d552001-06-28 07:25:16 +00008897 * Evaluate a pipeline. All the processes in the pipeline are children
8898 * of the process creating the pipeline. (This differs from some versions
8899 * of the shell, which make the last process in a pipeline the parent
8900 * of all the rest.)
8901 */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008902static int
Eric Andersenc470f442003-07-28 09:56:35 +00008903evalpipe(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00008904{
8905 struct job *jp;
8906 struct nodelist *lp;
8907 int pipelen;
8908 int prevfd;
8909 int pip[2];
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008910 int status = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00008911
Eric Andersenc470f442003-07-28 09:56:35 +00008912 TRACE(("evalpipe(0x%lx) called\n", (long)n));
Eric Andersencb57d552001-06-28 07:25:16 +00008913 pipelen = 0;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008914 for (lp = n->npipe.cmdlist; lp; lp = lp->next)
Eric Andersencb57d552001-06-28 07:25:16 +00008915 pipelen++;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008916 flags |= EV_EXIT;
Denis Vlasenkob012b102007-02-19 22:43:01 +00008917 INT_OFF;
Denis Vlasenko68404f12008-03-17 09:00:54 +00008918 jp = makejob(/*n,*/ pipelen);
Eric Andersencb57d552001-06-28 07:25:16 +00008919 prevfd = -1;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008920 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008921 prehash(lp->n);
Eric Andersencb57d552001-06-28 07:25:16 +00008922 pip[1] = -1;
8923 if (lp->next) {
8924 if (pipe(pip) < 0) {
8925 close(prevfd);
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00008926 ash_msg_and_raise_error("pipe call failed");
Eric Andersencb57d552001-06-28 07:25:16 +00008927 }
8928 }
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00008929 if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) {
Denys Vlasenko70392332016-10-27 02:31:55 +02008930 /* child */
Denis Vlasenkob012b102007-02-19 22:43:01 +00008931 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +00008932 if (pip[1] >= 0) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008933 close(pip[0]);
Eric Andersencb57d552001-06-28 07:25:16 +00008934 }
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008935 if (prevfd > 0) {
8936 dup2(prevfd, 0);
8937 close(prevfd);
8938 }
8939 if (pip[1] > 1) {
8940 dup2(pip[1], 1);
8941 close(pip[1]);
8942 }
Eric Andersenc470f442003-07-28 09:56:35 +00008943 evaltreenr(lp->n, flags);
8944 /* never returns */
Eric Andersencb57d552001-06-28 07:25:16 +00008945 }
Denys Vlasenko70392332016-10-27 02:31:55 +02008946 /* parent */
Eric Andersencb57d552001-06-28 07:25:16 +00008947 if (prevfd >= 0)
8948 close(prevfd);
8949 prevfd = pip[0];
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +00008950 /* Don't want to trigger debugging */
8951 if (pip[1] != -1)
8952 close(pip[1]);
Eric Andersencb57d552001-06-28 07:25:16 +00008953 }
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00008954 if (n->npipe.pipe_backgnd == 0) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008955 status = waitforjob(jp);
8956 TRACE(("evalpipe: job done exit status %d\n", status));
Eric Andersencb57d552001-06-28 07:25:16 +00008957 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00008958 INT_ON;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008959
8960 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00008961}
8962
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00008963/*
8964 * Controls whether the shell is interactive or not.
8965 */
8966static void
8967setinteractive(int on)
8968{
Denis Vlasenkob07a4962008-06-22 13:16:23 +00008969 static smallint is_interactive;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00008970
8971 if (++on == is_interactive)
8972 return;
8973 is_interactive = on;
8974 setsignal(SIGINT);
8975 setsignal(SIGQUIT);
8976 setsignal(SIGTERM);
8977#if !ENABLE_FEATURE_SH_EXTRA_QUIET
8978 if (is_interactive > 1) {
8979 /* Looks like they want an interactive shell */
Denis Vlasenkoca525b42007-06-13 12:27:17 +00008980 static smallint did_banner;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00008981
Denis Vlasenkoca525b42007-06-13 12:27:17 +00008982 if (!did_banner) {
Denys Vlasenkoc34c0332009-09-29 12:25:30 +02008983 /* note: ash and hush share this string */
8984 out1fmt("\n\n%s %s\n"
Denys Vlasenko2ec34962014-09-08 16:52:39 +02008985 IF_ASH_HELP("Enter 'help' for a list of built-in commands.\n")
8986 "\n",
Denys Vlasenkoc34c0332009-09-29 12:25:30 +02008987 bb_banner,
8988 "built-in shell (ash)"
8989 );
Denis Vlasenkoca525b42007-06-13 12:27:17 +00008990 did_banner = 1;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00008991 }
8992 }
8993#endif
8994}
8995
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00008996static void
8997optschanged(void)
8998{
8999#if DEBUG
9000 opentrace();
9001#endif
9002 setinteractive(iflag);
9003 setjobctl(mflag);
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009004#if ENABLE_FEATURE_EDITING_VI
9005 if (viflag)
9006 line_input_state->flags |= VI_MODE;
9007 else
9008 line_input_state->flags &= ~VI_MODE;
9009#else
9010 viflag = 0; /* forcibly keep the option off */
9011#endif
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009012}
9013
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009014static struct localvar *localvars;
9015
9016/*
9017 * Called after a function returns.
9018 * Interrupts must be off.
9019 */
9020static void
9021poplocalvars(void)
9022{
9023 struct localvar *lvp;
9024 struct var *vp;
9025
9026 while ((lvp = localvars) != NULL) {
9027 localvars = lvp->next;
9028 vp = lvp->vp;
Denys Vlasenkob563f622010-09-25 17:15:13 +02009029 TRACE(("poplocalvar %s\n", vp ? vp->var_text : "-"));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009030 if (vp == NULL) { /* $- saved */
9031 memcpy(optlist, lvp->text, sizeof(optlist));
9032 free((char*)lvp->text);
9033 optschanged();
9034 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009035 unsetvar(vp->var_text);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009036 } else {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009037 if (vp->var_func)
9038 vp->var_func(var_end(lvp->text));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009039 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009040 free((char*)vp->var_text);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009041 vp->flags = lvp->flags;
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009042 vp->var_text = lvp->text;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009043 }
9044 free(lvp);
9045 }
9046}
9047
9048static int
9049evalfun(struct funcnode *func, int argc, char **argv, int flags)
9050{
9051 volatile struct shparam saveparam;
9052 struct localvar *volatile savelocalvars;
9053 struct jmploc *volatile savehandler;
9054 struct jmploc jmploc;
9055 int e;
9056
9057 saveparam = shellparam;
9058 savelocalvars = localvars;
Denys Vlasenkoa2d121c2016-09-30 11:30:11 +02009059 savehandler = exception_handler;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009060 e = setjmp(jmploc.loc);
9061 if (e) {
9062 goto funcdone;
9063 }
9064 INT_OFF;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009065 exception_handler = &jmploc;
9066 localvars = NULL;
Denis Vlasenko01631112007-12-16 17:20:38 +00009067 shellparam.malloced = 0;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009068 func->count++;
9069 funcnest++;
9070 INT_ON;
9071 shellparam.nparam = argc - 1;
9072 shellparam.p = argv + 1;
9073#if ENABLE_ASH_GETOPTS
9074 shellparam.optind = 1;
9075 shellparam.optoff = -1;
9076#endif
Denys Vlasenko7aec8682016-10-25 20:26:02 +02009077 evaltree(func->n.narg.next, flags & EV_TESTED);
Denis Vlasenko01631112007-12-16 17:20:38 +00009078 funcdone:
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009079 INT_OFF;
9080 funcnest--;
9081 freefunc(func);
9082 poplocalvars();
9083 localvars = savelocalvars;
9084 freeparam(&shellparam);
9085 shellparam = saveparam;
9086 exception_handler = savehandler;
9087 INT_ON;
9088 evalskip &= ~SKIPFUNC;
9089 return e;
9090}
9091
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009092/*
9093 * Make a variable a local variable. When a variable is made local, it's
9094 * value and flags are saved in a localvar structure. The saved values
9095 * will be restored when the shell function returns. We handle the name
Denys Vlasenkoe0a4e102015-05-13 02:20:14 +02009096 * "-" as a special case: it makes changes to "set +-options" local
9097 * (options will be restored on return from the function).
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009098 */
9099static void
9100mklocal(char *name)
9101{
9102 struct localvar *lvp;
9103 struct var **vpp;
9104 struct var *vp;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009105 char *eq = strchr(name, '=');
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009106
9107 INT_OFF;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009108 /* Cater for duplicate "local". Examples:
9109 * x=0; f() { local x=1; echo $x; local x; echo $x; }; f; echo $x
9110 * x=0; f() { local x=1; echo $x; local x=2; echo $x; }; f; echo $x
9111 */
9112 lvp = localvars;
9113 while (lvp) {
Eugene Rudoy1285aa62015-04-26 23:32:00 +02009114 if (lvp->vp && varcmp(lvp->vp->var_text, name) == 0) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009115 if (eq)
9116 setvareq(name, 0);
9117 /* else:
9118 * it's a duplicate "local VAR" declaration, do nothing
9119 */
Denys Vlasenko06b11492016-11-04 16:43:18 +01009120 goto ret;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009121 }
9122 lvp = lvp->next;
9123 }
9124
9125 lvp = ckzalloc(sizeof(*lvp));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009126 if (LONE_DASH(name)) {
9127 char *p;
9128 p = ckmalloc(sizeof(optlist));
9129 lvp->text = memcpy(p, optlist, sizeof(optlist));
9130 vp = NULL;
9131 } else {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009132 vpp = hashvar(name);
9133 vp = *findvar(vpp, name);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009134 if (vp == NULL) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009135 /* variable did not exist yet */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009136 if (eq)
9137 setvareq(name, VSTRFIXED);
9138 else
9139 setvar(name, NULL, VSTRFIXED);
9140 vp = *vpp; /* the new variable */
9141 lvp->flags = VUNSET;
9142 } else {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009143 lvp->text = vp->var_text;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009144 lvp->flags = vp->flags;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009145 /* make sure neither "struct var" nor string gets freed
9146 * during (un)setting:
9147 */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009148 vp->flags |= VSTRFIXED|VTEXTFIXED;
9149 if (eq)
9150 setvareq(name, 0);
Denys Vlasenko109ee5d2014-03-16 18:41:11 +01009151 else
9152 /* "local VAR" unsets VAR: */
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009153 setvar0(name, NULL);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009154 }
9155 }
9156 lvp->vp = vp;
9157 lvp->next = localvars;
9158 localvars = lvp;
Denys Vlasenko06b11492016-11-04 16:43:18 +01009159 ret:
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009160 INT_ON;
9161}
9162
9163/*
9164 * The "local" command.
9165 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009166static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009167localcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009168{
9169 char *name;
9170
Ron Yorstonef2386b2015-10-29 16:19:14 +00009171 if (!funcnest)
9172 ash_msg_and_raise_error("not in a function");
9173
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009174 argv = argptr;
9175 while ((name = *argv++) != NULL) {
9176 mklocal(name);
9177 }
9178 return 0;
9179}
9180
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009181static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009182falsecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009183{
9184 return 1;
9185}
9186
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009187static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009188truecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009189{
9190 return 0;
9191}
9192
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009193static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009194execcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009195{
Denis Vlasenko68404f12008-03-17 09:00:54 +00009196 if (argv[1]) {
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009197 iflag = 0; /* exit on error */
9198 mflag = 0;
9199 optschanged();
Denys Vlasenkoe5814a52016-07-16 18:33:55 +02009200 /* We should set up signals for "exec CMD"
9201 * the same way as for "CMD" without "exec".
9202 * But optschanged->setinteractive->setsignal
9203 * still thought we are a root shell. Therefore, for example,
9204 * SIGQUIT is still set to IGN. Fix it:
9205 */
9206 shlvl++;
9207 setsignal(SIGQUIT);
9208 /*setsignal(SIGTERM); - unnecessary because of iflag=0 */
9209 /*setsignal(SIGTSTP); - unnecessary because of mflag=0 */
9210 /*setsignal(SIGTTOU); - unnecessary because of mflag=0 */
9211
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009212 shellexec(argv + 1, pathval(), 0);
Denys Vlasenkoe5814a52016-07-16 18:33:55 +02009213 /* NOTREACHED */
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009214 }
9215 return 0;
9216}
9217
9218/*
9219 * The return command.
9220 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009221static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009222returncmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009223{
9224 /*
9225 * If called outside a function, do what ksh does;
9226 * skip the rest of the file.
9227 */
Denys Vlasenko6a0710e2016-09-30 14:18:34 +02009228 evalskip = SKIPFUNC;
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009229 return argv[1] ? number(argv[1]) : exitstatus;
9230}
9231
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009232/* Forward declarations for builtintab[] */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009233static int breakcmd(int, char **) FAST_FUNC;
9234static int dotcmd(int, char **) FAST_FUNC;
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009235static int evalcmd(int, char **, int) FAST_FUNC;
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009236static int exitcmd(int, char **) FAST_FUNC;
9237static int exportcmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009238#if ENABLE_ASH_GETOPTS
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009239static int getoptscmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009240#endif
Denys Vlasenko2ec34962014-09-08 16:52:39 +02009241#if ENABLE_ASH_HELP
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009242static int helpcmd(int, char **) FAST_FUNC;
Denis Vlasenko52764022007-02-24 13:42:56 +00009243#endif
Flemming Madsend96ffda2013-04-07 18:47:24 +02009244#if MAX_HISTORY
9245static int historycmd(int, char **) FAST_FUNC;
9246#endif
Mike Frysinger98c52642009-04-02 10:02:37 +00009247#if ENABLE_SH_MATH_SUPPORT
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009248static int letcmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009249#endif
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009250static int readcmd(int, char **) FAST_FUNC;
9251static int setcmd(int, char **) FAST_FUNC;
9252static int shiftcmd(int, char **) FAST_FUNC;
9253static int timescmd(int, char **) FAST_FUNC;
9254static int trapcmd(int, char **) FAST_FUNC;
9255static int umaskcmd(int, char **) FAST_FUNC;
9256static int unsetcmd(int, char **) FAST_FUNC;
9257static int ulimitcmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009258
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009259#define BUILTIN_NOSPEC "0"
9260#define BUILTIN_SPECIAL "1"
9261#define BUILTIN_REGULAR "2"
9262#define BUILTIN_SPEC_REG "3"
9263#define BUILTIN_ASSIGN "4"
9264#define BUILTIN_SPEC_ASSG "5"
9265#define BUILTIN_REG_ASSG "6"
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009266#define BUILTIN_SPEC_REG_ASSG "7"
9267
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009268/* Stubs for calling non-FAST_FUNC's */
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009269#if ENABLE_ASH_BUILTIN_ECHO
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009270static int FAST_FUNC echocmd(int argc, char **argv) { return echo_main(argc, argv); }
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009271#endif
9272#if ENABLE_ASH_BUILTIN_PRINTF
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009273static int FAST_FUNC printfcmd(int argc, char **argv) { return printf_main(argc, argv); }
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009274#endif
9275#if ENABLE_ASH_BUILTIN_TEST
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009276static int FAST_FUNC testcmd(int argc, char **argv) { return test_main(argc, argv); }
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009277#endif
Denis Vlasenko468aea22008-04-01 14:47:57 +00009278
Denis Vlasenkof7d56652008-03-25 05:51:41 +00009279/* Keep these in proper order since it is searched via bsearch() */
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009280static const struct builtincmd builtintab[] = {
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009281 { BUILTIN_SPEC_REG "." , dotcmd },
9282 { BUILTIN_SPEC_REG ":" , truecmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009283#if ENABLE_ASH_BUILTIN_TEST
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009284 { BUILTIN_REGULAR "[" , testcmd },
Denis Vlasenko80591b02008-03-25 07:49:43 +00009285#if ENABLE_ASH_BASH_COMPAT
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009286 { BUILTIN_REGULAR "[[" , testcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009287#endif
Denis Vlasenko80591b02008-03-25 07:49:43 +00009288#endif
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009289#if ENABLE_ASH_ALIAS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009290 { BUILTIN_REG_ASSG "alias" , aliascmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009291#endif
9292#if JOBS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009293 { BUILTIN_REGULAR "bg" , fg_bgcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009294#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009295 { BUILTIN_SPEC_REG "break" , breakcmd },
9296 { BUILTIN_REGULAR "cd" , cdcmd },
9297 { BUILTIN_NOSPEC "chdir" , cdcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009298#if ENABLE_ASH_CMDCMD
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009299 { BUILTIN_REGULAR "command" , commandcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009300#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009301 { BUILTIN_SPEC_REG "continue", breakcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009302#if ENABLE_ASH_BUILTIN_ECHO
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009303 { BUILTIN_REGULAR "echo" , echocmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009304#endif
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009305 { BUILTIN_SPEC_REG "eval" , NULL }, /*evalcmd() has a differing prototype*/
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009306 { BUILTIN_SPEC_REG "exec" , execcmd },
9307 { BUILTIN_SPEC_REG "exit" , exitcmd },
9308 { BUILTIN_SPEC_REG_ASSG "export" , exportcmd },
9309 { BUILTIN_REGULAR "false" , falsecmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009310#if JOBS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009311 { BUILTIN_REGULAR "fg" , fg_bgcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009312#endif
9313#if ENABLE_ASH_GETOPTS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009314 { BUILTIN_REGULAR "getopts" , getoptscmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009315#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009316 { BUILTIN_NOSPEC "hash" , hashcmd },
Denys Vlasenko2ec34962014-09-08 16:52:39 +02009317#if ENABLE_ASH_HELP
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009318 { BUILTIN_NOSPEC "help" , helpcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009319#endif
Flemming Madsend96ffda2013-04-07 18:47:24 +02009320#if MAX_HISTORY
9321 { BUILTIN_NOSPEC "history" , historycmd },
9322#endif
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009323#if JOBS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009324 { BUILTIN_REGULAR "jobs" , jobscmd },
9325 { BUILTIN_REGULAR "kill" , killcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009326#endif
Mike Frysinger98c52642009-04-02 10:02:37 +00009327#if ENABLE_SH_MATH_SUPPORT
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009328 { BUILTIN_NOSPEC "let" , letcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009329#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009330 { BUILTIN_ASSIGN "local" , localcmd },
Denis Vlasenkocd2663f2008-06-01 22:36:39 +00009331#if ENABLE_ASH_BUILTIN_PRINTF
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009332 { BUILTIN_REGULAR "printf" , printfcmd },
Denis Vlasenkocd2663f2008-06-01 22:36:39 +00009333#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009334 { BUILTIN_NOSPEC "pwd" , pwdcmd },
9335 { BUILTIN_REGULAR "read" , readcmd },
9336 { BUILTIN_SPEC_REG_ASSG "readonly", exportcmd },
9337 { BUILTIN_SPEC_REG "return" , returncmd },
9338 { BUILTIN_SPEC_REG "set" , setcmd },
9339 { BUILTIN_SPEC_REG "shift" , shiftcmd },
Denys Vlasenko82731b42010-05-17 17:49:52 +02009340#if ENABLE_ASH_BASH_COMPAT
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009341 { BUILTIN_SPEC_REG "source" , dotcmd },
Denys Vlasenko82731b42010-05-17 17:49:52 +02009342#endif
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009343#if ENABLE_ASH_BUILTIN_TEST
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009344 { BUILTIN_REGULAR "test" , testcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009345#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009346 { BUILTIN_SPEC_REG "times" , timescmd },
9347 { BUILTIN_SPEC_REG "trap" , trapcmd },
9348 { BUILTIN_REGULAR "true" , truecmd },
9349 { BUILTIN_NOSPEC "type" , typecmd },
9350 { BUILTIN_NOSPEC "ulimit" , ulimitcmd },
9351 { BUILTIN_REGULAR "umask" , umaskcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009352#if ENABLE_ASH_ALIAS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009353 { BUILTIN_REGULAR "unalias" , unaliascmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009354#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009355 { BUILTIN_SPEC_REG "unset" , unsetcmd },
9356 { BUILTIN_REGULAR "wait" , waitcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009357};
9358
Denis Vlasenko80591b02008-03-25 07:49:43 +00009359/* Should match the above table! */
9360#define COMMANDCMD (builtintab + \
Denys Vlasenko928e2a72016-09-29 00:30:31 +02009361 /* . : */ 2 + \
9362 /* [ */ 1 * ENABLE_ASH_BUILTIN_TEST + \
9363 /* [[ */ 1 * ENABLE_ASH_BUILTIN_TEST * ENABLE_ASH_BASH_COMPAT + \
9364 /* alias */ 1 * ENABLE_ASH_ALIAS + \
9365 /* bg */ 1 * ENABLE_ASH_JOB_CONTROL + \
9366 /* break cd cddir */ 3)
9367#define EVALCMD (COMMANDCMD + \
9368 /* command */ 1 * ENABLE_ASH_CMDCMD + \
9369 /* continue */ 1 + \
9370 /* echo */ 1 * ENABLE_ASH_BUILTIN_ECHO + \
9371 0)
9372#define EXECCMD (EVALCMD + \
9373 /* eval */ 1)
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009374
9375/*
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009376 * Search the table of builtin commands.
9377 */
Denys Vlasenko888527c2016-10-02 16:54:17 +02009378static int
9379pstrcmp1(const void *a, const void *b)
9380{
9381 return strcmp((char*)a, *(char**)b + 1);
9382}
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009383static struct builtincmd *
9384find_builtin(const char *name)
9385{
9386 struct builtincmd *bp;
9387
9388 bp = bsearch(
Denis Vlasenko80b8b392007-06-25 10:55:35 +00009389 name, builtintab, ARRAY_SIZE(builtintab), sizeof(builtintab[0]),
Denys Vlasenko888527c2016-10-02 16:54:17 +02009390 pstrcmp1
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009391 );
9392 return bp;
9393}
9394
9395/*
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009396 * Execute a simple command.
9397 */
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009398static int
9399isassignment(const char *p)
Paul Foxc3850c82005-07-20 18:23:39 +00009400{
9401 const char *q = endofname(p);
9402 if (p == q)
9403 return 0;
9404 return *q == '=';
9405}
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009406static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009407bltincmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009408{
9409 /* Preserve exitstatus of a previous possible redirection
9410 * as POSIX mandates */
9411 return back_exitstatus;
9412}
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009413static int
Eric Andersenc470f442003-07-28 09:56:35 +00009414evalcommand(union node *cmd, int flags)
9415{
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00009416 static const struct builtincmd null_bltin = {
9417 "\0\0", bltincmd /* why three NULs? */
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009418 };
Eric Andersenc470f442003-07-28 09:56:35 +00009419 struct stackmark smark;
9420 union node *argp;
9421 struct arglist arglist;
9422 struct arglist varlist;
9423 char **argv;
9424 int argc;
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009425 const struct strlist *sp;
Eric Andersenc470f442003-07-28 09:56:35 +00009426 struct cmdentry cmdentry;
9427 struct job *jp;
9428 char *lastarg;
9429 const char *path;
9430 int spclbltin;
Eric Andersenc470f442003-07-28 09:56:35 +00009431 int status;
9432 char **nargv;
Paul Foxc3850c82005-07-20 18:23:39 +00009433 struct builtincmd *bcmd;
Denis Vlasenko34c73c42008-08-16 11:48:02 +00009434 smallint cmd_is_exec;
9435 smallint pseudovarflag = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00009436
9437 /* First expand the arguments. */
9438 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
9439 setstackmark(&smark);
9440 back_exitstatus = 0;
9441
9442 cmdentry.cmdtype = CMDBUILTIN;
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00009443 cmdentry.u.cmd = &null_bltin;
Eric Andersenc470f442003-07-28 09:56:35 +00009444 varlist.lastp = &varlist.list;
9445 *varlist.lastp = NULL;
9446 arglist.lastp = &arglist.list;
9447 *arglist.lastp = NULL;
9448
9449 argc = 0;
Denis Vlasenkob012b102007-02-19 22:43:01 +00009450 if (cmd->ncmd.args) {
Paul Foxc3850c82005-07-20 18:23:39 +00009451 bcmd = find_builtin(cmd->ncmd.args->narg.text);
9452 pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd);
9453 }
9454
Eric Andersenc470f442003-07-28 09:56:35 +00009455 for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) {
9456 struct strlist **spp;
9457
9458 spp = arglist.lastp;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00009459 if (pseudovarflag && isassignment(argp->narg.text))
Paul Foxc3850c82005-07-20 18:23:39 +00009460 expandarg(argp, &arglist, EXP_VARTILDE);
9461 else
9462 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
9463
Eric Andersenc470f442003-07-28 09:56:35 +00009464 for (sp = *spp; sp; sp = sp->next)
9465 argc++;
9466 }
9467
Denys Vlasenko65a8b852016-10-26 22:29:11 +02009468 /* Reserve one extra spot at the front for shellexec. */
9469 nargv = stalloc(sizeof(char *) * (argc + 2));
9470 argv = ++nargv;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009471 for (sp = arglist.list; sp; sp = sp->next) {
Eric Andersenc470f442003-07-28 09:56:35 +00009472 TRACE(("evalcommand arg: %s\n", sp->text));
9473 *nargv++ = sp->text;
9474 }
9475 *nargv = NULL;
9476
9477 lastarg = NULL;
9478 if (iflag && funcnest == 0 && argc > 0)
9479 lastarg = nargv[-1];
9480
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009481 preverrout_fd = 2;
Eric Andersenc470f442003-07-28 09:56:35 +00009482 expredir(cmd->ncmd.redirect);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009483 status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH | REDIR_SAVEFD2);
Eric Andersenc470f442003-07-28 09:56:35 +00009484
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009485 path = vpath.var_text;
Eric Andersenc470f442003-07-28 09:56:35 +00009486 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
9487 struct strlist **spp;
9488 char *p;
9489
9490 spp = varlist.lastp;
9491 expandarg(argp, &varlist, EXP_VARTILDE);
9492
9493 /*
9494 * Modify the command lookup path, if a PATH= assignment
9495 * is present
9496 */
9497 p = (*spp)->text;
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009498 if (varcmp(p, path) == 0)
Eric Andersenc470f442003-07-28 09:56:35 +00009499 path = p;
9500 }
9501
9502 /* Print the command if xflag is set. */
9503 if (xflag) {
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009504 int n;
Denys Vlasenkofd33e172010-06-26 22:55:44 +02009505 const char *p = " %s" + 1;
Eric Andersenc470f442003-07-28 09:56:35 +00009506
Denis Vlasenko0de37e12007-10-17 11:08:53 +00009507 fdprintf(preverrout_fd, p, expandstr(ps4val()));
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009508 sp = varlist.list;
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +00009509 for (n = 0; n < 2; n++) {
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009510 while (sp) {
Denis Vlasenko0de37e12007-10-17 11:08:53 +00009511 fdprintf(preverrout_fd, p, sp->text);
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009512 sp = sp->next;
Denys Vlasenkofd33e172010-06-26 22:55:44 +02009513 p = " %s";
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009514 }
9515 sp = arglist.list;
9516 }
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00009517 safe_write(preverrout_fd, "\n", 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009518 }
9519
9520 cmd_is_exec = 0;
9521 spclbltin = -1;
9522
9523 /* Now locate the command. */
9524 if (argc) {
Eric Andersenc470f442003-07-28 09:56:35 +00009525 int cmd_flag = DO_ERR;
Denys Vlasenko0b4980c2012-09-25 12:49:29 +02009526#if ENABLE_ASH_CMDCMD
9527 const char *oldpath = path + 5;
9528#endif
Eric Andersenc470f442003-07-28 09:56:35 +00009529 path += 5;
Eric Andersenc470f442003-07-28 09:56:35 +00009530 for (;;) {
9531 find_command(argv[0], &cmdentry, cmd_flag, path);
9532 if (cmdentry.cmdtype == CMDUNKNOWN) {
Denys Vlasenko8131eea2009-11-02 14:19:51 +01009533 flush_stdout_stderr();
Denis Vlasenko6514c5e2008-07-24 13:41:37 +00009534 status = 127;
Eric Andersenc470f442003-07-28 09:56:35 +00009535 goto bail;
9536 }
9537
9538 /* implement bltin and command here */
9539 if (cmdentry.cmdtype != CMDBUILTIN)
9540 break;
9541 if (spclbltin < 0)
9542 spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd);
9543 if (cmdentry.u.cmd == EXECCMD)
Denis Vlasenko34c73c42008-08-16 11:48:02 +00009544 cmd_is_exec = 1;
Denis Vlasenko131ae172007-02-18 13:00:19 +00009545#if ENABLE_ASH_CMDCMD
Eric Andersenc470f442003-07-28 09:56:35 +00009546 if (cmdentry.u.cmd == COMMANDCMD) {
Eric Andersenc470f442003-07-28 09:56:35 +00009547 path = oldpath;
9548 nargv = parse_command_args(argv, &path);
9549 if (!nargv)
9550 break;
Denys Vlasenkocac4d002016-10-01 03:02:25 +02009551 /* It's "command [-p] PROG ARGS" (that is, no -Vv).
9552 * nargv => "PROG". path is updated if -p.
9553 */
Eric Andersenc470f442003-07-28 09:56:35 +00009554 argc -= nargv - argv;
9555 argv = nargv;
9556 cmd_flag |= DO_NOFUNC;
9557 } else
9558#endif
9559 break;
9560 }
9561 }
9562
9563 if (status) {
9564 /* We have a redirection error. */
9565 if (spclbltin > 0)
Denis Vlasenkob012b102007-02-19 22:43:01 +00009566 raise_exception(EXERROR);
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009567 bail:
Eric Andersenc470f442003-07-28 09:56:35 +00009568 exitstatus = status;
9569 goto out;
9570 }
9571
9572 /* Execute the command. */
9573 switch (cmdentry.cmdtype) {
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009574 default: {
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +00009575
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009576#if ENABLE_FEATURE_SH_NOFORK
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009577/* (1) BUG: if variables are set, we need to fork, or save/restore them
9578 * around run_nofork_applet() call.
9579 * (2) Should this check also be done in forkshell()?
9580 * (perhaps it should, so that "VAR=VAL nofork" at least avoids exec...)
9581 */
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00009582 /* find_command() encodes applet_no as (-2 - applet_no) */
9583 int applet_no = (- cmdentry.u.index - 2);
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009584 if (applet_no >= 0 && APPLET_IS_NOFORK(applet_no)) {
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009585 listsetvar(varlist.list, VEXPORT|VSTACK);
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00009586 /* run <applet>_main() */
Ron Yorston5ccb0e92016-10-20 12:24:02 +01009587 status = run_nofork_applet(applet_no, argv);
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009588 break;
9589 }
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009590#endif
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009591 /* Can we avoid forking off? For example, very last command
9592 * in a script or a subshell does not need forking,
9593 * we can just exec it.
9594 */
Denys Vlasenko238bf182010-05-18 15:49:07 +02009595 if (!(flags & EV_EXIT) || may_have_traps) {
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009596 /* No, forking off a child is necessary */
Denis Vlasenkob012b102007-02-19 22:43:01 +00009597 INT_OFF;
Denis Vlasenko68404f12008-03-17 09:00:54 +00009598 jp = makejob(/*cmd,*/ 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009599 if (forkshell(jp, cmd, FORK_FG) != 0) {
Denys Vlasenko238bf182010-05-18 15:49:07 +02009600 /* parent */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009601 status = waitforjob(jp);
Denis Vlasenkob012b102007-02-19 22:43:01 +00009602 INT_ON;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009603 TRACE(("forked child exited with %d\n", status));
Eric Andersenc470f442003-07-28 09:56:35 +00009604 break;
9605 }
Denys Vlasenko238bf182010-05-18 15:49:07 +02009606 /* child */
Denis Vlasenkob012b102007-02-19 22:43:01 +00009607 FORCE_INT_ON;
Denys Vlasenkoc7f95d22010-05-18 15:52:23 +02009608 /* fall through to exec'ing external program */
Eric Andersenc470f442003-07-28 09:56:35 +00009609 }
9610 listsetvar(varlist.list, VEXPORT|VSTACK);
9611 shellexec(argv, path, cmdentry.u.index);
9612 /* NOTREACHED */
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009613 } /* default */
Eric Andersenc470f442003-07-28 09:56:35 +00009614 case CMDBUILTIN:
9615 cmdenviron = varlist.list;
9616 if (cmdenviron) {
9617 struct strlist *list = cmdenviron;
9618 int i = VNOSET;
9619 if (spclbltin > 0 || argc == 0) {
9620 i = 0;
9621 if (cmd_is_exec && argc > 1)
9622 i = VEXPORT;
9623 }
9624 listsetvar(list, i);
9625 }
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +00009626 /* Tight loop with builtins only:
9627 * "while kill -0 $child; do true; done"
9628 * will never exit even if $child died, unless we do this
9629 * to reap the zombie and make kill detect that it's gone: */
9630 dowait(DOWAIT_NONBLOCK, NULL);
9631
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009632 if (evalbltin(cmdentry.u.cmd, argc, argv, flags)) {
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02009633 if (exception_type == EXERROR && spclbltin <= 0) {
9634 FORCE_INT_ON;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +02009635 goto readstatus;
Eric Andersenc470f442003-07-28 09:56:35 +00009636 }
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02009637 raise:
9638 longjmp(exception_handler->loc, 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009639 }
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009640 goto readstatus;
Eric Andersenc470f442003-07-28 09:56:35 +00009641
9642 case CMDFUNCTION:
9643 listsetvar(varlist.list, 0);
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +00009644 /* See above for the rationale */
9645 dowait(DOWAIT_NONBLOCK, NULL);
Eric Andersenc470f442003-07-28 09:56:35 +00009646 if (evalfun(cmdentry.u.func, argc, argv, flags))
9647 goto raise;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009648 readstatus:
9649 status = exitstatus;
Eric Andersenc470f442003-07-28 09:56:35 +00009650 break;
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009651 } /* switch */
Eric Andersenc470f442003-07-28 09:56:35 +00009652
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009653 out:
Denys Vlasenkoeaf94362016-10-25 21:46:03 +02009654 if (cmd->ncmd.redirect)
9655 popredir(/*drop:*/ cmd_is_exec, /*restore:*/ cmd_is_exec);
Denis Vlasenko6514c5e2008-07-24 13:41:37 +00009656 if (lastarg) {
Eric Andersenc470f442003-07-28 09:56:35 +00009657 /* dsl: I think this is intended to be used to support
9658 * '_' in 'vi' command mode during line editing...
9659 * However I implemented that within libedit itself.
9660 */
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009661 setvar0("_", lastarg);
Denis Vlasenko6514c5e2008-07-24 13:41:37 +00009662 }
Eric Andersenc470f442003-07-28 09:56:35 +00009663 popstackmark(&smark);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009664
9665 return status;
Eric Andersenc470f442003-07-28 09:56:35 +00009666}
9667
9668static int
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009669evalbltin(const struct builtincmd *cmd, int argc, char **argv, int flags)
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009670{
Eric Andersenc470f442003-07-28 09:56:35 +00009671 char *volatile savecmdname;
9672 struct jmploc *volatile savehandler;
9673 struct jmploc jmploc;
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009674 int status;
Eric Andersenc470f442003-07-28 09:56:35 +00009675 int i;
9676
9677 savecmdname = commandname;
Denys Vlasenkoa2d121c2016-09-30 11:30:11 +02009678 savehandler = exception_handler;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009679 i = setjmp(jmploc.loc);
9680 if (i)
Eric Andersenc470f442003-07-28 09:56:35 +00009681 goto cmddone;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009682 exception_handler = &jmploc;
Eric Andersenc470f442003-07-28 09:56:35 +00009683 commandname = argv[0];
9684 argptr = argv + 1;
9685 optptr = NULL; /* initialize nextopt */
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009686 if (cmd == EVALCMD)
9687 status = evalcmd(argc, argv, flags);
9688 else
9689 status = (*cmd->builtin)(argc, argv);
Denis Vlasenkob012b102007-02-19 22:43:01 +00009690 flush_stdout_stderr();
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009691 status |= ferror(stdout);
9692 exitstatus = status;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009693 cmddone:
Rob Landleyf296f0b2006-07-06 01:09:21 +00009694 clearerr(stdout);
Eric Andersenc470f442003-07-28 09:56:35 +00009695 commandname = savecmdname;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009696 exception_handler = savehandler;
Eric Andersenc470f442003-07-28 09:56:35 +00009697
9698 return i;
9699}
9700
Denis Vlasenkoaa744452007-02-23 01:04:22 +00009701static int
9702goodname(const char *p)
Glenn L McGrath16e45d72004-02-04 08:24:39 +00009703{
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02009704 return endofname(p)[0] == '\0';
Glenn L McGrath16e45d72004-02-04 08:24:39 +00009705}
9706
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009707
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009708/*
9709 * Search for a command. This is called before we fork so that the
9710 * location of the command will be available in the parent as well as
Glenn L McGrath16e45d72004-02-04 08:24:39 +00009711 * the child. The check for "goodname" is an overly conservative
9712 * check that the name will not be subject to expansion.
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009713 */
Eric Andersenc470f442003-07-28 09:56:35 +00009714static void
9715prehash(union node *n)
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009716{
9717 struct cmdentry entry;
9718
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +00009719 if (n->type == NCMD && n->ncmd.args && goodname(n->ncmd.args->narg.text))
9720 find_command(n->ncmd.args->narg.text, &entry, 0, pathval());
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009721}
9722
Eric Andersencb57d552001-06-28 07:25:16 +00009723
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009724/* ============ Builtin commands
9725 *
9726 * Builtin commands whose functions are closely tied to evaluation
9727 * are implemented here.
Eric Andersencb57d552001-06-28 07:25:16 +00009728 */
9729
9730/*
Eric Andersencb57d552001-06-28 07:25:16 +00009731 * Handle break and continue commands. Break, continue, and return are
9732 * all handled by setting the evalskip flag. The evaluation routines
9733 * above all check this flag, and if it is set they start skipping
9734 * commands rather than executing them. The variable skipcount is
9735 * the number of loops to break/continue, or the number of function
9736 * levels to return. (The latter is always 1.) It should probably
9737 * be an error to break out of more loops than exist, but it isn't
9738 * in the standard shell so we don't make it one here.
9739 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009740static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009741breakcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00009742{
Denis Vlasenko68404f12008-03-17 09:00:54 +00009743 int n = argv[1] ? number(argv[1]) : 1;
Eric Andersencb57d552001-06-28 07:25:16 +00009744
Aaron Lehmann2aef3a62001-12-31 06:03:12 +00009745 if (n <= 0)
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02009746 ash_msg_and_raise_error(msg_illnum, argv[1]);
Eric Andersencb57d552001-06-28 07:25:16 +00009747 if (n > loopnest)
9748 n = loopnest;
9749 if (n > 0) {
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009750 evalskip = (**argv == 'c') ? SKIPCONT : SKIPBREAK;
Eric Andersencb57d552001-06-28 07:25:16 +00009751 skipcount = n;
9752 }
9753 return 0;
9754}
9755
Eric Andersenc470f442003-07-28 09:56:35 +00009756
Denys Vlasenko70392332016-10-27 02:31:55 +02009757/*
Eric Andersen90898442003-08-06 11:20:52 +00009758 * This implements the input routines used by the parser.
Eric Andersencb57d552001-06-28 07:25:16 +00009759 */
Denis Vlasenko99eb8502007-02-23 21:09:49 +00009760
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009761enum {
9762 INPUT_PUSH_FILE = 1,
9763 INPUT_NOFILE_OK = 2,
9764};
Eric Andersencb57d552001-06-28 07:25:16 +00009765
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009766static smallint checkkwd;
Denis Vlasenko99eb8502007-02-23 21:09:49 +00009767/* values of checkkwd variable */
9768#define CHKALIAS 0x1
9769#define CHKKWD 0x2
9770#define CHKNL 0x4
9771
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009772/*
9773 * Push a string back onto the input at this current parsefile level.
9774 * We handle aliases this way.
9775 */
9776#if !ENABLE_ASH_ALIAS
9777#define pushstring(s, ap) pushstring(s)
9778#endif
9779static void
9780pushstring(char *s, struct alias *ap)
9781{
9782 struct strpush *sp;
9783 int len;
9784
9785 len = strlen(s);
9786 INT_OFF;
9787 if (g_parsefile->strpush) {
9788 sp = ckzalloc(sizeof(*sp));
9789 sp->prev = g_parsefile->strpush;
9790 } else {
9791 sp = &(g_parsefile->basestrpush);
9792 }
9793 g_parsefile->strpush = sp;
9794 sp->prev_string = g_parsefile->next_to_pgetc;
9795 sp->prev_left_in_line = g_parsefile->left_in_line;
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02009796 sp->unget = g_parsefile->unget;
9797 memcpy(sp->lastc, g_parsefile->lastc, sizeof(sp->lastc));
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009798#if ENABLE_ASH_ALIAS
9799 sp->ap = ap;
9800 if (ap) {
9801 ap->flag |= ALIASINUSE;
9802 sp->string = s;
9803 }
9804#endif
9805 g_parsefile->next_to_pgetc = s;
9806 g_parsefile->left_in_line = len;
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02009807 g_parsefile->unget = 0;
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009808 INT_ON;
9809}
9810
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009811static void
9812popstring(void)
Eric Andersenc470f442003-07-28 09:56:35 +00009813{
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009814 struct strpush *sp = g_parsefile->strpush;
Eric Andersenc470f442003-07-28 09:56:35 +00009815
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009816 INT_OFF;
Denis Vlasenko131ae172007-02-18 13:00:19 +00009817#if ENABLE_ASH_ALIAS
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009818 if (sp->ap) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009819 if (g_parsefile->next_to_pgetc[-1] == ' '
9820 || g_parsefile->next_to_pgetc[-1] == '\t'
9821 ) {
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009822 checkkwd |= CHKALIAS;
Glenn L McGrath28939ad2004-07-21 10:20:19 +00009823 }
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009824 if (sp->string != sp->ap->val) {
9825 free(sp->string);
9826 }
9827 sp->ap->flag &= ~ALIASINUSE;
9828 if (sp->ap->flag & ALIASDEAD) {
9829 unalias(sp->ap->name);
9830 }
Glenn L McGrath28939ad2004-07-21 10:20:19 +00009831 }
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00009832#endif
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009833 g_parsefile->next_to_pgetc = sp->prev_string;
9834 g_parsefile->left_in_line = sp->prev_left_in_line;
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02009835 g_parsefile->unget = sp->unget;
9836 memcpy(g_parsefile->lastc, sp->lastc, sizeof(sp->lastc));
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009837 g_parsefile->strpush = sp->prev;
9838 if (sp != &(g_parsefile->basestrpush))
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009839 free(sp);
9840 INT_ON;
9841}
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00009842
Denis Vlasenkoaa744452007-02-23 01:04:22 +00009843static int
9844preadfd(void)
Eric Andersencb57d552001-06-28 07:25:16 +00009845{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009846 int nr;
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00009847 char *buf = g_parsefile->buf;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009848
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009849 g_parsefile->next_to_pgetc = buf;
Denis Vlasenko38f63192007-01-22 09:03:07 +00009850#if ENABLE_FEATURE_EDITING
Denis Vlasenko85c24712008-03-17 09:04:04 +00009851 retry:
Denys Vlasenko79b3d422010-06-03 04:29:08 +02009852 if (!iflag || g_parsefile->pf_fd != STDIN_FILENO)
Ron Yorston61d6ae22015-04-19 10:50:25 +01009853 nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009854 else {
Denys Vlasenko66c5b122011-02-08 05:07:02 +01009855 int timeout = -1;
9856# if ENABLE_ASH_IDLE_TIMEOUT
9857 if (iflag) {
9858 const char *tmout_var = lookupvar("TMOUT");
9859 if (tmout_var) {
9860 timeout = atoi(tmout_var) * 1000;
9861 if (timeout <= 0)
9862 timeout = -1;
9863 }
9864 }
9865# endif
Denys Vlasenko8c52f802011-02-04 17:36:21 +01009866# if ENABLE_FEATURE_TAB_COMPLETION
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00009867 line_input_state->path_lookup = pathval();
Denys Vlasenko8c52f802011-02-04 17:36:21 +01009868# endif
Denys Vlasenkoe9ab07c2014-08-13 18:00:08 +02009869 reinit_unicode_for_ash();
Denys Vlasenko66c5b122011-02-08 05:07:02 +01009870 nr = read_line_input(line_input_state, cmdedit_prompt, buf, IBUFSIZ, timeout);
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00009871 if (nr == 0) {
9872 /* Ctrl+C pressed */
9873 if (trap[SIGINT]) {
Glenn L McGrath16e45d72004-02-04 08:24:39 +00009874 buf[0] = '\n';
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00009875 buf[1] = '\0';
Glenn L McGrath16e45d72004-02-04 08:24:39 +00009876 raise(SIGINT);
9877 return 1;
9878 }
Eric Andersenc470f442003-07-28 09:56:35 +00009879 goto retry;
9880 }
Denys Vlasenko66c5b122011-02-08 05:07:02 +01009881 if (nr < 0) {
9882 if (errno == 0) {
9883 /* Ctrl+D pressed */
9884 nr = 0;
9885 }
9886# if ENABLE_ASH_IDLE_TIMEOUT
9887 else if (errno == EAGAIN && timeout > 0) {
Denys Vlasenkod60752f2015-10-07 22:42:45 +02009888 puts("\007timed out waiting for input: auto-logout");
Denys Vlasenko66c5b122011-02-08 05:07:02 +01009889 exitshell();
9890 }
9891# endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009892 }
Eric Andersencb57d552001-06-28 07:25:16 +00009893 }
9894#else
Ron Yorston61d6ae22015-04-19 10:50:25 +01009895 nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1);
Eric Andersencb57d552001-06-28 07:25:16 +00009896#endif
9897
Denys Vlasenko80c5b682011-05-08 21:21:10 +02009898#if 0 /* disabled: nonblock_immune_read() handles this problem */
Eric Andersencb57d552001-06-28 07:25:16 +00009899 if (nr < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00009900 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
Denis Vlasenkod37f2222007-08-19 13:42:08 +00009901 int flags = fcntl(0, F_GETFL);
Denis Vlasenko9cb220b2007-12-09 10:03:28 +00009902 if (flags >= 0 && (flags & O_NONBLOCK)) {
9903 flags &= ~O_NONBLOCK;
Eric Andersencb57d552001-06-28 07:25:16 +00009904 if (fcntl(0, F_SETFL, flags) >= 0) {
9905 out2str("sh: turning off NDELAY mode\n");
9906 goto retry;
9907 }
9908 }
9909 }
9910 }
Denis Vlasenkoe376d452008-02-20 22:23:24 +00009911#endif
Eric Andersencb57d552001-06-28 07:25:16 +00009912 return nr;
9913}
9914
9915/*
9916 * Refill the input buffer and return the next input character:
9917 *
9918 * 1) If a string was pushed back on the input, pop it;
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009919 * 2) If an EOF was pushed back (g_parsefile->left_in_line < -BIGNUM)
9920 * or we are reading from a string so we can't refill the buffer,
9921 * return EOF.
Denys Vlasenko883cea42009-07-11 15:31:59 +02009922 * 3) If there is more stuff in this buffer, use it else call read to fill it.
Eric Andersencb57d552001-06-28 07:25:16 +00009923 * 4) Process input up to the next newline, deleting nul characters.
9924 */
Denis Vlasenko727752d2008-11-28 03:41:47 +00009925//#define pgetc_debug(...) bb_error_msg(__VA_ARGS__)
9926#define pgetc_debug(...) ((void)0)
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02009927static int pgetc(void);
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009928static int
Eric Andersenc470f442003-07-28 09:56:35 +00009929preadbuffer(void)
Eric Andersencb57d552001-06-28 07:25:16 +00009930{
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009931 char *q;
Eric Andersencb57d552001-06-28 07:25:16 +00009932 int more;
Eric Andersencb57d552001-06-28 07:25:16 +00009933
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02009934 if (g_parsefile->strpush) {
Denis Vlasenko131ae172007-02-18 13:00:19 +00009935#if ENABLE_ASH_ALIAS
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009936 if (g_parsefile->left_in_line == -1
9937 && g_parsefile->strpush->ap
9938 && g_parsefile->next_to_pgetc[-1] != ' '
9939 && g_parsefile->next_to_pgetc[-1] != '\t'
Denis Vlasenko16898402008-11-25 01:34:52 +00009940 ) {
Denis Vlasenko727752d2008-11-28 03:41:47 +00009941 pgetc_debug("preadbuffer PEOA");
Eric Andersencb57d552001-06-28 07:25:16 +00009942 return PEOA;
9943 }
Eric Andersen2870d962001-07-02 17:27:21 +00009944#endif
Eric Andersencb57d552001-06-28 07:25:16 +00009945 popstring();
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02009946 return pgetc();
Eric Andersencb57d552001-06-28 07:25:16 +00009947 }
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009948 /* on both branches above g_parsefile->left_in_line < 0.
Denis Vlasenko727752d2008-11-28 03:41:47 +00009949 * "pgetc" needs refilling.
9950 */
9951
Denis Vlasenkoe27dafd2008-11-28 04:01:03 +00009952 /* -90 is our -BIGNUM. Below we use -99 to mark "EOF on read",
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009953 * pungetc() may increment it a few times.
Denis Vlasenkoe27dafd2008-11-28 04:01:03 +00009954 * Assuming it won't increment it to less than -90.
Denis Vlasenko727752d2008-11-28 03:41:47 +00009955 */
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009956 if (g_parsefile->left_in_line < -90 || g_parsefile->buf == NULL) {
Denis Vlasenko727752d2008-11-28 03:41:47 +00009957 pgetc_debug("preadbuffer PEOF1");
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009958 /* even in failure keep left_in_line and next_to_pgetc
9959 * in lock step, for correct multi-layer pungetc.
9960 * left_in_line was decremented before preadbuffer(),
9961 * must inc next_to_pgetc: */
9962 g_parsefile->next_to_pgetc++;
Eric Andersencb57d552001-06-28 07:25:16 +00009963 return PEOF;
Denis Vlasenko727752d2008-11-28 03:41:47 +00009964 }
Eric Andersencb57d552001-06-28 07:25:16 +00009965
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009966 more = g_parsefile->left_in_buffer;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009967 if (more <= 0) {
Denis Vlasenko727752d2008-11-28 03:41:47 +00009968 flush_stdout_stderr();
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009969 again:
9970 more = preadfd();
9971 if (more <= 0) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009972 /* don't try reading again */
9973 g_parsefile->left_in_line = -99;
Denis Vlasenko727752d2008-11-28 03:41:47 +00009974 pgetc_debug("preadbuffer PEOF2");
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009975 g_parsefile->next_to_pgetc++;
Eric Andersencb57d552001-06-28 07:25:16 +00009976 return PEOF;
9977 }
9978 }
9979
Denis Vlasenko727752d2008-11-28 03:41:47 +00009980 /* Find out where's the end of line.
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009981 * Set g_parsefile->left_in_line
9982 * and g_parsefile->left_in_buffer acordingly.
Denis Vlasenko727752d2008-11-28 03:41:47 +00009983 * NUL chars are deleted.
9984 */
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009985 q = g_parsefile->next_to_pgetc;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009986 for (;;) {
Denis Vlasenko727752d2008-11-28 03:41:47 +00009987 char c;
Eric Andersencb57d552001-06-28 07:25:16 +00009988
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009989 more--;
Eric Andersenc470f442003-07-28 09:56:35 +00009990
Denis Vlasenko727752d2008-11-28 03:41:47 +00009991 c = *q;
9992 if (c == '\0') {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009993 memmove(q, q + 1, more);
Denis Vlasenko727752d2008-11-28 03:41:47 +00009994 } else {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009995 q++;
9996 if (c == '\n') {
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009997 g_parsefile->left_in_line = q - g_parsefile->next_to_pgetc - 1;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009998 break;
9999 }
Eric Andersencb57d552001-06-28 07:25:16 +000010000 }
10001
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010002 if (more <= 0) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010003 g_parsefile->left_in_line = q - g_parsefile->next_to_pgetc - 1;
10004 if (g_parsefile->left_in_line < 0)
Eric Andersencb57d552001-06-28 07:25:16 +000010005 goto again;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010006 break;
Eric Andersencb57d552001-06-28 07:25:16 +000010007 }
10008 }
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010009 g_parsefile->left_in_buffer = more;
Eric Andersencb57d552001-06-28 07:25:16 +000010010
Eric Andersencb57d552001-06-28 07:25:16 +000010011 if (vflag) {
Denis Vlasenko727752d2008-11-28 03:41:47 +000010012 char save = *q;
10013 *q = '\0';
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010014 out2str(g_parsefile->next_to_pgetc);
Denis Vlasenko727752d2008-11-28 03:41:47 +000010015 *q = save;
Eric Andersencb57d552001-06-28 07:25:16 +000010016 }
10017
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010018 pgetc_debug("preadbuffer at %d:%p'%s'",
10019 g_parsefile->left_in_line,
10020 g_parsefile->next_to_pgetc,
10021 g_parsefile->next_to_pgetc);
Denys Vlasenkocd716832009-11-28 22:14:02 +010010022 return (unsigned char)*g_parsefile->next_to_pgetc++;
Eric Andersencb57d552001-06-28 07:25:16 +000010023}
10024
Denys Vlasenkoce332a22016-10-02 23:47:34 +020010025static void
10026nlprompt(void)
10027{
10028 g_parsefile->linno++;
10029 setprompt_if(doprompt, 2);
10030}
10031static void
10032nlnoprompt(void)
10033{
10034 g_parsefile->linno++;
10035 needprompt = doprompt;
10036}
10037
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010038static int
10039pgetc(void)
10040{
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010041 int c;
10042
10043 pgetc_debug("pgetc at %d:%p'%s'",
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010044 g_parsefile->left_in_line,
10045 g_parsefile->next_to_pgetc,
10046 g_parsefile->next_to_pgetc);
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010047 if (g_parsefile->unget)
10048 return g_parsefile->lastc[--g_parsefile->unget];
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010049
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010050 if (--g_parsefile->left_in_line >= 0)
10051 c = (signed char)*g_parsefile->next_to_pgetc++;
10052 else
10053 c = preadbuffer();
10054
10055 g_parsefile->lastc[1] = g_parsefile->lastc[0];
10056 g_parsefile->lastc[0] = c;
10057
10058 return c;
10059}
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010060
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010061#if ENABLE_ASH_ALIAS
10062static int
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010010063pgetc_without_PEOA(void)
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010064{
10065 int c;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010066 do {
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010067 pgetc_debug("pgetc at %d:%p'%s'",
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010068 g_parsefile->left_in_line,
10069 g_parsefile->next_to_pgetc,
10070 g_parsefile->next_to_pgetc);
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010071 c = pgetc();
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010072 } while (c == PEOA);
10073 return c;
10074}
10075#else
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010010076# define pgetc_without_PEOA() pgetc()
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010077#endif
10078
10079/*
10080 * Read a line from the script.
10081 */
10082static char *
10083pfgets(char *line, int len)
10084{
10085 char *p = line;
10086 int nleft = len;
10087 int c;
10088
10089 while (--nleft > 0) {
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010010090 c = pgetc_without_PEOA();
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010091 if (c == PEOF) {
10092 if (p == line)
10093 return NULL;
10094 break;
10095 }
10096 *p++ = c;
10097 if (c == '\n')
10098 break;
10099 }
10100 *p = '\0';
10101 return line;
10102}
10103
Eric Andersenc470f442003-07-28 09:56:35 +000010104/*
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010105 * Undo a call to pgetc. Only two characters may be pushed back.
Eric Andersenc470f442003-07-28 09:56:35 +000010106 * PEOF may be pushed back.
10107 */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010108static void
Eric Andersenc470f442003-07-28 09:56:35 +000010109pungetc(void)
10110{
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010111 g_parsefile->unget++;
Eric Andersencb57d552001-06-28 07:25:16 +000010112}
10113
Denys Vlasenko73c3e072016-09-29 17:17:04 +020010114/* This one eats backslash+newline */
10115static int
10116pgetc_eatbnl(void)
10117{
10118 int c;
10119
10120 while ((c = pgetc()) == '\\') {
10121 if (pgetc() != '\n') {
10122 pungetc();
10123 break;
10124 }
10125
Denys Vlasenkoce332a22016-10-02 23:47:34 +020010126 nlprompt();
Denys Vlasenko73c3e072016-09-29 17:17:04 +020010127 }
10128
10129 return c;
10130}
10131
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010132/*
10133 * To handle the "." command, a stack of input files is used. Pushfile
10134 * adds a new entry to the stack and popfile restores the previous level.
10135 */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010136static void
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010137pushfile(void)
Eric Andersenc470f442003-07-28 09:56:35 +000010138{
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010139 struct parsefile *pf;
10140
Denis Vlasenko597906c2008-02-20 16:38:54 +000010141 pf = ckzalloc(sizeof(*pf));
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010142 pf->prev = g_parsefile;
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010143 pf->pf_fd = -1;
Denis Vlasenko597906c2008-02-20 16:38:54 +000010144 /*pf->strpush = NULL; - ckzalloc did it */
10145 /*pf->basestrpush.prev = NULL;*/
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010146 /*pf->unget = 0;*/
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010147 g_parsefile = pf;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010148}
10149
10150static void
10151popfile(void)
10152{
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010153 struct parsefile *pf = g_parsefile;
Eric Andersenc470f442003-07-28 09:56:35 +000010154
Denys Vlasenko493b9ca2016-10-30 18:27:14 +010010155 if (pf == &basepf)
10156 return;
10157
Denis Vlasenkob012b102007-02-19 22:43:01 +000010158 INT_OFF;
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010159 if (pf->pf_fd >= 0)
10160 close(pf->pf_fd);
Denis Vlasenko60818682007-09-28 22:07:23 +000010161 free(pf->buf);
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010162 while (pf->strpush)
10163 popstring();
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010164 g_parsefile = pf->prev;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010165 free(pf);
Denis Vlasenkob012b102007-02-19 22:43:01 +000010166 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +000010167}
10168
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010169/*
10170 * Return to top level.
10171 */
10172static void
10173popallfiles(void)
10174{
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010175 while (g_parsefile != &basepf)
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010176 popfile();
10177}
10178
10179/*
10180 * Close the file(s) that the shell is reading commands from. Called
10181 * after a fork is done.
10182 */
10183static void
10184closescript(void)
10185{
10186 popallfiles();
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010187 if (g_parsefile->pf_fd > 0) {
10188 close(g_parsefile->pf_fd);
10189 g_parsefile->pf_fd = 0;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010190 }
10191}
10192
10193/*
10194 * Like setinputfile, but takes an open file descriptor. Call this with
10195 * interrupts off.
10196 */
10197static void
10198setinputfd(int fd, int push)
10199{
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010200 if (push) {
10201 pushfile();
Denis Vlasenko727752d2008-11-28 03:41:47 +000010202 g_parsefile->buf = NULL;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010203 }
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010204 g_parsefile->pf_fd = fd;
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010205 if (g_parsefile->buf == NULL)
10206 g_parsefile->buf = ckmalloc(IBUFSIZ);
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010207 g_parsefile->left_in_buffer = 0;
10208 g_parsefile->left_in_line = 0;
10209 g_parsefile->linno = 1;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010210}
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010211
Eric Andersenc470f442003-07-28 09:56:35 +000010212/*
10213 * Set the input to take input from a file. If push is set, push the
10214 * old input onto the stack first.
10215 */
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010216static int
10217setinputfile(const char *fname, int flags)
Eric Andersenc470f442003-07-28 09:56:35 +000010218{
10219 int fd;
Eric Andersenc470f442003-07-28 09:56:35 +000010220
Denis Vlasenkob012b102007-02-19 22:43:01 +000010221 INT_OFF;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010222 fd = open(fname, O_RDONLY);
10223 if (fd < 0) {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010224 if (flags & INPUT_NOFILE_OK)
10225 goto out;
Denys Vlasenkob7adf7a2016-10-25 17:00:13 +020010226 exitstatus = 127;
Denis Vlasenko9604e1b2009-03-03 18:47:56 +000010227 ash_msg_and_raise_error("can't open '%s'", fname);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010228 }
Denys Vlasenko64774602016-10-26 15:24:30 +020010229 if (fd < 10)
10230 fd = savefd(fd);
Denys Vlasenkoe19923f2016-10-26 15:38:44 +020010231 else
10232 close_on_exec_on(fd);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010233 setinputfd(fd, flags & INPUT_PUSH_FILE);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010234 out:
Denis Vlasenkob012b102007-02-19 22:43:01 +000010235 INT_ON;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010236 return fd;
Eric Andersenc470f442003-07-28 09:56:35 +000010237}
10238
Eric Andersencb57d552001-06-28 07:25:16 +000010239/*
10240 * Like setinputfile, but takes input from a string.
10241 */
Eric Andersenc470f442003-07-28 09:56:35 +000010242static void
10243setinputstring(char *string)
Eric Andersen62483552001-07-10 06:09:16 +000010244{
Denis Vlasenkob012b102007-02-19 22:43:01 +000010245 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +000010246 pushfile();
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010247 g_parsefile->next_to_pgetc = string;
10248 g_parsefile->left_in_line = strlen(string);
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010249 g_parsefile->buf = NULL;
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010250 g_parsefile->linno = 1;
Denis Vlasenkob012b102007-02-19 22:43:01 +000010251 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +000010252}
10253
10254
Denys Vlasenko70392332016-10-27 02:31:55 +020010255/*
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010256 * Routines to check for mail.
Eric Andersencb57d552001-06-28 07:25:16 +000010257 */
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010258
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010259#if ENABLE_ASH_MAIL
Eric Andersencb57d552001-06-28 07:25:16 +000010260
Denys Vlasenko23841622015-10-09 15:52:03 +020010261/* Hash of mtimes of mailboxes */
10262static unsigned mailtime_hash;
Eric Andersenc470f442003-07-28 09:56:35 +000010263/* Set if MAIL or MAILPATH is changed. */
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010264static smallint mail_var_path_changed;
Eric Andersencb57d552001-06-28 07:25:16 +000010265
Eric Andersencb57d552001-06-28 07:25:16 +000010266/*
Eric Andersenc470f442003-07-28 09:56:35 +000010267 * Print appropriate message(s) if mail has arrived.
10268 * If mail_var_path_changed is set,
10269 * then the value of MAIL has mail_var_path_changed,
10270 * so we just update the values.
Eric Andersencb57d552001-06-28 07:25:16 +000010271 */
Eric Andersenc470f442003-07-28 09:56:35 +000010272static void
10273chkmail(void)
Eric Andersencb57d552001-06-28 07:25:16 +000010274{
Eric Andersencb57d552001-06-28 07:25:16 +000010275 const char *mpath;
10276 char *p;
10277 char *q;
Denys Vlasenko23841622015-10-09 15:52:03 +020010278 unsigned new_hash;
Eric Andersencb57d552001-06-28 07:25:16 +000010279 struct stackmark smark;
10280 struct stat statb;
10281
Eric Andersencb57d552001-06-28 07:25:16 +000010282 setstackmark(&smark);
Eric Andersenc470f442003-07-28 09:56:35 +000010283 mpath = mpathset() ? mpathval() : mailval();
Denys Vlasenko23841622015-10-09 15:52:03 +020010284 new_hash = 0;
10285 for (;;) {
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020010286 p = path_advance(&mpath, nullstr);
Eric Andersencb57d552001-06-28 07:25:16 +000010287 if (p == NULL)
10288 break;
10289 if (*p == '\0')
10290 continue;
Denis Vlasenkof7d56652008-03-25 05:51:41 +000010291 for (q = p; *q; q++)
10292 continue;
Denis Vlasenkoa7189f02006-11-17 20:29:00 +000010293#if DEBUG
Eric Andersencb57d552001-06-28 07:25:16 +000010294 if (q[-1] != '/')
10295 abort();
10296#endif
Eric Andersenc470f442003-07-28 09:56:35 +000010297 q[-1] = '\0'; /* delete trailing '/' */
10298 if (stat(p, &statb) < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +000010299 continue;
Eric Andersencb57d552001-06-28 07:25:16 +000010300 }
Denys Vlasenko23841622015-10-09 15:52:03 +020010301 /* Very simplistic "hash": just a sum of all mtimes */
10302 new_hash += (unsigned)statb.st_mtime;
10303 }
10304 if (!mail_var_path_changed && mailtime_hash != new_hash) {
Denys Vlasenko4cd99e72015-10-09 16:02:53 +020010305 if (mailtime_hash != 0)
10306 out2str("you have mail\n");
Denys Vlasenko23841622015-10-09 15:52:03 +020010307 mailtime_hash = new_hash;
Eric Andersencb57d552001-06-28 07:25:16 +000010308 }
Eric Andersenc470f442003-07-28 09:56:35 +000010309 mail_var_path_changed = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010310 popstackmark(&smark);
10311}
Eric Andersencb57d552001-06-28 07:25:16 +000010312
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010313static void FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010314changemail(const char *val UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000010315{
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010316 mail_var_path_changed = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000010317}
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010318
Denis Vlasenko131ae172007-02-18 13:00:19 +000010319#endif /* ASH_MAIL */
Eric Andersenc470f442003-07-28 09:56:35 +000010320
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010321
10322/* ============ ??? */
10323
Eric Andersencb57d552001-06-28 07:25:16 +000010324/*
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010325 * Set the shell parameters.
Eric Andersencb57d552001-06-28 07:25:16 +000010326 */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010327static void
10328setparam(char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000010329{
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010330 char **newparam;
10331 char **ap;
10332 int nparam;
Eric Andersencb57d552001-06-28 07:25:16 +000010333
Denis Vlasenkof7d56652008-03-25 05:51:41 +000010334 for (nparam = 0; argv[nparam]; nparam++)
10335 continue;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010336 ap = newparam = ckmalloc((nparam + 1) * sizeof(*ap));
10337 while (*argv) {
10338 *ap++ = ckstrdup(*argv++);
Eric Andersencb57d552001-06-28 07:25:16 +000010339 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010340 *ap = NULL;
10341 freeparam(&shellparam);
Denis Vlasenko01631112007-12-16 17:20:38 +000010342 shellparam.malloced = 1;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010343 shellparam.nparam = nparam;
10344 shellparam.p = newparam;
10345#if ENABLE_ASH_GETOPTS
10346 shellparam.optind = 1;
10347 shellparam.optoff = -1;
10348#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010349}
10350
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010351/*
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010352 * Process shell options. The global variable argptr contains a pointer
10353 * to the argument list; we advance it past the options.
Denis Vlasenko94e87bc2008-02-14 16:51:58 +000010354 *
10355 * SUSv3 section 2.8.1 "Consequences of Shell Errors" says:
10356 * For a non-interactive shell, an error condition encountered
10357 * by a special built-in ... shall cause the shell to write a diagnostic message
10358 * to standard error and exit as shown in the following table:
Denis Vlasenko56244732008-02-17 15:14:04 +000010359 * Error Special Built-In
Denis Vlasenko94e87bc2008-02-14 16:51:58 +000010360 * ...
10361 * Utility syntax error (option or operand error) Shall exit
10362 * ...
10363 * However, in bug 1142 (http://busybox.net/bugs/view.php?id=1142)
10364 * we see that bash does not do that (set "finishes" with error code 1 instead,
10365 * and shell continues), and people rely on this behavior!
10366 * Testcase:
10367 * set -o barfoo 2>/dev/null
10368 * echo $?
10369 *
10370 * Oh well. Let's mimic that.
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010371 */
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010372static int
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010373plus_minus_o(char *name, int val)
Eric Andersen62483552001-07-10 06:09:16 +000010374{
10375 int i;
10376
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010377 if (name) {
10378 for (i = 0; i < NOPTS; i++) {
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000010379 if (strcmp(name, optnames(i)) == 0) {
Eric Andersenc470f442003-07-28 09:56:35 +000010380 optlist[i] = val;
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010381 return 0;
Eric Andersen62483552001-07-10 06:09:16 +000010382 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010383 }
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010384 ash_msg("illegal option %co %s", val ? '-' : '+', name);
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010385 return 1;
Eric Andersen62483552001-07-10 06:09:16 +000010386 }
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000010387 for (i = 0; i < NOPTS; i++) {
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010388 if (val) {
10389 out1fmt("%-16s%s\n", optnames(i), optlist[i] ? "on" : "off");
10390 } else {
10391 out1fmt("set %co %s\n", optlist[i] ? '-' : '+', optnames(i));
10392 }
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000010393 }
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010394 return 0;
Eric Andersen62483552001-07-10 06:09:16 +000010395}
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010396static void
10397setoption(int flag, int val)
10398{
10399 int i;
10400
10401 for (i = 0; i < NOPTS; i++) {
10402 if (optletters(i) == flag) {
10403 optlist[i] = val;
10404 return;
10405 }
10406 }
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010407 ash_msg_and_raise_error("illegal option %c%c", val ? '-' : '+', flag);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010408 /* NOTREACHED */
10409}
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010410static int
Eric Andersenc470f442003-07-28 09:56:35 +000010411options(int cmdline)
Eric Andersencb57d552001-06-28 07:25:16 +000010412{
10413 char *p;
10414 int val;
10415 int c;
10416
10417 if (cmdline)
10418 minusc = NULL;
10419 while ((p = *argptr) != NULL) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010420 c = *p++;
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010421 if (c != '-' && c != '+')
10422 break;
10423 argptr++;
10424 val = 0; /* val = 0 if c == '+' */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010425 if (c == '-') {
Eric Andersencb57d552001-06-28 07:25:16 +000010426 val = 1;
Denis Vlasenko9f739442006-12-16 23:49:13 +000010427 if (p[0] == '\0' || LONE_DASH(p)) {
Eric Andersen2870d962001-07-02 17:27:21 +000010428 if (!cmdline) {
10429 /* "-" means turn off -x and -v */
10430 if (p[0] == '\0')
10431 xflag = vflag = 0;
10432 /* "--" means reset params */
10433 else if (*argptr == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +000010434 setparam(argptr);
Eric Andersen2870d962001-07-02 17:27:21 +000010435 }
Denys Vlasenkob0b83432011-03-07 12:34:59 +010010436 break; /* "-" or "--" terminates options */
Eric Andersencb57d552001-06-28 07:25:16 +000010437 }
Eric Andersencb57d552001-06-28 07:25:16 +000010438 }
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010439 /* first char was + or - */
Eric Andersencb57d552001-06-28 07:25:16 +000010440 while ((c = *p++) != '\0') {
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010441 /* bash 3.2 indeed handles -c CMD and +c CMD the same */
Eric Andersencb57d552001-06-28 07:25:16 +000010442 if (c == 'c' && cmdline) {
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010443 minusc = p; /* command is after shell args */
Eric Andersencb57d552001-06-28 07:25:16 +000010444 } else if (c == 'o') {
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010445 if (plus_minus_o(*argptr, val)) {
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010446 /* it already printed err message */
10447 return 1; /* error */
10448 }
Eric Andersencb57d552001-06-28 07:25:16 +000010449 if (*argptr)
10450 argptr++;
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010451 } else if (cmdline && (c == 'l')) { /* -l or +l == --login */
10452 isloginsh = 1;
10453 /* bash does not accept +-login, we also won't */
10454 } else if (cmdline && val && (c == '-')) { /* long options */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010455 if (strcmp(p, "login") == 0)
Robert Griebl64f70cc2002-05-14 23:22:06 +000010456 isloginsh = 1;
10457 break;
Eric Andersencb57d552001-06-28 07:25:16 +000010458 } else {
10459 setoption(c, val);
10460 }
10461 }
10462 }
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010463 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010464}
10465
Eric Andersencb57d552001-06-28 07:25:16 +000010466/*
Eric Andersencb57d552001-06-28 07:25:16 +000010467 * The shift builtin command.
10468 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010469static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010470shiftcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000010471{
10472 int n;
10473 char **ap1, **ap2;
10474
10475 n = 1;
Denis Vlasenko68404f12008-03-17 09:00:54 +000010476 if (argv[1])
Eric Andersencb57d552001-06-28 07:25:16 +000010477 n = number(argv[1]);
10478 if (n > shellparam.nparam)
Denis Vlasenkoc90e1be2008-07-30 15:35:05 +000010479 n = 0; /* bash compat, was = shellparam.nparam; */
Denis Vlasenkob012b102007-02-19 22:43:01 +000010480 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +000010481 shellparam.nparam -= n;
Denis Vlasenko2da584f2007-02-19 22:44:05 +000010482 for (ap1 = shellparam.p; --n >= 0; ap1++) {
Denis Vlasenko01631112007-12-16 17:20:38 +000010483 if (shellparam.malloced)
Denis Vlasenkob012b102007-02-19 22:43:01 +000010484 free(*ap1);
Eric Andersencb57d552001-06-28 07:25:16 +000010485 }
10486 ap2 = shellparam.p;
Denis Vlasenkof7d56652008-03-25 05:51:41 +000010487 while ((*ap2++ = *ap1++) != NULL)
10488 continue;
Denis Vlasenko131ae172007-02-18 13:00:19 +000010489#if ENABLE_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +000010490 shellparam.optind = 1;
10491 shellparam.optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +000010492#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +000010493 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +000010494 return 0;
10495}
10496
Eric Andersencb57d552001-06-28 07:25:16 +000010497/*
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010498 * POSIX requires that 'set' (but not export or readonly) output the
10499 * variables in lexicographic order - by the locale's collating order (sigh).
10500 * Maybe we could keep them in an ordered balanced binary tree
10501 * instead of hashed lists.
10502 * For now just roll 'em through qsort for printing...
10503 */
10504static int
10505showvars(const char *sep_prefix, int on, int off)
10506{
10507 const char *sep;
10508 char **ep, **epend;
10509
10510 ep = listvars(on, off, &epend);
10511 qsort(ep, epend - ep, sizeof(char *), vpcmp);
10512
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010513 sep = *sep_prefix ? " " : sep_prefix;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010514
10515 for (; ep < epend; ep++) {
10516 const char *p;
10517 const char *q;
10518
10519 p = strchrnul(*ep, '=');
10520 q = nullstr;
10521 if (*p)
10522 q = single_quote(++p);
10523 out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
10524 }
10525 return 0;
10526}
10527
10528/*
Eric Andersencb57d552001-06-28 07:25:16 +000010529 * The set command builtin.
10530 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010531static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010532setcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +000010533{
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010534 int retval;
10535
Denis Vlasenko68404f12008-03-17 09:00:54 +000010536 if (!argv[1])
Eric Andersenc470f442003-07-28 09:56:35 +000010537 return showvars(nullstr, 0, VUNSET);
Denys Vlasenkob0b83432011-03-07 12:34:59 +010010538
Denis Vlasenkob012b102007-02-19 22:43:01 +000010539 INT_OFF;
Denys Vlasenkob0b83432011-03-07 12:34:59 +010010540 retval = options(/*cmdline:*/ 0);
10541 if (retval == 0) { /* if no parse error... */
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010542 optschanged();
10543 if (*argptr != NULL) {
10544 setparam(argptr);
10545 }
Eric Andersencb57d552001-06-28 07:25:16 +000010546 }
Denis Vlasenkob012b102007-02-19 22:43:01 +000010547 INT_ON;
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010548 return retval;
Eric Andersencb57d552001-06-28 07:25:16 +000010549}
10550
Denis Vlasenko131ae172007-02-18 13:00:19 +000010551#if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010552static void FAST_FUNC
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000010553change_random(const char *value)
Eric Andersenef02f822004-03-11 13:34:24 +000010554{
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020010555 uint32_t t;
10556
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000010557 if (value == NULL) {
Eric Andersen16767e22004-03-16 05:14:10 +000010558 /* "get", generate */
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020010559 t = next_random(&random_gen);
Eric Andersen16767e22004-03-16 05:14:10 +000010560 /* set without recursion */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +020010561 setvar(vrandom.var_text, utoa(t), VNOFUNC);
Eric Andersen16767e22004-03-16 05:14:10 +000010562 vrandom.flags &= ~VNOFUNC;
10563 } else {
10564 /* set/reset */
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020010565 t = strtoul(value, NULL, 10);
10566 INIT_RANDOM_T(&random_gen, (t ? t : 1), t);
Eric Andersen16767e22004-03-16 05:14:10 +000010567 }
Eric Andersenef02f822004-03-11 13:34:24 +000010568}
Eric Andersen16767e22004-03-16 05:14:10 +000010569#endif
10570
Denis Vlasenko131ae172007-02-18 13:00:19 +000010571#if ENABLE_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +000010572static int
Denys Vlasenko35c2a132016-10-26 17:34:26 +020010573getopts(char *optstr, char *optvar, char **optfirst)
Eric Andersencb57d552001-06-28 07:25:16 +000010574{
10575 char *p, *q;
10576 char c = '?';
10577 int done = 0;
Denys Vlasenko9c541002015-10-07 15:44:36 +020010578 char sbuf[2];
Eric Andersena48b0a32003-10-22 10:56:47 +000010579 char **optnext;
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010580 int ind = shellparam.optind;
10581 int off = shellparam.optoff;
Eric Andersencb57d552001-06-28 07:25:16 +000010582
Denys Vlasenko9c541002015-10-07 15:44:36 +020010583 sbuf[1] = '\0';
10584
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010585 shellparam.optind = -1;
10586 optnext = optfirst + ind - 1;
Eric Andersena48b0a32003-10-22 10:56:47 +000010587
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010588 if (ind <= 1 || off < 0 || (int)strlen(optnext[-1]) < off)
Eric Andersencb57d552001-06-28 07:25:16 +000010589 p = NULL;
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010590 else
10591 p = optnext[-1] + off;
Eric Andersencb57d552001-06-28 07:25:16 +000010592 if (p == NULL || *p == '\0') {
10593 /* Current word is done, advance */
Eric Andersencb57d552001-06-28 07:25:16 +000010594 p = *optnext;
10595 if (p == NULL || *p != '-' || *++p == '\0') {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010596 atend:
Eric Andersencb57d552001-06-28 07:25:16 +000010597 p = NULL;
10598 done = 1;
10599 goto out;
10600 }
10601 optnext++;
Denis Vlasenko9f739442006-12-16 23:49:13 +000010602 if (LONE_DASH(p)) /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +000010603 goto atend;
10604 }
10605
10606 c = *p++;
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +000010607 for (q = optstr; *q != c;) {
Eric Andersencb57d552001-06-28 07:25:16 +000010608 if (*q == '\0') {
10609 if (optstr[0] == ':') {
Denys Vlasenko9c541002015-10-07 15:44:36 +020010610 sbuf[0] = c;
10611 /*sbuf[1] = '\0'; - already is */
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010612 setvar0("OPTARG", sbuf);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010613 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010614 fprintf(stderr, "Illegal option -%c\n", c);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010615 unsetvar("OPTARG");
Eric Andersencb57d552001-06-28 07:25:16 +000010616 }
10617 c = '?';
Eric Andersenc470f442003-07-28 09:56:35 +000010618 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +000010619 }
10620 if (*++q == ':')
10621 q++;
10622 }
10623
10624 if (*++q == ':') {
10625 if (*p == '\0' && (p = *optnext) == NULL) {
10626 if (optstr[0] == ':') {
Denys Vlasenko9c541002015-10-07 15:44:36 +020010627 sbuf[0] = c;
10628 /*sbuf[1] = '\0'; - already is */
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010629 setvar0("OPTARG", sbuf);
Eric Andersencb57d552001-06-28 07:25:16 +000010630 c = ':';
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010631 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010632 fprintf(stderr, "No arg for -%c option\n", c);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010633 unsetvar("OPTARG");
Eric Andersencb57d552001-06-28 07:25:16 +000010634 c = '?';
10635 }
Eric Andersenc470f442003-07-28 09:56:35 +000010636 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +000010637 }
10638
10639 if (p == *optnext)
10640 optnext++;
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010641 setvar0("OPTARG", p);
Eric Andersencb57d552001-06-28 07:25:16 +000010642 p = NULL;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010643 } else
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010644 setvar0("OPTARG", nullstr);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010645 out:
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010646 ind = optnext - optfirst + 1;
10647 setvar("OPTIND", itoa(ind), VNOFUNC);
Denys Vlasenko9c541002015-10-07 15:44:36 +020010648 sbuf[0] = c;
10649 /*sbuf[1] = '\0'; - already is */
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010650 setvar0(optvar, sbuf);
10651
10652 shellparam.optoff = p ? p - *(optnext - 1) : -1;
10653 shellparam.optind = ind;
10654
Eric Andersencb57d552001-06-28 07:25:16 +000010655 return done;
10656}
Eric Andersenc470f442003-07-28 09:56:35 +000010657
10658/*
10659 * The getopts builtin. Shellparam.optnext points to the next argument
10660 * to be processed. Shellparam.optptr points to the next character to
10661 * be processed in the current argument. If shellparam.optnext is NULL,
10662 * then it's the first time getopts has been called.
10663 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010664static int FAST_FUNC
Eric Andersenc470f442003-07-28 09:56:35 +000010665getoptscmd(int argc, char **argv)
10666{
10667 char **optbase;
10668
10669 if (argc < 3)
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +000010670 ash_msg_and_raise_error("usage: getopts optstring var [arg]");
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010671 if (argc == 3) {
Eric Andersenc470f442003-07-28 09:56:35 +000010672 optbase = shellparam.p;
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010673 if ((unsigned)shellparam.optind > shellparam.nparam + 1) {
Eric Andersenc470f442003-07-28 09:56:35 +000010674 shellparam.optind = 1;
10675 shellparam.optoff = -1;
10676 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010677 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010678 optbase = &argv[3];
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010679 if ((unsigned)shellparam.optind > argc - 2) {
Eric Andersenc470f442003-07-28 09:56:35 +000010680 shellparam.optind = 1;
10681 shellparam.optoff = -1;
10682 }
10683 }
10684
Denys Vlasenko35c2a132016-10-26 17:34:26 +020010685 return getopts(argv[1], argv[2], optbase);
Eric Andersenc470f442003-07-28 09:56:35 +000010686}
Denis Vlasenko131ae172007-02-18 13:00:19 +000010687#endif /* ASH_GETOPTS */
Eric Andersencb57d552001-06-28 07:25:16 +000010688
Eric Andersencb57d552001-06-28 07:25:16 +000010689
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010690/* ============ Shell parser */
Eric Andersencb57d552001-06-28 07:25:16 +000010691
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010692struct heredoc {
10693 struct heredoc *next; /* next here document in list */
10694 union node *here; /* redirection node */
10695 char *eofmark; /* string indicating end of input */
10696 smallint striptabs; /* if set, strip leading tabs */
10697};
10698
10699static smallint tokpushback; /* last token pushed back */
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010700static smallint quoteflag; /* set if (part of) last token was quoted */
10701static token_id_t lasttoken; /* last token read (integer id Txxx) */
10702static struct heredoc *heredoclist; /* list of here documents to read */
10703static char *wordtext; /* text of last word returned by readtoken */
10704static struct nodelist *backquotelist;
10705static union node *redirnode;
10706static struct heredoc *heredoc;
Denis Vlasenko99eb8502007-02-23 21:09:49 +000010707
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010708static const char *
10709tokname(char *buf, int tok)
10710{
10711 if (tok < TSEMI)
Denys Vlasenko888527c2016-10-02 16:54:17 +020010712 return tokname_array[tok];
10713 sprintf(buf, "\"%s\"", tokname_array[tok]);
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010714 return buf;
10715}
10716
10717/* raise_error_unexpected_syntax:
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010718 * Called when an unexpected token is read during the parse. The argument
10719 * is the token that is expected, or -1 if more than one type of token can
10720 * occur at this point.
10721 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010722static void raise_error_unexpected_syntax(int) NORETURN;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010723static void
10724raise_error_unexpected_syntax(int token)
10725{
10726 char msg[64];
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010727 char buf[16];
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010728 int l;
10729
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010730 l = sprintf(msg, "unexpected %s", tokname(buf, lasttoken));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010731 if (token >= 0)
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010732 sprintf(msg + l, " (expecting %s)", tokname(buf, token));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010733 raise_error_syntax(msg);
10734 /* NOTREACHED */
10735}
Eric Andersencb57d552001-06-28 07:25:16 +000010736
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010737#define EOFMARKLEN 79
Eric Andersencb57d552001-06-28 07:25:16 +000010738
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010739/* parsing is heavily cross-recursive, need these forward decls */
10740static union node *andor(void);
10741static union node *pipeline(void);
10742static union node *parse_command(void);
10743static void parseheredoc(void);
Ron Yorstonc0e00762015-10-29 11:30:55 +000010744static int peektoken(void);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010745static int readtoken(void);
Eric Andersencb57d552001-06-28 07:25:16 +000010746
Eric Andersenc470f442003-07-28 09:56:35 +000010747static union node *
10748list(int nlflag)
Eric Andersencb57d552001-06-28 07:25:16 +000010749{
10750 union node *n1, *n2, *n3;
10751 int tok;
10752
Eric Andersencb57d552001-06-28 07:25:16 +000010753 n1 = NULL;
10754 for (;;) {
Ron Yorstonc0e00762015-10-29 11:30:55 +000010755 switch (peektoken()) {
10756 case TNL:
10757 if (!(nlflag & 1))
10758 break;
10759 parseheredoc();
10760 return n1;
10761
10762 case TEOF:
10763 if (!n1 && (nlflag & 1))
10764 n1 = NODE_EOF;
10765 parseheredoc();
10766 return n1;
10767 }
10768
10769 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Denys Vlasenko888527c2016-10-02 16:54:17 +020010770 if (nlflag == 2 && ((1 << peektoken()) & tokendlist))
Ron Yorstonc0e00762015-10-29 11:30:55 +000010771 return n1;
10772 nlflag |= 2;
10773
Eric Andersencb57d552001-06-28 07:25:16 +000010774 n2 = andor();
10775 tok = readtoken();
10776 if (tok == TBACKGND) {
Eric Andersenc470f442003-07-28 09:56:35 +000010777 if (n2->type == NPIPE) {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +000010778 n2->npipe.pipe_backgnd = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010779 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010780 if (n2->type != NREDIR) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000010781 n3 = stzalloc(sizeof(struct nredir));
Eric Andersenc470f442003-07-28 09:56:35 +000010782 n3->nredir.n = n2;
Denis Vlasenko597906c2008-02-20 16:38:54 +000010783 /*n3->nredir.redirect = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000010784 n2 = n3;
10785 }
10786 n2->type = NBACKGND;
Eric Andersencb57d552001-06-28 07:25:16 +000010787 }
10788 }
10789 if (n1 == NULL) {
10790 n1 = n2;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010791 } else {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010792 n3 = stzalloc(sizeof(struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +000010793 n3->type = NSEMI;
10794 n3->nbinary.ch1 = n1;
10795 n3->nbinary.ch2 = n2;
10796 n1 = n3;
10797 }
10798 switch (tok) {
Ron Yorstonc0e00762015-10-29 11:30:55 +000010799 case TNL:
10800 case TEOF:
10801 tokpushback = 1;
10802 /* fall through */
Eric Andersencb57d552001-06-28 07:25:16 +000010803 case TBACKGND:
10804 case TSEMI:
Eric Andersencb57d552001-06-28 07:25:16 +000010805 break;
Eric Andersencb57d552001-06-28 07:25:16 +000010806 default:
Ron Yorstonc0e00762015-10-29 11:30:55 +000010807 if ((nlflag & 1))
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010808 raise_error_unexpected_syntax(-1);
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010809 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010810 return n1;
10811 }
10812 }
10813}
10814
Eric Andersenc470f442003-07-28 09:56:35 +000010815static union node *
10816andor(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010817{
Eric Andersencb57d552001-06-28 07:25:16 +000010818 union node *n1, *n2, *n3;
10819 int t;
10820
Eric Andersencb57d552001-06-28 07:25:16 +000010821 n1 = pipeline();
10822 for (;;) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010823 t = readtoken();
10824 if (t == TAND) {
Eric Andersencb57d552001-06-28 07:25:16 +000010825 t = NAND;
10826 } else if (t == TOR) {
10827 t = NOR;
10828 } else {
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010829 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010830 return n1;
10831 }
Eric Andersenc470f442003-07-28 09:56:35 +000010832 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000010833 n2 = pipeline();
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010834 n3 = stzalloc(sizeof(struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +000010835 n3->type = t;
10836 n3->nbinary.ch1 = n1;
10837 n3->nbinary.ch2 = n2;
10838 n1 = n3;
10839 }
10840}
10841
Eric Andersenc470f442003-07-28 09:56:35 +000010842static union node *
10843pipeline(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010844{
Eric Andersencb57d552001-06-28 07:25:16 +000010845 union node *n1, *n2, *pipenode;
10846 struct nodelist *lp, *prev;
10847 int negate;
10848
10849 negate = 0;
10850 TRACE(("pipeline: entered\n"));
10851 if (readtoken() == TNOT) {
10852 negate = !negate;
Eric Andersenc470f442003-07-28 09:56:35 +000010853 checkkwd = CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000010854 } else
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010855 tokpushback = 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010856 n1 = parse_command();
Eric Andersencb57d552001-06-28 07:25:16 +000010857 if (readtoken() == TPIPE) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000010858 pipenode = stzalloc(sizeof(struct npipe));
Eric Andersencb57d552001-06-28 07:25:16 +000010859 pipenode->type = NPIPE;
Denis Vlasenko2dc240c2008-07-24 06:07:50 +000010860 /*pipenode->npipe.pipe_backgnd = 0; - stzalloc did it */
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010861 lp = stzalloc(sizeof(struct nodelist));
Eric Andersencb57d552001-06-28 07:25:16 +000010862 pipenode->npipe.cmdlist = lp;
10863 lp->n = n1;
10864 do {
10865 prev = lp;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010866 lp = stzalloc(sizeof(struct nodelist));
Eric Andersenc470f442003-07-28 09:56:35 +000010867 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010868 lp->n = parse_command();
Eric Andersencb57d552001-06-28 07:25:16 +000010869 prev->next = lp;
10870 } while (readtoken() == TPIPE);
10871 lp->next = NULL;
10872 n1 = pipenode;
10873 }
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010874 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010875 if (negate) {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010876 n2 = stzalloc(sizeof(struct nnot));
Eric Andersencb57d552001-06-28 07:25:16 +000010877 n2->type = NNOT;
10878 n2->nnot.com = n1;
10879 return n2;
Denis Vlasenko2da584f2007-02-19 22:44:05 +000010880 }
10881 return n1;
Eric Andersencb57d552001-06-28 07:25:16 +000010882}
10883
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010884static union node *
10885makename(void)
10886{
10887 union node *n;
10888
Denis Vlasenko597906c2008-02-20 16:38:54 +000010889 n = stzalloc(sizeof(struct narg));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010890 n->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000010891 /*n->narg.next = NULL; - stzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010892 n->narg.text = wordtext;
10893 n->narg.backquote = backquotelist;
10894 return n;
10895}
10896
10897static void
10898fixredir(union node *n, const char *text, int err)
10899{
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000010900 int fd;
10901
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010902 TRACE(("Fix redir %s %d\n", text, err));
10903 if (!err)
10904 n->ndup.vname = NULL;
10905
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000010906 fd = bb_strtou(text, NULL, 10);
10907 if (!errno && fd >= 0)
10908 n->ndup.dupfd = fd;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010909 else if (LONE_DASH(text))
10910 n->ndup.dupfd = -1;
10911 else {
10912 if (err)
Denis Vlasenko559691a2008-10-05 18:39:31 +000010913 raise_error_syntax("bad fd number");
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010914 n->ndup.vname = makename();
10915 }
10916}
10917
10918/*
10919 * Returns true if the text contains nothing to expand (no dollar signs
10920 * or backquotes).
10921 */
10922static int
Denis Vlasenko68819d12008-12-15 11:26:36 +000010923noexpand(const char *text)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010924{
Denys Vlasenkocd716832009-11-28 22:14:02 +010010925 unsigned char c;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010926
Denys Vlasenkocd716832009-11-28 22:14:02 +010010927 while ((c = *text++) != '\0') {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010928 if (c == CTLQUOTEMARK)
10929 continue;
10930 if (c == CTLESC)
Denys Vlasenkocd716832009-11-28 22:14:02 +010010931 text++;
Denys Vlasenko76bc2d62009-11-29 01:37:46 +010010932 else if (SIT(c, BASESYNTAX) == CCTL)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010933 return 0;
10934 }
10935 return 1;
10936}
10937
10938static void
10939parsefname(void)
10940{
10941 union node *n = redirnode;
10942
10943 if (readtoken() != TWORD)
10944 raise_error_unexpected_syntax(-1);
10945 if (n->type == NHERE) {
10946 struct heredoc *here = heredoc;
10947 struct heredoc *p;
10948 int i;
10949
10950 if (quoteflag == 0)
10951 n->type = NXHERE;
10952 TRACE(("Here document %d\n", n->type));
10953 if (!noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
Denis Vlasenko559691a2008-10-05 18:39:31 +000010954 raise_error_syntax("illegal eof marker for << redirection");
Denys Vlasenkob6c84342009-08-29 20:23:20 +020010955 rmescapes(wordtext, 0);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010956 here->eofmark = wordtext;
10957 here->next = NULL;
10958 if (heredoclist == NULL)
10959 heredoclist = here;
10960 else {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010961 for (p = heredoclist; p->next; p = p->next)
10962 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010963 p->next = here;
10964 }
10965 } else if (n->type == NTOFD || n->type == NFROMFD) {
10966 fixredir(n, wordtext, 0);
10967 } else {
10968 n->nfile.fname = makename();
10969 }
10970}
Eric Andersencb57d552001-06-28 07:25:16 +000010971
Eric Andersenc470f442003-07-28 09:56:35 +000010972static union node *
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010973simplecmd(void)
10974{
10975 union node *args, **app;
10976 union node *n = NULL;
10977 union node *vars, **vpp;
10978 union node **rpp, *redir;
10979 int savecheckkwd;
Denis Vlasenko80591b02008-03-25 07:49:43 +000010980#if ENABLE_ASH_BASH_COMPAT
10981 smallint double_brackets_flag = 0;
Ron Yorston95ebcf72015-11-03 09:42:23 +000010982 smallint function_flag = 0;
Denis Vlasenko80591b02008-03-25 07:49:43 +000010983#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010984
10985 args = NULL;
10986 app = &args;
10987 vars = NULL;
10988 vpp = &vars;
10989 redir = NULL;
10990 rpp = &redir;
10991
10992 savecheckkwd = CHKALIAS;
10993 for (;;) {
Denis Vlasenko80591b02008-03-25 07:49:43 +000010994 int t;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010995 checkkwd = savecheckkwd;
Denis Vlasenko80591b02008-03-25 07:49:43 +000010996 t = readtoken();
10997 switch (t) {
10998#if ENABLE_ASH_BASH_COMPAT
Ron Yorston95ebcf72015-11-03 09:42:23 +000010999 case TFUNCTION:
11000 if (peektoken() != TWORD)
11001 raise_error_unexpected_syntax(TWORD);
11002 function_flag = 1;
11003 break;
Denis Vlasenko80591b02008-03-25 07:49:43 +000011004 case TAND: /* "&&" */
11005 case TOR: /* "||" */
11006 if (!double_brackets_flag) {
11007 tokpushback = 1;
11008 goto out;
11009 }
11010 wordtext = (char *) (t == TAND ? "-a" : "-o");
11011#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011012 case TWORD:
Denis Vlasenko597906c2008-02-20 16:38:54 +000011013 n = stzalloc(sizeof(struct narg));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011014 n->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011015 /*n->narg.next = NULL; - stzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011016 n->narg.text = wordtext;
Denis Vlasenko80591b02008-03-25 07:49:43 +000011017#if ENABLE_ASH_BASH_COMPAT
11018 if (strcmp("[[", wordtext) == 0)
11019 double_brackets_flag = 1;
11020 else if (strcmp("]]", wordtext) == 0)
11021 double_brackets_flag = 0;
11022#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011023 n->narg.backquote = backquotelist;
11024 if (savecheckkwd && isassignment(wordtext)) {
11025 *vpp = n;
11026 vpp = &n->narg.next;
11027 } else {
11028 *app = n;
11029 app = &n->narg.next;
11030 savecheckkwd = 0;
11031 }
Ron Yorston95ebcf72015-11-03 09:42:23 +000011032#if ENABLE_ASH_BASH_COMPAT
11033 if (function_flag) {
11034 checkkwd = CHKNL | CHKKWD;
11035 switch (peektoken()) {
11036 case TBEGIN:
11037 case TIF:
11038 case TCASE:
11039 case TUNTIL:
11040 case TWHILE:
11041 case TFOR:
11042 goto do_func;
11043 case TLP:
11044 function_flag = 0;
11045 break;
11046 case TWORD:
11047 if (strcmp("[[", wordtext) == 0)
11048 goto do_func;
11049 /* fall through */
11050 default:
11051 raise_error_unexpected_syntax(-1);
11052 }
11053 }
11054#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011055 break;
11056 case TREDIR:
11057 *rpp = n = redirnode;
11058 rpp = &n->nfile.next;
11059 parsefname(); /* read name of redirection file */
11060 break;
11061 case TLP:
Ron Yorston95ebcf72015-11-03 09:42:23 +000011062 IF_ASH_BASH_COMPAT(do_func:)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011063 if (args && app == &args->narg.next
11064 && !vars && !redir
11065 ) {
11066 struct builtincmd *bcmd;
11067 const char *name;
11068
11069 /* We have a function */
Ron Yorston95ebcf72015-11-03 09:42:23 +000011070 if (IF_ASH_BASH_COMPAT(!function_flag &&) readtoken() != TRP)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011071 raise_error_unexpected_syntax(TRP);
11072 name = n->narg.text;
11073 if (!goodname(name)
11074 || ((bcmd = find_builtin(name)) && IS_BUILTIN_SPECIAL(bcmd))
11075 ) {
Denis Vlasenko559691a2008-10-05 18:39:31 +000011076 raise_error_syntax("bad function name");
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011077 }
11078 n->type = NDEFUN;
11079 checkkwd = CHKNL | CHKKWD | CHKALIAS;
11080 n->narg.next = parse_command();
11081 return n;
11082 }
Ron Yorston95ebcf72015-11-03 09:42:23 +000011083 IF_ASH_BASH_COMPAT(function_flag = 0;)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011084 /* fall through */
11085 default:
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011086 tokpushback = 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011087 goto out;
11088 }
11089 }
11090 out:
11091 *app = NULL;
11092 *vpp = NULL;
11093 *rpp = NULL;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011094 n = stzalloc(sizeof(struct ncmd));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011095 n->type = NCMD;
11096 n->ncmd.args = args;
11097 n->ncmd.assign = vars;
11098 n->ncmd.redirect = redir;
11099 return n;
11100}
11101
11102static union node *
11103parse_command(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011104{
Eric Andersencb57d552001-06-28 07:25:16 +000011105 union node *n1, *n2;
11106 union node *ap, **app;
11107 union node *cp, **cpp;
11108 union node *redir, **rpp;
Eric Andersenc470f442003-07-28 09:56:35 +000011109 union node **rpp2;
Eric Andersencb57d552001-06-28 07:25:16 +000011110 int t;
11111
11112 redir = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +000011113 rpp2 = &redir;
Eric Andersen88cec252001-09-06 17:35:20 +000011114
Eric Andersencb57d552001-06-28 07:25:16 +000011115 switch (readtoken()) {
Eric Andersenc470f442003-07-28 09:56:35 +000011116 default:
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011117 raise_error_unexpected_syntax(-1);
Eric Andersenc470f442003-07-28 09:56:35 +000011118 /* NOTREACHED */
Eric Andersencb57d552001-06-28 07:25:16 +000011119 case TIF:
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011120 n1 = stzalloc(sizeof(struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +000011121 n1->type = NIF;
11122 n1->nif.test = list(0);
11123 if (readtoken() != TTHEN)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011124 raise_error_unexpected_syntax(TTHEN);
Eric Andersencb57d552001-06-28 07:25:16 +000011125 n1->nif.ifpart = list(0);
11126 n2 = n1;
11127 while (readtoken() == TELIF) {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011128 n2->nif.elsepart = stzalloc(sizeof(struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +000011129 n2 = n2->nif.elsepart;
11130 n2->type = NIF;
11131 n2->nif.test = list(0);
11132 if (readtoken() != TTHEN)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011133 raise_error_unexpected_syntax(TTHEN);
Eric Andersencb57d552001-06-28 07:25:16 +000011134 n2->nif.ifpart = list(0);
11135 }
11136 if (lasttoken == TELSE)
11137 n2->nif.elsepart = list(0);
11138 else {
11139 n2->nif.elsepart = NULL;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011140 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011141 }
Eric Andersenc470f442003-07-28 09:56:35 +000011142 t = TFI;
Eric Andersencb57d552001-06-28 07:25:16 +000011143 break;
11144 case TWHILE:
Eric Andersenc470f442003-07-28 09:56:35 +000011145 case TUNTIL: {
Eric Andersencb57d552001-06-28 07:25:16 +000011146 int got;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011147 n1 = stzalloc(sizeof(struct nbinary));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011148 n1->type = (lasttoken == TWHILE) ? NWHILE : NUNTIL;
Eric Andersencb57d552001-06-28 07:25:16 +000011149 n1->nbinary.ch1 = list(0);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011150 got = readtoken();
11151 if (got != TDO) {
Denys Vlasenko888527c2016-10-02 16:54:17 +020011152 TRACE(("expecting DO got '%s' %s\n", tokname_array[got],
Denis Vlasenko131ae172007-02-18 13:00:19 +000011153 got == TWORD ? wordtext : ""));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011154 raise_error_unexpected_syntax(TDO);
Eric Andersencb57d552001-06-28 07:25:16 +000011155 }
11156 n1->nbinary.ch2 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +000011157 t = TDONE;
Eric Andersencb57d552001-06-28 07:25:16 +000011158 break;
11159 }
11160 case TFOR:
Denis Vlasenko2dc240c2008-07-24 06:07:50 +000011161 if (readtoken() != TWORD || quoteflag || !goodname(wordtext))
Denis Vlasenko559691a2008-10-05 18:39:31 +000011162 raise_error_syntax("bad for loop variable");
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011163 n1 = stzalloc(sizeof(struct nfor));
Eric Andersencb57d552001-06-28 07:25:16 +000011164 n1->type = NFOR;
11165 n1->nfor.var = wordtext;
Ron Yorstonab80e012015-08-03 13:46:00 +010011166 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000011167 if (readtoken() == TIN) {
11168 app = &ap;
11169 while (readtoken() == TWORD) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011170 n2 = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000011171 n2->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011172 /*n2->narg.next = NULL; - stzalloc did it */
Eric Andersencb57d552001-06-28 07:25:16 +000011173 n2->narg.text = wordtext;
11174 n2->narg.backquote = backquotelist;
11175 *app = n2;
11176 app = &n2->narg.next;
11177 }
11178 *app = NULL;
11179 n1->nfor.args = ap;
11180 if (lasttoken != TNL && lasttoken != TSEMI)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011181 raise_error_unexpected_syntax(-1);
Eric Andersencb57d552001-06-28 07:25:16 +000011182 } else {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011183 n2 = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000011184 n2->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011185 /*n2->narg.next = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011186 n2->narg.text = (char *)dolatstr;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011187 /*n2->narg.backquote = NULL;*/
Eric Andersencb57d552001-06-28 07:25:16 +000011188 n1->nfor.args = n2;
11189 /*
11190 * Newline or semicolon here is optional (but note
11191 * that the original Bourne shell only allowed NL).
11192 */
Ron Yorstonab80e012015-08-03 13:46:00 +010011193 if (lasttoken != TSEMI)
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011194 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011195 }
Eric Andersenc470f442003-07-28 09:56:35 +000011196 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000011197 if (readtoken() != TDO)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011198 raise_error_unexpected_syntax(TDO);
Eric Andersencb57d552001-06-28 07:25:16 +000011199 n1->nfor.body = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +000011200 t = TDONE;
Eric Andersencb57d552001-06-28 07:25:16 +000011201 break;
11202 case TCASE:
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011203 n1 = stzalloc(sizeof(struct ncase));
Eric Andersencb57d552001-06-28 07:25:16 +000011204 n1->type = NCASE;
11205 if (readtoken() != TWORD)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011206 raise_error_unexpected_syntax(TWORD);
Denis Vlasenko597906c2008-02-20 16:38:54 +000011207 n1->ncase.expr = n2 = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000011208 n2->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011209 /*n2->narg.next = NULL; - stzalloc did it */
Eric Andersencb57d552001-06-28 07:25:16 +000011210 n2->narg.text = wordtext;
11211 n2->narg.backquote = backquotelist;
Ron Yorston383b8852015-08-03 13:46:25 +010011212 checkkwd = CHKNL | CHKKWD | CHKALIAS;
11213 if (readtoken() != TIN)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011214 raise_error_unexpected_syntax(TIN);
Eric Andersencb57d552001-06-28 07:25:16 +000011215 cpp = &n1->ncase.cases;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011216 next_case:
Eric Andersenc470f442003-07-28 09:56:35 +000011217 checkkwd = CHKNL | CHKKWD;
11218 t = readtoken();
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011219 while (t != TESAC) {
Eric Andersencb57d552001-06-28 07:25:16 +000011220 if (lasttoken == TLP)
11221 readtoken();
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011222 *cpp = cp = stzalloc(sizeof(struct nclist));
Eric Andersencb57d552001-06-28 07:25:16 +000011223 cp->type = NCLIST;
11224 app = &cp->nclist.pattern;
11225 for (;;) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011226 *app = ap = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000011227 ap->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011228 /*ap->narg.next = NULL; - stzalloc did it */
Eric Andersencb57d552001-06-28 07:25:16 +000011229 ap->narg.text = wordtext;
11230 ap->narg.backquote = backquotelist;
Eric Andersenc470f442003-07-28 09:56:35 +000011231 if (readtoken() != TPIPE)
Eric Andersencb57d552001-06-28 07:25:16 +000011232 break;
11233 app = &ap->narg.next;
11234 readtoken();
11235 }
Denis Vlasenko597906c2008-02-20 16:38:54 +000011236 //ap->narg.next = NULL;
Eric Andersencb57d552001-06-28 07:25:16 +000011237 if (lasttoken != TRP)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011238 raise_error_unexpected_syntax(TRP);
Eric Andersenc470f442003-07-28 09:56:35 +000011239 cp->nclist.body = list(2);
Eric Andersencb57d552001-06-28 07:25:16 +000011240
Eric Andersenc470f442003-07-28 09:56:35 +000011241 cpp = &cp->nclist.next;
11242
11243 checkkwd = CHKNL | CHKKWD;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011244 t = readtoken();
11245 if (t != TESAC) {
Eric Andersencb57d552001-06-28 07:25:16 +000011246 if (t != TENDCASE)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011247 raise_error_unexpected_syntax(TENDCASE);
11248 goto next_case;
Eric Andersencb57d552001-06-28 07:25:16 +000011249 }
Eric Andersenc470f442003-07-28 09:56:35 +000011250 }
Eric Andersencb57d552001-06-28 07:25:16 +000011251 *cpp = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +000011252 goto redir;
Eric Andersencb57d552001-06-28 07:25:16 +000011253 case TLP:
Denis Vlasenko597906c2008-02-20 16:38:54 +000011254 n1 = stzalloc(sizeof(struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +000011255 n1->type = NSUBSHELL;
11256 n1->nredir.n = list(0);
Denis Vlasenko597906c2008-02-20 16:38:54 +000011257 /*n1->nredir.redirect = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011258 t = TRP;
Eric Andersencb57d552001-06-28 07:25:16 +000011259 break;
11260 case TBEGIN:
11261 n1 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +000011262 t = TEND;
Eric Andersencb57d552001-06-28 07:25:16 +000011263 break;
Ron Yorston95ebcf72015-11-03 09:42:23 +000011264 IF_ASH_BASH_COMPAT(case TFUNCTION:)
Eric Andersencb57d552001-06-28 07:25:16 +000011265 case TWORD:
Eric Andersenc470f442003-07-28 09:56:35 +000011266 case TREDIR:
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011267 tokpushback = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000011268 return simplecmd();
Eric Andersencb57d552001-06-28 07:25:16 +000011269 }
11270
Eric Andersenc470f442003-07-28 09:56:35 +000011271 if (readtoken() != t)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011272 raise_error_unexpected_syntax(t);
Eric Andersenc470f442003-07-28 09:56:35 +000011273
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011274 redir:
Eric Andersencb57d552001-06-28 07:25:16 +000011275 /* Now check for redirection which may follow command */
Eric Andersenc470f442003-07-28 09:56:35 +000011276 checkkwd = CHKKWD | CHKALIAS;
11277 rpp = rpp2;
Eric Andersencb57d552001-06-28 07:25:16 +000011278 while (readtoken() == TREDIR) {
11279 *rpp = n2 = redirnode;
11280 rpp = &n2->nfile.next;
11281 parsefname();
11282 }
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011283 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011284 *rpp = NULL;
11285 if (redir) {
11286 if (n1->type != NSUBSHELL) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011287 n2 = stzalloc(sizeof(struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +000011288 n2->type = NREDIR;
11289 n2->nredir.n = n1;
11290 n1 = n2;
11291 }
11292 n1->nredir.redirect = redir;
11293 }
Eric Andersencb57d552001-06-28 07:25:16 +000011294 return n1;
11295}
11296
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011297#if ENABLE_ASH_BASH_COMPAT
Denys Vlasenko37dc08b2016-10-02 04:38:07 +020011298static int
11299decode_dollar_squote(void)
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011300{
11301 static const char C_escapes[] ALIGN1 = "nrbtfav""x\\01234567";
11302 int c, cnt;
11303 char *p;
11304 char buf[4];
11305
11306 c = pgetc();
11307 p = strchr(C_escapes, c);
11308 if (p) {
11309 buf[0] = c;
11310 p = buf;
11311 cnt = 3;
11312 if ((unsigned char)(c - '0') <= 7) { /* \ooo */
11313 do {
11314 c = pgetc();
11315 *++p = c;
11316 } while ((unsigned char)(c - '0') <= 7 && --cnt);
11317 pungetc();
11318 } else if (c == 'x') { /* \xHH */
11319 do {
11320 c = pgetc();
11321 *++p = c;
11322 } while (isxdigit(c) && --cnt);
11323 pungetc();
11324 if (cnt == 3) { /* \x but next char is "bad" */
11325 c = 'x';
11326 goto unrecognized;
11327 }
11328 } else { /* simple seq like \\ or \t */
11329 p++;
11330 }
11331 *p = '\0';
11332 p = buf;
11333 c = bb_process_escape_sequence((void*)&p);
11334 } else { /* unrecognized "\z": print both chars unless ' or " */
11335 if (c != '\'' && c != '"') {
11336 unrecognized:
11337 c |= 0x100; /* "please encode \, then me" */
11338 }
11339 }
11340 return c;
11341}
11342#endif
11343
Eric Andersencb57d552001-06-28 07:25:16 +000011344/*
11345 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
11346 * is not NULL, read a here document. In the latter case, eofmark is the
11347 * word which marks the end of the document and striptabs is true if
Denys Vlasenkocd716832009-11-28 22:14:02 +010011348 * leading tabs should be stripped from the document. The argument c
Eric Andersencb57d552001-06-28 07:25:16 +000011349 * is the first character of the input token or document.
11350 *
11351 * Because C does not have internal subroutines, I have simulated them
11352 * using goto's to implement the subroutine linkage. The following macros
11353 * will run code that appears at the end of readtoken1.
11354 */
Eric Andersen2870d962001-07-02 17:27:21 +000011355#define CHECKEND() {goto checkend; checkend_return:;}
11356#define PARSEREDIR() {goto parseredir; parseredir_return:;}
11357#define PARSESUB() {goto parsesub; parsesub_return:;}
11358#define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
11359#define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
11360#define PARSEARITH() {goto parsearith; parsearith_return:;}
Eric Andersencb57d552001-06-28 07:25:16 +000011361static int
Denys Vlasenkocd716832009-11-28 22:14:02 +010011362readtoken1(int c, int syntax, char *eofmark, int striptabs)
Manuel Novoa III 16815d42001-08-10 19:36:07 +000011363{
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011364 /* NB: syntax parameter fits into smallint */
Denys Vlasenkocd716832009-11-28 22:14:02 +010011365 /* c parameter is an unsigned char or PEOF or PEOA */
Eric Andersencb57d552001-06-28 07:25:16 +000011366 char *out;
Denys Vlasenko50e6d422016-09-30 11:35:54 +020011367 size_t len;
Eric Andersencb57d552001-06-28 07:25:16 +000011368 char line[EOFMARKLEN + 1];
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011369 struct nodelist *bqlist;
11370 smallint quotef;
11371 smallint dblquote;
11372 smallint oldstyle;
11373 smallint prevsyntax; /* syntax before arithmetic */
Denis Vlasenko46a53062007-09-24 18:30:02 +000011374#if ENABLE_ASH_EXPAND_PRMT
11375 smallint pssyntax; /* we are expanding a prompt string */
11376#endif
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011377 int varnest; /* levels of variables expansion */
11378 int arinest; /* levels of arithmetic expansion */
11379 int parenlevel; /* levels of parens in arithmetic */
11380 int dqvarnest; /* levels of variables expansion within double quotes */
11381
Denis Vlasenko5e34ff22009-04-21 11:09:40 +000011382 IF_ASH_BASH_COMPAT(smallint bash_dollar_squote = 0;)
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011383
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011384 startlinno = g_parsefile->linno;
Eric Andersencb57d552001-06-28 07:25:16 +000011385 bqlist = NULL;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011386 quotef = 0;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011387 prevsyntax = 0;
Denis Vlasenko46a53062007-09-24 18:30:02 +000011388#if ENABLE_ASH_EXPAND_PRMT
11389 pssyntax = (syntax == PSSYNTAX);
11390 if (pssyntax)
11391 syntax = DQSYNTAX;
11392#endif
11393 dblquote = (syntax == DQSYNTAX);
Eric Andersencb57d552001-06-28 07:25:16 +000011394 varnest = 0;
11395 arinest = 0;
11396 parenlevel = 0;
11397 dqvarnest = 0;
11398
11399 STARTSTACKSTR(out);
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011400 loop:
11401 /* For each line, until end of word */
Denys Vlasenko958581a2010-09-12 15:04:27 +020011402 CHECKEND(); /* set c to PEOF if at end of here document */
11403 for (;;) { /* until end of line or end of word */
11404 CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */
11405 switch (SIT(c, syntax)) {
11406 case CNL: /* '\n' */
11407 if (syntax == BASESYNTAX)
11408 goto endword; /* exit outer loop */
11409 USTPUTC(c, out);
Denys Vlasenkoce332a22016-10-02 23:47:34 +020011410 nlprompt();
Denys Vlasenko958581a2010-09-12 15:04:27 +020011411 c = pgetc();
11412 goto loop; /* continue outer loop */
11413 case CWORD:
11414 USTPUTC(c, out);
11415 break;
11416 case CCTL:
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011417#if ENABLE_ASH_BASH_COMPAT
Denys Vlasenko958581a2010-09-12 15:04:27 +020011418 if (c == '\\' && bash_dollar_squote) {
11419 c = decode_dollar_squote();
Denys Vlasenko13f20912016-09-25 20:54:25 +020011420 if (c == '\0') {
11421 /* skip $'\000', $'\x00' (like bash) */
11422 break;
11423 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020011424 if (c & 0x100) {
Denys Vlasenko13f20912016-09-25 20:54:25 +020011425 /* Unknown escape. Encode as '\z' */
Denys Vlasenko958581a2010-09-12 15:04:27 +020011426 c = (unsigned char)c;
Denys Vlasenko13f20912016-09-25 20:54:25 +020011427 if (eofmark == NULL || dblquote)
11428 USTPUTC(CTLESC, out);
11429 USTPUTC('\\', out);
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011430 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020011431 }
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011432#endif
Denys Vlasenko13f20912016-09-25 20:54:25 +020011433 if (eofmark == NULL || dblquote)
11434 USTPUTC(CTLESC, out);
Denys Vlasenko958581a2010-09-12 15:04:27 +020011435 USTPUTC(c, out);
11436 break;
11437 case CBACK: /* backslash */
11438 c = pgetc_without_PEOA();
11439 if (c == PEOF) {
11440 USTPUTC(CTLESC, out);
11441 USTPUTC('\\', out);
11442 pungetc();
11443 } else if (c == '\n') {
Denys Vlasenkoce332a22016-10-02 23:47:34 +020011444 nlprompt();
Denys Vlasenko958581a2010-09-12 15:04:27 +020011445 } else {
11446#if ENABLE_ASH_EXPAND_PRMT
11447 if (c == '$' && pssyntax) {
Eric Andersenc470f442003-07-28 09:56:35 +000011448 USTPUTC(CTLESC, out);
Eric Andersencb57d552001-06-28 07:25:16 +000011449 USTPUTC('\\', out);
Denys Vlasenko958581a2010-09-12 15:04:27 +020011450 }
Denis Vlasenko46a53062007-09-24 18:30:02 +000011451#endif
Denys Vlasenko958581a2010-09-12 15:04:27 +020011452 /* Backslash is retained if we are in "str" and next char isn't special */
11453 if (dblquote
11454 && c != '\\'
11455 && c != '`'
11456 && c != '$'
11457 && (c != '"' || eofmark != NULL)
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011458 ) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020011459 USTPUTC('\\', out);
Eric Andersencb57d552001-06-28 07:25:16 +000011460 }
Ron Yorston549deab2015-05-18 09:57:51 +020011461 USTPUTC(CTLESC, out);
Denys Vlasenko0ff78a02010-08-30 15:20:07 +020011462 USTPUTC(c, out);
Denys Vlasenko958581a2010-09-12 15:04:27 +020011463 quotef = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011464 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020011465 break;
11466 case CSQUOTE:
11467 syntax = SQSYNTAX;
11468 quotemark:
11469 if (eofmark == NULL) {
11470 USTPUTC(CTLQUOTEMARK, out);
11471 }
11472 break;
11473 case CDQUOTE:
11474 syntax = DQSYNTAX;
11475 dblquote = 1;
11476 goto quotemark;
11477 case CENDQUOTE:
11478 IF_ASH_BASH_COMPAT(bash_dollar_squote = 0;)
Ron Yorston7e4ed262015-05-18 09:54:43 +020011479 if (eofmark != NULL && varnest == 0) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020011480 USTPUTC(c, out);
11481 } else {
11482 if (dqvarnest == 0) {
11483 syntax = BASESYNTAX;
11484 dblquote = 0;
11485 }
11486 quotef = 1;
11487 goto quotemark;
11488 }
11489 break;
11490 case CVAR: /* '$' */
11491 PARSESUB(); /* parse substitution */
11492 break;
11493 case CENDVAR: /* '}' */
11494 if (varnest > 0) {
11495 varnest--;
11496 if (dqvarnest > 0) {
11497 dqvarnest--;
11498 }
11499 c = CTLENDVAR;
11500 }
11501 USTPUTC(c, out);
11502 break;
11503#if ENABLE_SH_MATH_SUPPORT
11504 case CLP: /* '(' in arithmetic */
11505 parenlevel++;
11506 USTPUTC(c, out);
11507 break;
11508 case CRP: /* ')' in arithmetic */
11509 if (parenlevel > 0) {
11510 parenlevel--;
11511 } else {
Denys Vlasenko459293b2016-09-29 17:58:58 +020011512 if (pgetc_eatbnl() == ')') {
Ron Yorstonad88bde2015-05-18 09:56:16 +020011513 c = CTLENDARI;
Denys Vlasenko958581a2010-09-12 15:04:27 +020011514 if (--arinest == 0) {
11515 syntax = prevsyntax;
Denys Vlasenko958581a2010-09-12 15:04:27 +020011516 }
11517 } else {
11518 /*
11519 * unbalanced parens
11520 * (don't 2nd guess - no error)
11521 */
11522 pungetc();
11523 }
11524 }
11525 USTPUTC(c, out);
11526 break;
11527#endif
11528 case CBQUOTE: /* '`' */
11529 PARSEBACKQOLD();
11530 break;
11531 case CENDFILE:
11532 goto endword; /* exit outer loop */
11533 case CIGN:
11534 break;
11535 default:
11536 if (varnest == 0) {
11537#if ENABLE_ASH_BASH_COMPAT
11538 if (c == '&') {
Denys Vlasenko459293b2016-09-29 17:58:58 +020011539//Can't call pgetc_eatbnl() here, this requires three-deep pungetc()
Denys Vlasenko958581a2010-09-12 15:04:27 +020011540 if (pgetc() == '>')
11541 c = 0x100 + '>'; /* flag &> */
11542 pungetc();
11543 }
11544#endif
11545 goto endword; /* exit outer loop */
11546 }
11547 IF_ASH_ALIAS(if (c != PEOA))
11548 USTPUTC(c, out);
11549 }
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020011550 c = pgetc();
Denys Vlasenko958581a2010-09-12 15:04:27 +020011551 } /* for (;;) */
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011552 endword:
Denys Vlasenko958581a2010-09-12 15:04:27 +020011553
Mike Frysinger98c52642009-04-02 10:02:37 +000011554#if ENABLE_SH_MATH_SUPPORT
Eric Andersencb57d552001-06-28 07:25:16 +000011555 if (syntax == ARISYNTAX)
Denis Vlasenko559691a2008-10-05 18:39:31 +000011556 raise_error_syntax("missing '))'");
Eric Andersenc470f442003-07-28 09:56:35 +000011557#endif
Ron Yorston0e056f72015-07-01 16:45:40 +010011558 if (syntax != BASESYNTAX && eofmark == NULL)
Denis Vlasenko559691a2008-10-05 18:39:31 +000011559 raise_error_syntax("unterminated quoted string");
Eric Andersencb57d552001-06-28 07:25:16 +000011560 if (varnest != 0) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011561 startlinno = g_parsefile->linno;
Eric Andersenc470f442003-07-28 09:56:35 +000011562 /* { */
Denis Vlasenko559691a2008-10-05 18:39:31 +000011563 raise_error_syntax("missing '}'");
Eric Andersencb57d552001-06-28 07:25:16 +000011564 }
11565 USTPUTC('\0', out);
Eric Andersenc470f442003-07-28 09:56:35 +000011566 len = out - (char *)stackblock();
Eric Andersencb57d552001-06-28 07:25:16 +000011567 out = stackblock();
11568 if (eofmark == NULL) {
Denis Vlasenko5e34ff22009-04-21 11:09:40 +000011569 if ((c == '>' || c == '<' IF_ASH_BASH_COMPAT( || c == 0x100 + '>'))
Denis Vlasenko834dee72008-10-07 09:18:30 +000011570 && quotef == 0
11571 ) {
Denis Vlasenko559691a2008-10-05 18:39:31 +000011572 if (isdigit_str9(out)) {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000011573 PARSEREDIR(); /* passed as params: out, c */
11574 lasttoken = TREDIR;
11575 return lasttoken;
11576 }
11577 /* else: non-number X seen, interpret it
11578 * as "NNNX>file" = "NNNX >file" */
Eric Andersencb57d552001-06-28 07:25:16 +000011579 }
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011580 pungetc();
Eric Andersencb57d552001-06-28 07:25:16 +000011581 }
11582 quoteflag = quotef;
11583 backquotelist = bqlist;
11584 grabstackblock(len);
11585 wordtext = out;
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011586 lasttoken = TWORD;
11587 return lasttoken;
Eric Andersencb57d552001-06-28 07:25:16 +000011588/* end of readtoken routine */
11589
Eric Andersencb57d552001-06-28 07:25:16 +000011590/*
11591 * Check to see whether we are at the end of the here document. When this
11592 * is called, c is set to the first character of the next input line. If
11593 * we are at the end of the here document, this routine sets the c to PEOF.
11594 */
Eric Andersenc470f442003-07-28 09:56:35 +000011595checkend: {
11596 if (eofmark) {
Denis Vlasenko131ae172007-02-18 13:00:19 +000011597#if ENABLE_ASH_ALIAS
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010011598 if (c == PEOA)
11599 c = pgetc_without_PEOA();
Eric Andersenc470f442003-07-28 09:56:35 +000011600#endif
11601 if (striptabs) {
11602 while (c == '\t') {
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010011603 c = pgetc_without_PEOA();
Eric Andersencb57d552001-06-28 07:25:16 +000011604 }
Eric Andersenc470f442003-07-28 09:56:35 +000011605 }
11606 if (c == *eofmark) {
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011607 if (pfgets(line, sizeof(line)) != NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +000011608 char *p, *q;
Denys Vlasenko350e6862016-10-26 16:26:45 +020011609 int cc;
Eric Andersencb57d552001-06-28 07:25:16 +000011610
Eric Andersenc470f442003-07-28 09:56:35 +000011611 p = line;
Denys Vlasenko350e6862016-10-26 16:26:45 +020011612 for (q = eofmark + 1;; p++, q++) {
11613 cc = *p;
11614 if (cc == '\n')
11615 cc = 0;
11616 if (!*q || cc != *q)
11617 break;
11618 }
11619 if (cc == *q) {
Eric Andersenc470f442003-07-28 09:56:35 +000011620 c = PEOF;
Denys Vlasenkoce332a22016-10-02 23:47:34 +020011621 nlnoprompt();
Eric Andersenc470f442003-07-28 09:56:35 +000011622 } else {
11623 pushstring(line, NULL);
Eric Andersencb57d552001-06-28 07:25:16 +000011624 }
11625 }
11626 }
11627 }
Eric Andersenc470f442003-07-28 09:56:35 +000011628 goto checkend_return;
11629}
Eric Andersencb57d552001-06-28 07:25:16 +000011630
Eric Andersencb57d552001-06-28 07:25:16 +000011631/*
11632 * Parse a redirection operator. The variable "out" points to a string
11633 * specifying the fd to be redirected. The variable "c" contains the
11634 * first character of the redirection operator.
11635 */
Eric Andersenc470f442003-07-28 09:56:35 +000011636parseredir: {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000011637 /* out is already checked to be a valid number or "" */
11638 int fd = (*out == '\0' ? -1 : atoi(out));
Eric Andersenc470f442003-07-28 09:56:35 +000011639 union node *np;
Eric Andersencb57d552001-06-28 07:25:16 +000011640
Denis Vlasenko597906c2008-02-20 16:38:54 +000011641 np = stzalloc(sizeof(struct nfile));
Eric Andersenc470f442003-07-28 09:56:35 +000011642 if (c == '>') {
11643 np->nfile.fd = 1;
11644 c = pgetc();
11645 if (c == '>')
11646 np->type = NAPPEND;
11647 else if (c == '|')
11648 np->type = NCLOBBER;
11649 else if (c == '&')
11650 np->type = NTOFD;
Denis Vlasenko559691a2008-10-05 18:39:31 +000011651 /* it also can be NTO2 (>&file), but we can't figure it out yet */
Eric Andersenc470f442003-07-28 09:56:35 +000011652 else {
11653 np->type = NTO;
11654 pungetc();
Eric Andersencb57d552001-06-28 07:25:16 +000011655 }
Denis Vlasenko834dee72008-10-07 09:18:30 +000011656 }
11657#if ENABLE_ASH_BASH_COMPAT
11658 else if (c == 0x100 + '>') { /* this flags &> redirection */
11659 np->nfile.fd = 1;
11660 pgetc(); /* this is '>', no need to check */
11661 np->type = NTO2;
11662 }
11663#endif
11664 else { /* c == '<' */
Denis Vlasenko597906c2008-02-20 16:38:54 +000011665 /*np->nfile.fd = 0; - stzalloc did it */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011666 c = pgetc();
11667 switch (c) {
Eric Andersenc470f442003-07-28 09:56:35 +000011668 case '<':
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011669 if (sizeof(struct nfile) != sizeof(struct nhere)) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011670 np = stzalloc(sizeof(struct nhere));
11671 /*np->nfile.fd = 0; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011672 }
11673 np->type = NHERE;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011674 heredoc = stzalloc(sizeof(struct heredoc));
Eric Andersenc470f442003-07-28 09:56:35 +000011675 heredoc->here = np;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011676 c = pgetc();
11677 if (c == '-') {
Eric Andersenc470f442003-07-28 09:56:35 +000011678 heredoc->striptabs = 1;
11679 } else {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011680 /*heredoc->striptabs = 0; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011681 pungetc();
11682 }
11683 break;
11684
11685 case '&':
11686 np->type = NFROMFD;
11687 break;
11688
11689 case '>':
11690 np->type = NFROMTO;
11691 break;
11692
11693 default:
11694 np->type = NFROM;
11695 pungetc();
11696 break;
11697 }
Eric Andersencb57d552001-06-28 07:25:16 +000011698 }
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000011699 if (fd >= 0)
11700 np->nfile.fd = fd;
Eric Andersenc470f442003-07-28 09:56:35 +000011701 redirnode = np;
11702 goto parseredir_return;
11703}
Eric Andersencb57d552001-06-28 07:25:16 +000011704
Eric Andersencb57d552001-06-28 07:25:16 +000011705/*
11706 * Parse a substitution. At this point, we have read the dollar sign
11707 * and nothing else.
11708 */
Denis Vlasenkocc571512007-02-23 21:10:35 +000011709
11710/* is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise
11711 * (assuming ascii char codes, as the original implementation did) */
11712#define is_special(c) \
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011713 (((unsigned)(c) - 33 < 32) \
11714 && ((0xc1ff920dU >> ((unsigned)(c) - 33)) & 1))
Eric Andersenc470f442003-07-28 09:56:35 +000011715parsesub: {
Denys Vlasenkocd716832009-11-28 22:14:02 +010011716 unsigned char subtype;
Eric Andersenc470f442003-07-28 09:56:35 +000011717 int typeloc;
Eric Andersencb57d552001-06-28 07:25:16 +000011718
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011719 c = pgetc_eatbnl();
Denys Vlasenkocd716832009-11-28 22:14:02 +010011720 if (c > 255 /* PEOA or PEOF */
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011721 || (c != '(' && c != '{' && !is_name(c) && !is_special(c))
Eric Andersenc470f442003-07-28 09:56:35 +000011722 ) {
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011723#if ENABLE_ASH_BASH_COMPAT
Ron Yorston84ba50c2016-04-03 22:43:14 +010011724 if (syntax != DQSYNTAX && c == '\'')
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011725 bash_dollar_squote = 1;
11726 else
11727#endif
11728 USTPUTC('$', out);
Eric Andersenc470f442003-07-28 09:56:35 +000011729 pungetc();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011730 } else if (c == '(') {
11731 /* $(command) or $((arith)) */
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011732 if (pgetc_eatbnl() == '(') {
Mike Frysinger98c52642009-04-02 10:02:37 +000011733#if ENABLE_SH_MATH_SUPPORT
Eric Andersenc470f442003-07-28 09:56:35 +000011734 PARSEARITH();
11735#else
Mike Frysinger98a6f562008-06-09 09:38:45 +000011736 raise_error_syntax("you disabled math support for $((arith)) syntax");
Eric Andersenc470f442003-07-28 09:56:35 +000011737#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011738 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000011739 pungetc();
11740 PARSEBACKQNEW();
11741 }
11742 } else {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011743 /* $VAR, $<specialchar>, ${...}, or PEOA/PEOF */
Eric Andersenc470f442003-07-28 09:56:35 +000011744 USTPUTC(CTLVAR, out);
11745 typeloc = out - (char *)stackblock();
Denys Vlasenko3df14102016-10-26 16:41:13 +020011746 STADJUST(1, out);
Eric Andersenc470f442003-07-28 09:56:35 +000011747 subtype = VSNORMAL;
11748 if (c == '{') {
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011749 c = pgetc_eatbnl();
Denys Vlasenkof15aa572016-10-26 15:56:53 +020011750 subtype = 0;
Eric Andersenc470f442003-07-28 09:56:35 +000011751 }
Denys Vlasenkof15aa572016-10-26 15:56:53 +020011752 varname:
Denys Vlasenko3df14102016-10-26 16:41:13 +020011753 if (is_name(c)) {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011754 /* $[{[#]]NAME[}] */
Eric Andersenc470f442003-07-28 09:56:35 +000011755 do {
11756 STPUTC(c, out);
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011757 c = pgetc_eatbnl();
Denys Vlasenko3df14102016-10-26 16:41:13 +020011758 } while (is_in_name(c));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011759 } else if (isdigit(c)) {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011760 /* $[{[#]]NUM[}] */
Eric Andersenc470f442003-07-28 09:56:35 +000011761 do {
11762 STPUTC(c, out);
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011763 c = pgetc_eatbnl();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011764 } while (isdigit(c));
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011765 } else if (is_special(c)) {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011766 /* $[{[#]]<specialchar>[}] */
Denys Vlasenkof15aa572016-10-26 15:56:53 +020011767 int cc = c;
11768
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011769 c = pgetc_eatbnl();
Denys Vlasenkof15aa572016-10-26 15:56:53 +020011770 if (!subtype && cc == '#') {
11771 subtype = VSLENGTH;
11772 if (c == '_' || isalnum(c))
11773 goto varname;
11774 cc = c;
11775 c = pgetc_eatbnl();
11776 if (cc == '}' || c != '}') {
11777 pungetc();
11778 subtype = 0;
11779 c = cc;
11780 cc = '#';
11781 }
11782 }
11783 USTPUTC(cc, out);
Denis Vlasenko559691a2008-10-05 18:39:31 +000011784 } else {
Denys Vlasenko88e15702016-10-26 01:55:56 +020011785 goto badsub;
Denis Vlasenko559691a2008-10-05 18:39:31 +000011786 }
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011787 if (c != '}' && subtype == VSLENGTH) {
11788 /* ${#VAR didn't end with } */
Cristian Ionescu-Idbohrn301f5ec2009-10-05 02:07:23 +020011789 goto badsub;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011790 }
Eric Andersencb57d552001-06-28 07:25:16 +000011791
Eric Andersenc470f442003-07-28 09:56:35 +000011792 if (subtype == 0) {
Denys Vlasenkof8ddbe12016-07-25 03:56:00 +020011793 static const char types[] ALIGN1 = "}-+?=";
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011794 /* ${VAR...} but not $VAR or ${#VAR} */
11795 /* c == first char after VAR */
Eric Andersenc470f442003-07-28 09:56:35 +000011796 switch (c) {
11797 case ':':
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011798 c = pgetc_eatbnl();
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011799#if ENABLE_ASH_BASH_COMPAT
Denys Vlasenkof8ddbe12016-07-25 03:56:00 +020011800 /* This check is only needed to not misinterpret
11801 * ${VAR:-WORD}, ${VAR:+WORD}, ${VAR:=WORD}, ${VAR:?WORD}
11802 * constructs.
11803 */
11804 if (!strchr(types, c)) {
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011805 subtype = VSSUBSTR;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011806 pungetc();
Denys Vlasenko88e15702016-10-26 01:55:56 +020011807 break; /* "goto badsub" is bigger (!) */
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011808 }
11809#endif
Denys Vlasenko3df14102016-10-26 16:41:13 +020011810 subtype = VSNUL;
Eric Andersenc470f442003-07-28 09:56:35 +000011811 /*FALLTHROUGH*/
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011812 default: {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011813 const char *p = strchr(types, c);
Eric Andersenc470f442003-07-28 09:56:35 +000011814 if (p == NULL)
Denys Vlasenko88e15702016-10-26 01:55:56 +020011815 break;
Denys Vlasenko3df14102016-10-26 16:41:13 +020011816 subtype |= p - types + VSNORMAL;
Eric Andersenc470f442003-07-28 09:56:35 +000011817 break;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011818 }
Eric Andersenc470f442003-07-28 09:56:35 +000011819 case '%':
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011820 case '#': {
11821 int cc = c;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011822 subtype = (c == '#' ? VSTRIMLEFT : VSTRIMRIGHT);
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011823 c = pgetc_eatbnl();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011824 if (c != cc)
Denys Vlasenko88e15702016-10-26 01:55:56 +020011825 goto badsub;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011826 subtype++;
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011827 break;
11828 }
11829#if ENABLE_ASH_BASH_COMPAT
11830 case '/':
Denys Vlasenko6040fe82010-09-12 15:03:16 +020011831 /* ${v/[/]pattern/repl} */
11832//TODO: encode pattern and repl separately.
11833// Currently ${v/$var_with_slash/repl} is horribly broken
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011834 subtype = VSREPLACE;
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011835 c = pgetc_eatbnl();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011836 if (c != '/')
Denys Vlasenko88e15702016-10-26 01:55:56 +020011837 goto badsub;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011838 subtype++; /* VSREPLACEALL */
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011839 break;
11840#endif
Eric Andersencb57d552001-06-28 07:25:16 +000011841 }
Eric Andersenc470f442003-07-28 09:56:35 +000011842 } else {
Denys Vlasenko88e15702016-10-26 01:55:56 +020011843 badsub:
Eric Andersenc470f442003-07-28 09:56:35 +000011844 pungetc();
11845 }
Denys Vlasenko3df14102016-10-26 16:41:13 +020011846 ((unsigned char *)stackblock())[typeloc] = subtype;
Eric Andersenc470f442003-07-28 09:56:35 +000011847 if (subtype != VSNORMAL) {
11848 varnest++;
Denys Vlasenko3df14102016-10-26 16:41:13 +020011849 if (dblquote)
Eric Andersenc470f442003-07-28 09:56:35 +000011850 dqvarnest++;
Eric Andersencb57d552001-06-28 07:25:16 +000011851 }
Denys Vlasenko88e15702016-10-26 01:55:56 +020011852 STPUTC('=', out);
Eric Andersencb57d552001-06-28 07:25:16 +000011853 }
Eric Andersenc470f442003-07-28 09:56:35 +000011854 goto parsesub_return;
11855}
Eric Andersencb57d552001-06-28 07:25:16 +000011856
Eric Andersencb57d552001-06-28 07:25:16 +000011857/*
11858 * Called to parse command substitutions. Newstyle is set if the command
11859 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
11860 * list of commands (passed by reference), and savelen is the number of
11861 * characters on the top of the stack which must be preserved.
11862 */
Eric Andersenc470f442003-07-28 09:56:35 +000011863parsebackq: {
11864 struct nodelist **nlpp;
Eric Andersenc470f442003-07-28 09:56:35 +000011865 union node *n;
Ron Yorston072fc602015-07-01 16:46:18 +010011866 char *str;
Eric Andersenc470f442003-07-28 09:56:35 +000011867 size_t savelen;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011868 smallint saveprompt = 0;
11869
Eric Andersenc470f442003-07-28 09:56:35 +000011870 str = NULL;
11871 savelen = out - (char *)stackblock();
11872 if (savelen > 0) {
Denys Vlasenko7bc3d392016-09-17 20:53:47 +020011873 /*
11874 * FIXME: this can allocate very large block on stack and SEGV.
11875 * Example:
11876 * echo "..<100kbytes>..`true` $(true) `true` ..."
Denys Vlasenko73737592016-09-17 20:58:22 +020011877 * allocates 100kb for every command subst. With about
Denys Vlasenko7bc3d392016-09-17 20:53:47 +020011878 * a hundred command substitutions stack overflows.
11879 * With larger prepended string, SEGV happens sooner.
11880 */
Ron Yorston072fc602015-07-01 16:46:18 +010011881 str = alloca(savelen);
Eric Andersenc470f442003-07-28 09:56:35 +000011882 memcpy(str, stackblock(), savelen);
11883 }
Denys Vlasenko7bc3d392016-09-17 20:53:47 +020011884
Eric Andersenc470f442003-07-28 09:56:35 +000011885 if (oldstyle) {
11886 /* We must read until the closing backquote, giving special
Denys Vlasenko60cb48c2013-01-14 15:57:44 +010011887 * treatment to some slashes, and then push the string and
11888 * reread it as input, interpreting it normally.
11889 */
Eric Andersenc470f442003-07-28 09:56:35 +000011890 char *pout;
Eric Andersenc470f442003-07-28 09:56:35 +000011891 size_t psavelen;
11892 char *pstr;
11893
Eric Andersenc470f442003-07-28 09:56:35 +000011894 STARTSTACKSTR(pout);
11895 for (;;) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020011896 int pc;
11897
11898 setprompt_if(needprompt, 2);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011899 pc = pgetc();
11900 switch (pc) {
Eric Andersenc470f442003-07-28 09:56:35 +000011901 case '`':
11902 goto done;
11903
11904 case '\\':
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011905 pc = pgetc();
11906 if (pc == '\n') {
Denys Vlasenkoce332a22016-10-02 23:47:34 +020011907 nlprompt();
Eric Andersenc470f442003-07-28 09:56:35 +000011908 /*
11909 * If eating a newline, avoid putting
11910 * the newline into the new character
11911 * stream (via the STPUTC after the
11912 * switch).
11913 */
11914 continue;
11915 }
11916 if (pc != '\\' && pc != '`' && pc != '$'
Denys Vlasenko76bc2d62009-11-29 01:37:46 +010011917 && (!dblquote || pc != '"')
11918 ) {
Eric Andersenc470f442003-07-28 09:56:35 +000011919 STPUTC('\\', pout);
Denys Vlasenko76bc2d62009-11-29 01:37:46 +010011920 }
Denys Vlasenkocd716832009-11-28 22:14:02 +010011921 if (pc <= 255 /* not PEOA or PEOF */) {
Eric Andersenc470f442003-07-28 09:56:35 +000011922 break;
11923 }
11924 /* fall through */
11925
11926 case PEOF:
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010011927 IF_ASH_ALIAS(case PEOA:)
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011928 startlinno = g_parsefile->linno;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011929 raise_error_syntax("EOF in backquote substitution");
Eric Andersenc470f442003-07-28 09:56:35 +000011930
11931 case '\n':
Denys Vlasenkoce332a22016-10-02 23:47:34 +020011932 nlnoprompt();
Eric Andersenc470f442003-07-28 09:56:35 +000011933 break;
11934
11935 default:
11936 break;
11937 }
11938 STPUTC(pc, pout);
11939 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011940 done:
Eric Andersenc470f442003-07-28 09:56:35 +000011941 STPUTC('\0', pout);
11942 psavelen = pout - (char *)stackblock();
11943 if (psavelen > 0) {
11944 pstr = grabstackstr(pout);
11945 setinputstring(pstr);
11946 }
11947 }
11948 nlpp = &bqlist;
11949 while (*nlpp)
11950 nlpp = &(*nlpp)->next;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011951 *nlpp = stzalloc(sizeof(**nlpp));
11952 /* (*nlpp)->next = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011953
11954 if (oldstyle) {
11955 saveprompt = doprompt;
11956 doprompt = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000011957 }
11958
Eric Andersenc470f442003-07-28 09:56:35 +000011959 n = list(2);
11960
11961 if (oldstyle)
11962 doprompt = saveprompt;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011963 else if (readtoken() != TRP)
11964 raise_error_unexpected_syntax(TRP);
Eric Andersenc470f442003-07-28 09:56:35 +000011965
11966 (*nlpp)->n = n;
11967 if (oldstyle) {
11968 /*
11969 * Start reading from old file again, ignoring any pushed back
11970 * tokens left from the backquote parsing
11971 */
11972 popfile();
11973 tokpushback = 0;
11974 }
11975 while (stackblocksize() <= savelen)
11976 growstackblock();
11977 STARTSTACKSTR(out);
11978 if (str) {
11979 memcpy(out, str, savelen);
11980 STADJUST(savelen, out);
Eric Andersenc470f442003-07-28 09:56:35 +000011981 }
Ron Yorston549deab2015-05-18 09:57:51 +020011982 USTPUTC(CTLBACKQ, out);
Eric Andersenc470f442003-07-28 09:56:35 +000011983 if (oldstyle)
11984 goto parsebackq_oldreturn;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011985 goto parsebackq_newreturn;
Eric Andersenc470f442003-07-28 09:56:35 +000011986}
11987
Mike Frysinger98c52642009-04-02 10:02:37 +000011988#if ENABLE_SH_MATH_SUPPORT
Eric Andersencb57d552001-06-28 07:25:16 +000011989/*
11990 * Parse an arithmetic expansion (indicate start of one and set state)
11991 */
Eric Andersenc470f442003-07-28 09:56:35 +000011992parsearith: {
Eric Andersenc470f442003-07-28 09:56:35 +000011993 if (++arinest == 1) {
11994 prevsyntax = syntax;
11995 syntax = ARISYNTAX;
Eric Andersencb57d552001-06-28 07:25:16 +000011996 }
Ron Yorstonad88bde2015-05-18 09:56:16 +020011997 USTPUTC(CTLARI, out);
Eric Andersenc470f442003-07-28 09:56:35 +000011998 goto parsearith_return;
11999}
12000#endif
Eric Andersenc470f442003-07-28 09:56:35 +000012001} /* end of readtoken */
12002
Eric Andersencb57d552001-06-28 07:25:16 +000012003/*
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012004 * Read the next input token.
12005 * If the token is a word, we set backquotelist to the list of cmds in
12006 * backquotes. We set quoteflag to true if any part of the word was
12007 * quoted.
12008 * If the token is TREDIR, then we set redirnode to a structure containing
12009 * the redirection.
12010 * In all cases, the variable startlinno is set to the number of the line
12011 * on which the token starts.
12012 *
12013 * [Change comment: here documents and internal procedures]
12014 * [Readtoken shouldn't have any arguments. Perhaps we should make the
12015 * word parsing code into a separate routine. In this case, readtoken
12016 * doesn't need to have any internal procedures, but parseword does.
12017 * We could also make parseoperator in essence the main routine, and
12018 * have parseword (readtoken1?) handle both words and redirection.]
Eric Andersencb57d552001-06-28 07:25:16 +000012019 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012020#define NEW_xxreadtoken
12021#ifdef NEW_xxreadtoken
12022/* singles must be first! */
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000012023static const char xxreadtoken_chars[7] ALIGN1 = {
Denis Vlasenko834dee72008-10-07 09:18:30 +000012024 '\n', '(', ')', /* singles */
12025 '&', '|', ';', /* doubles */
12026 0
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000012027};
Eric Andersencb57d552001-06-28 07:25:16 +000012028
Denis Vlasenko834dee72008-10-07 09:18:30 +000012029#define xxreadtoken_singles 3
12030#define xxreadtoken_doubles 3
12031
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000012032static const char xxreadtoken_tokens[] ALIGN1 = {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012033 TNL, TLP, TRP, /* only single occurrence allowed */
12034 TBACKGND, TPIPE, TSEMI, /* if single occurrence */
12035 TEOF, /* corresponds to trailing nul */
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000012036 TAND, TOR, TENDCASE /* if double occurrence */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012037};
12038
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012039static int
12040xxreadtoken(void)
12041{
12042 int c;
12043
12044 if (tokpushback) {
12045 tokpushback = 0;
12046 return lasttoken;
Eric Andersencb57d552001-06-28 07:25:16 +000012047 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020012048 setprompt_if(needprompt, 2);
Denis Vlasenko41eb3002008-11-28 03:42:31 +000012049 startlinno = g_parsefile->linno;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012050 for (;;) { /* until token or start of word found */
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020012051 c = pgetc();
Denis Vlasenko5e34ff22009-04-21 11:09:40 +000012052 if (c == ' ' || c == '\t' IF_ASH_ALIAS( || c == PEOA))
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012053 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012054
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012055 if (c == '#') {
12056 while ((c = pgetc()) != '\n' && c != PEOF)
12057 continue;
12058 pungetc();
12059 } else if (c == '\\') {
12060 if (pgetc() != '\n') {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012061 pungetc();
Denis Vlasenko834dee72008-10-07 09:18:30 +000012062 break; /* return readtoken1(...) */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012063 }
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012064 nlprompt();
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012065 } else {
12066 const char *p;
12067
12068 p = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
12069 if (c != PEOF) {
12070 if (c == '\n') {
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012071 nlnoprompt();
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012072 }
12073
12074 p = strchr(xxreadtoken_chars, c);
Denis Vlasenko834dee72008-10-07 09:18:30 +000012075 if (p == NULL)
12076 break; /* return readtoken1(...) */
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012077
Denis Vlasenko834dee72008-10-07 09:18:30 +000012078 if ((int)(p - xxreadtoken_chars) >= xxreadtoken_singles) {
12079 int cc = pgetc();
12080 if (cc == c) { /* double occurrence? */
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012081 p += xxreadtoken_doubles + 1;
12082 } else {
12083 pungetc();
Denis Vlasenko834dee72008-10-07 09:18:30 +000012084#if ENABLE_ASH_BASH_COMPAT
12085 if (c == '&' && cc == '>') /* &> */
12086 break; /* return readtoken1(...) */
12087#endif
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012088 }
12089 }
12090 }
12091 lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
12092 return lasttoken;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012093 }
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012094 } /* for (;;) */
Denis Vlasenko834dee72008-10-07 09:18:30 +000012095
12096 return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012097}
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012098#else /* old xxreadtoken */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012099#define RETURN(token) return lasttoken = token
12100static int
12101xxreadtoken(void)
12102{
12103 int c;
12104
12105 if (tokpushback) {
12106 tokpushback = 0;
12107 return lasttoken;
12108 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020012109 setprompt_if(needprompt, 2);
Denis Vlasenko41eb3002008-11-28 03:42:31 +000012110 startlinno = g_parsefile->linno;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012111 for (;;) { /* until token or start of word found */
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020012112 c = pgetc();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012113 switch (c) {
12114 case ' ': case '\t':
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010012115 IF_ASH_ALIAS(case PEOA:)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012116 continue;
12117 case '#':
Denis Vlasenkof7d56652008-03-25 05:51:41 +000012118 while ((c = pgetc()) != '\n' && c != PEOF)
12119 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012120 pungetc();
12121 continue;
12122 case '\\':
12123 if (pgetc() == '\n') {
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012124 nlprompt();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012125 continue;
12126 }
12127 pungetc();
12128 goto breakloop;
12129 case '\n':
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012130 nlnoprompt();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012131 RETURN(TNL);
12132 case PEOF:
12133 RETURN(TEOF);
12134 case '&':
12135 if (pgetc() == '&')
12136 RETURN(TAND);
12137 pungetc();
12138 RETURN(TBACKGND);
12139 case '|':
12140 if (pgetc() == '|')
12141 RETURN(TOR);
12142 pungetc();
12143 RETURN(TPIPE);
12144 case ';':
12145 if (pgetc() == ';')
12146 RETURN(TENDCASE);
12147 pungetc();
12148 RETURN(TSEMI);
12149 case '(':
12150 RETURN(TLP);
12151 case ')':
12152 RETURN(TRP);
12153 default:
12154 goto breakloop;
12155 }
12156 }
12157 breakloop:
12158 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
12159#undef RETURN
12160}
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012161#endif /* old xxreadtoken */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012162
12163static int
12164readtoken(void)
12165{
12166 int t;
Ron Yorston713f07d2015-10-29 16:44:56 +000012167 int kwd = checkkwd;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012168#if DEBUG
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000012169 smallint alreadyseen = tokpushback;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012170#endif
12171
12172#if ENABLE_ASH_ALIAS
12173 top:
12174#endif
12175
12176 t = xxreadtoken();
12177
12178 /*
12179 * eat newlines
12180 */
Ron Yorston713f07d2015-10-29 16:44:56 +000012181 if (kwd & CHKNL) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012182 while (t == TNL) {
12183 parseheredoc();
12184 t = xxreadtoken();
12185 }
12186 }
12187
12188 if (t != TWORD || quoteflag) {
12189 goto out;
12190 }
12191
12192 /*
12193 * check for keywords
12194 */
Ron Yorston713f07d2015-10-29 16:44:56 +000012195 if (kwd & CHKKWD) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012196 const char *const *pp;
12197
12198 pp = findkwd(wordtext);
12199 if (pp) {
12200 lasttoken = t = pp - tokname_array;
Denys Vlasenko888527c2016-10-02 16:54:17 +020012201 TRACE(("keyword '%s' recognized\n", tokname_array[t]));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012202 goto out;
12203 }
12204 }
12205
12206 if (checkkwd & CHKALIAS) {
12207#if ENABLE_ASH_ALIAS
12208 struct alias *ap;
12209 ap = lookupalias(wordtext, 1);
12210 if (ap != NULL) {
12211 if (*ap->val) {
12212 pushstring(ap->val, ap);
12213 }
12214 goto top;
12215 }
12216#endif
12217 }
12218 out:
12219 checkkwd = 0;
12220#if DEBUG
12221 if (!alreadyseen)
Denys Vlasenko888527c2016-10-02 16:54:17 +020012222 TRACE(("token '%s' %s\n", tokname_array[t], t == TWORD ? wordtext : ""));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012223 else
Denys Vlasenko888527c2016-10-02 16:54:17 +020012224 TRACE(("reread token '%s' %s\n", tokname_array[t], t == TWORD ? wordtext : ""));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012225#endif
12226 return t;
Eric Andersencb57d552001-06-28 07:25:16 +000012227}
12228
Ron Yorstonc0e00762015-10-29 11:30:55 +000012229static int
Ron Yorston6bd2fab2015-10-29 11:30:22 +000012230peektoken(void)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012231{
12232 int t;
12233
12234 t = readtoken();
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000012235 tokpushback = 1;
Ron Yorstonc0e00762015-10-29 11:30:55 +000012236 return t;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012237}
Eric Andersencb57d552001-06-28 07:25:16 +000012238
12239/*
Denys Vlasenko86e83ec2009-07-23 22:07:07 +020012240 * Read and parse a command. Returns NODE_EOF on end of file.
12241 * (NULL is a valid parse tree indicating a blank line.)
Eric Andersencb57d552001-06-28 07:25:16 +000012242 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012243static union node *
12244parsecmd(int interact)
Eric Andersen90898442003-08-06 11:20:52 +000012245{
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012246 tokpushback = 0;
Ron Yorstonc0e00762015-10-29 11:30:55 +000012247 checkkwd = 0;
12248 heredoclist = 0;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012249 doprompt = interact;
Denys Vlasenko958581a2010-09-12 15:04:27 +020012250 setprompt_if(doprompt, doprompt);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012251 needprompt = 0;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012252 return list(1);
12253}
12254
12255/*
12256 * Input any here documents.
12257 */
12258static void
12259parseheredoc(void)
12260{
12261 struct heredoc *here;
12262 union node *n;
12263
12264 here = heredoclist;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000012265 heredoclist = NULL;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012266
12267 while (here) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020012268 setprompt_if(needprompt, 2);
12269 readtoken1(pgetc(), here->here->type == NHERE ? SQSYNTAX : DQSYNTAX,
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012270 here->eofmark, here->striptabs);
Denis Vlasenko597906c2008-02-20 16:38:54 +000012271 n = stzalloc(sizeof(struct narg));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012272 n->narg.type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000012273 /*n->narg.next = NULL; - stzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012274 n->narg.text = wordtext;
12275 n->narg.backquote = backquotelist;
12276 here->here->nhere.doc = n;
12277 here = here->next;
Eric Andersencb57d552001-06-28 07:25:16 +000012278 }
Eric Andersencb57d552001-06-28 07:25:16 +000012279}
12280
12281
12282/*
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000012283 * called by editline -- any expansions to the prompt should be added here.
Eric Andersencb57d552001-06-28 07:25:16 +000012284 */
Denis Vlasenko131ae172007-02-18 13:00:19 +000012285#if ENABLE_ASH_EXPAND_PRMT
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012286static const char *
12287expandstr(const char *ps)
12288{
12289 union node n;
Denys Vlasenko2a6d29a2016-10-25 21:17:52 +020012290 int saveprompt;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012291
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000012292 /* XXX Fix (char *) cast. It _is_ a bug. ps is variable's value,
12293 * and token processing _can_ alter it (delete NULs etc). */
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012294 setinputstring((char *)ps);
Denys Vlasenko2a6d29a2016-10-25 21:17:52 +020012295
12296 saveprompt = doprompt;
12297 doprompt = 0;
Denis Vlasenko46a53062007-09-24 18:30:02 +000012298 readtoken1(pgetc(), PSSYNTAX, nullstr, 0);
Denys Vlasenko2a6d29a2016-10-25 21:17:52 +020012299 doprompt = saveprompt;
12300
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012301 popfile();
12302
12303 n.narg.type = NARG;
12304 n.narg.next = NULL;
12305 n.narg.text = wordtext;
12306 n.narg.backquote = backquotelist;
12307
Ron Yorston549deab2015-05-18 09:57:51 +020012308 expandarg(&n, NULL, EXP_QUOTED);
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012309 return stackblock();
12310}
12311#endif
12312
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012313/*
12314 * Execute a command or commands contained in a string.
12315 */
12316static int
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020012317evalstring(char *s, int flags)
Eric Andersenc470f442003-07-28 09:56:35 +000012318{
Denys Vlasenko493b9ca2016-10-30 18:27:14 +010012319 struct jmploc *volatile savehandler;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012320 struct jmploc jmploc;
12321 int ex;
12322
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012323 union node *n;
12324 struct stackmark smark;
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012325 int status;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012326
Denys Vlasenko8e2bc472016-09-28 23:02:57 +020012327 s = sstrdup(s);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012328 setinputstring(s);
12329 setstackmark(&smark);
12330
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012331 status = 0;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012332 /* On exception inside execution loop, we must popfile().
12333 * Try interactively:
12334 * readonly a=a
12335 * command eval "a=b" # throws "is read only" error
12336 * "command BLTIN" is not supposed to abort (even in non-interactive use).
12337 * But if we skip popfile(), we hit EOF in eval's string, and exit.
12338 */
12339 savehandler = exception_handler;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012340 ex = setjmp(jmploc.loc);
12341 if (ex)
12342 goto out;
Denys Vlasenko493b9ca2016-10-30 18:27:14 +010012343 exception_handler = &jmploc;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012344
Denys Vlasenko86e83ec2009-07-23 22:07:07 +020012345 while ((n = parsecmd(0)) != NODE_EOF) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020012346 int i;
12347
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020012348 i = evaltree(n, flags);
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012349 if (n)
12350 status = i;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012351 popstackmark(&smark);
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012352 if (evalskip)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012353 break;
12354 }
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012355 out:
Denys Vlasenko8e2bc472016-09-28 23:02:57 +020012356 popstackmark(&smark);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012357 popfile();
Denys Vlasenko8e2bc472016-09-28 23:02:57 +020012358 stunalloc(s);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012359
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020012360 exception_handler = savehandler;
12361 if (ex)
12362 longjmp(exception_handler->loc, ex);
12363
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012364 return status;
Eric Andersenc470f442003-07-28 09:56:35 +000012365}
12366
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012367/*
12368 * The eval command.
12369 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012370static int FAST_FUNC
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020012371evalcmd(int argc UNUSED_PARAM, char **argv, int flags)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012372{
12373 char *p;
12374 char *concat;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012375
Denis Vlasenko68404f12008-03-17 09:00:54 +000012376 if (argv[1]) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012377 p = argv[1];
Denis Vlasenko68404f12008-03-17 09:00:54 +000012378 argv += 2;
12379 if (argv[0]) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012380 STARTSTACKSTR(concat);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012381 for (;;) {
12382 concat = stack_putstr(p, concat);
Denis Vlasenko68404f12008-03-17 09:00:54 +000012383 p = *argv++;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012384 if (p == NULL)
12385 break;
12386 STPUTC(' ', concat);
12387 }
12388 STPUTC('\0', concat);
12389 p = grabstackstr(concat);
12390 }
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020012391 return evalstring(p, flags & EV_TESTED);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012392 }
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012393 return 0;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012394}
12395
12396/*
Denys Vlasenko285ad152009-12-04 23:02:27 +010012397 * Read and execute commands.
12398 * "Top" is nonzero for the top level command loop;
12399 * it turns on prompting if the shell is interactive.
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012400 */
12401static int
12402cmdloop(int top)
12403{
12404 union node *n;
12405 struct stackmark smark;
12406 int inter;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020012407 int status = 0;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012408 int numeof = 0;
12409
12410 TRACE(("cmdloop(%d) called\n", top));
12411 for (;;) {
12412 int skip;
12413
12414 setstackmark(&smark);
12415#if JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +000012416 if (doing_jobctl)
Denys Vlasenko9c541002015-10-07 15:44:36 +020012417 showjobs(SHOW_CHANGED|SHOW_STDERR);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012418#endif
12419 inter = 0;
12420 if (iflag && top) {
12421 inter++;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012422 chkmail();
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012423 }
12424 n = parsecmd(inter);
Denys Vlasenko7cee00e2009-07-24 01:08:03 +020012425#if DEBUG
12426 if (DEBUG > 2 && debug && (n != NODE_EOF))
Denys Vlasenko883cea42009-07-11 15:31:59 +020012427 showtree(n);
Denis Vlasenko135cecb2009-04-12 00:00:57 +000012428#endif
Denys Vlasenko86e83ec2009-07-23 22:07:07 +020012429 if (n == NODE_EOF) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012430 if (!top || numeof >= 50)
12431 break;
12432 if (!stoppedjobs()) {
12433 if (!Iflag)
12434 break;
12435 out2str("\nUse \"exit\" to leave shell.\n");
12436 }
12437 numeof++;
12438 } else if (nflag == 0) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020012439 int i;
12440
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +000012441 /* job_warning can only be 2,1,0. Here 2->1, 1/0->0 */
12442 job_warning >>= 1;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012443 numeof = 0;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020012444 i = evaltree(n, 0);
12445 if (n)
12446 status = i;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012447 }
12448 popstackmark(&smark);
12449 skip = evalskip;
12450
12451 if (skip) {
Denys Vlasenko6a0710e2016-09-30 14:18:34 +020012452 evalskip &= ~SKIPFUNC;
Denys Vlasenko0840c912016-10-01 15:27:44 +020012453 break;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012454 }
12455 }
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020012456 return status;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012457}
12458
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000012459/*
12460 * Take commands from a file. To be compatible we should do a path
12461 * search for the file, which is necessary to find sub-commands.
12462 */
12463static char *
12464find_dot_file(char *name)
12465{
12466 char *fullname;
12467 const char *path = pathval();
12468 struct stat statb;
12469
12470 /* don't try this for absolute or relative paths */
12471 if (strchr(name, '/'))
12472 return name;
12473
Denis Vlasenko8ad78e12009-02-15 12:40:30 +000012474 /* IIRC standards do not say whether . is to be searched.
12475 * And it is even smaller this way, making it unconditional for now:
12476 */
12477 if (1) { /* ENABLE_ASH_BASH_COMPAT */
12478 fullname = name;
12479 goto try_cur_dir;
12480 }
12481
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020012482 while ((fullname = path_advance(&path, name)) != NULL) {
Denis Vlasenko8ad78e12009-02-15 12:40:30 +000012483 try_cur_dir:
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000012484 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
12485 /*
12486 * Don't bother freeing here, since it will
12487 * be freed by the caller.
12488 */
12489 return fullname;
12490 }
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020012491 if (fullname != name)
12492 stunalloc(fullname);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000012493 }
12494
12495 /* not found in the PATH */
12496 ash_msg_and_raise_error("%s: not found", name);
12497 /* NOTREACHED */
12498}
12499
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012500static int FAST_FUNC
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012501dotcmd(int argc_ UNUSED_PARAM, char **argv_ UNUSED_PARAM)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012502{
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012503 /* "false; . empty_file; echo $?" should print 0, not 1: */
12504 int status = 0;
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012505 char *fullname;
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012506 char **argv;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012507 struct strlist *sp;
12508 volatile struct shparam saveparam;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012509
12510 for (sp = cmdenviron; sp; sp = sp->next)
Denis Vlasenko4222ae42007-02-25 02:37:49 +000012511 setvareq(ckstrdup(sp->text), VSTRFIXED | VTEXTFIXED);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012512
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012513 nextopt(nullstr); /* handle possible "--" */
12514 argv = argptr;
12515
12516 if (!argv[0]) {
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012517 /* bash says: "bash: .: filename argument required" */
12518 return 2; /* bash compat */
12519 }
12520
Denys Vlasenko091f8312013-03-17 14:25:22 +010012521 /* This aborts if file isn't found, which is POSIXly correct.
12522 * bash returns exitcode 1 instead.
12523 */
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012524 fullname = find_dot_file(argv[0]);
12525 argv++;
12526 if (argv[0]) { /* . FILE ARGS, ARGS exist */
12527 int argc;
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012528 saveparam = shellparam;
12529 shellparam.malloced = 0;
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012530 argc = 1;
12531 while (argv[argc])
12532 argc++;
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012533 shellparam.nparam = argc;
12534 shellparam.p = argv;
12535 };
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012536
Denys Vlasenko091f8312013-03-17 14:25:22 +010012537 /* This aborts if file can't be opened, which is POSIXly correct.
12538 * bash returns exitcode 1 instead.
12539 */
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012540 setinputfile(fullname, INPUT_PUSH_FILE);
12541 commandname = fullname;
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012542 status = cmdloop(0);
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012543 popfile();
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012544
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012545 if (argv[0]) {
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012546 freeparam(&shellparam);
12547 shellparam = saveparam;
12548 };
12549
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012550 return status;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012551}
12552
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012553static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012554exitcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012555{
12556 if (stoppedjobs())
12557 return 0;
Denis Vlasenko68404f12008-03-17 09:00:54 +000012558 if (argv[1])
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012559 exitstatus = number(argv[1]);
12560 raise_exception(EXEXIT);
12561 /* NOTREACHED */
12562}
12563
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012564/*
12565 * Read a file containing shell functions.
12566 */
12567static void
12568readcmdfile(char *name)
12569{
12570 setinputfile(name, INPUT_PUSH_FILE);
12571 cmdloop(0);
12572 popfile();
12573}
12574
12575
Denis Vlasenkocc571512007-02-23 21:10:35 +000012576/* ============ find_command inplementation */
12577
12578/*
12579 * Resolve a command name. If you change this routine, you may have to
12580 * change the shellexec routine as well.
12581 */
12582static void
12583find_command(char *name, struct cmdentry *entry, int act, const char *path)
12584{
12585 struct tblentry *cmdp;
12586 int idx;
12587 int prev;
12588 char *fullname;
12589 struct stat statb;
12590 int e;
12591 int updatetbl;
12592 struct builtincmd *bcmd;
12593
12594 /* If name contains a slash, don't use PATH or hash table */
12595 if (strchr(name, '/') != NULL) {
12596 entry->u.index = -1;
12597 if (act & DO_ABS) {
12598 while (stat(name, &statb) < 0) {
12599#ifdef SYSV
12600 if (errno == EINTR)
12601 continue;
12602#endif
12603 entry->cmdtype = CMDUNKNOWN;
12604 return;
12605 }
12606 }
12607 entry->cmdtype = CMDNORMAL;
12608 return;
12609 }
12610
Denis Vlasenkof20de5b2007-04-29 23:42:54 +000012611/* #if ENABLE_FEATURE_SH_STANDALONE... moved after builtin check */
Denis Vlasenkocc571512007-02-23 21:10:35 +000012612
12613 updatetbl = (path == pathval());
12614 if (!updatetbl) {
12615 act |= DO_ALTPATH;
12616 if (strstr(path, "%builtin") != NULL)
12617 act |= DO_ALTBLTIN;
12618 }
12619
12620 /* If name is in the table, check answer will be ok */
12621 cmdp = cmdlookup(name, 0);
12622 if (cmdp != NULL) {
12623 int bit;
12624
12625 switch (cmdp->cmdtype) {
12626 default:
12627#if DEBUG
12628 abort();
12629#endif
12630 case CMDNORMAL:
12631 bit = DO_ALTPATH;
12632 break;
12633 case CMDFUNCTION:
12634 bit = DO_NOFUNC;
12635 break;
12636 case CMDBUILTIN:
12637 bit = DO_ALTBLTIN;
12638 break;
12639 }
12640 if (act & bit) {
12641 updatetbl = 0;
12642 cmdp = NULL;
12643 } else if (cmdp->rehash == 0)
12644 /* if not invalidated by cd, we're done */
12645 goto success;
12646 }
12647
12648 /* If %builtin not in path, check for builtin next */
12649 bcmd = find_builtin(name);
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000012650 if (bcmd) {
12651 if (IS_BUILTIN_REGULAR(bcmd))
12652 goto builtin_success;
12653 if (act & DO_ALTPATH) {
12654 if (!(act & DO_ALTBLTIN))
12655 goto builtin_success;
12656 } else if (builtinloc <= 0) {
12657 goto builtin_success;
Denis Vlasenko8e858e22007-03-07 09:35:43 +000012658 }
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000012659 }
Denis Vlasenkocc571512007-02-23 21:10:35 +000012660
Denis Vlasenkof20de5b2007-04-29 23:42:54 +000012661#if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko7465dbc2008-04-13 02:25:53 +000012662 {
12663 int applet_no = find_applet_by_name(name);
12664 if (applet_no >= 0) {
12665 entry->cmdtype = CMDNORMAL;
12666 entry->u.index = -2 - applet_no;
12667 return;
12668 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +000012669 }
12670#endif
12671
Denis Vlasenkocc571512007-02-23 21:10:35 +000012672 /* We have to search path. */
12673 prev = -1; /* where to start */
12674 if (cmdp && cmdp->rehash) { /* doing a rehash */
12675 if (cmdp->cmdtype == CMDBUILTIN)
12676 prev = builtinloc;
12677 else
12678 prev = cmdp->param.index;
12679 }
12680
12681 e = ENOENT;
12682 idx = -1;
12683 loop:
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020012684 while ((fullname = path_advance(&path, name)) != NULL) {
Denis Vlasenkocc571512007-02-23 21:10:35 +000012685 stunalloc(fullname);
Denis Vlasenkodee82b62007-07-29 14:05:27 +000012686 /* NB: code below will still use fullname
12687 * despite it being "unallocated" */
Denis Vlasenkocc571512007-02-23 21:10:35 +000012688 idx++;
12689 if (pathopt) {
12690 if (prefix(pathopt, "builtin")) {
12691 if (bcmd)
12692 goto builtin_success;
12693 continue;
Denis Vlasenko4a9ca132008-04-12 20:07:08 +000012694 }
12695 if ((act & DO_NOFUNC)
12696 || !prefix(pathopt, "func")
Denys Vlasenkoe4dcba12010-10-28 18:57:19 +020012697 ) { /* ignore unimplemented options */
Denis Vlasenkocc571512007-02-23 21:10:35 +000012698 continue;
12699 }
12700 }
12701 /* if rehash, don't redo absolute path names */
12702 if (fullname[0] == '/' && idx <= prev) {
12703 if (idx < prev)
12704 continue;
12705 TRACE(("searchexec \"%s\": no change\n", name));
12706 goto success;
12707 }
12708 while (stat(fullname, &statb) < 0) {
12709#ifdef SYSV
12710 if (errno == EINTR)
12711 continue;
12712#endif
12713 if (errno != ENOENT && errno != ENOTDIR)
12714 e = errno;
12715 goto loop;
12716 }
12717 e = EACCES; /* if we fail, this will be the error */
12718 if (!S_ISREG(statb.st_mode))
12719 continue;
12720 if (pathopt) { /* this is a %func directory */
12721 stalloc(strlen(fullname) + 1);
Denis Vlasenkodee82b62007-07-29 14:05:27 +000012722 /* NB: stalloc will return space pointed by fullname
12723 * (because we don't have any intervening allocations
12724 * between stunalloc above and this stalloc) */
Denis Vlasenkocc571512007-02-23 21:10:35 +000012725 readcmdfile(fullname);
12726 cmdp = cmdlookup(name, 0);
12727 if (cmdp == NULL || cmdp->cmdtype != CMDFUNCTION)
12728 ash_msg_and_raise_error("%s not defined in %s", name, fullname);
12729 stunalloc(fullname);
12730 goto success;
12731 }
12732 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
12733 if (!updatetbl) {
12734 entry->cmdtype = CMDNORMAL;
12735 entry->u.index = idx;
12736 return;
12737 }
12738 INT_OFF;
12739 cmdp = cmdlookup(name, 1);
12740 cmdp->cmdtype = CMDNORMAL;
12741 cmdp->param.index = idx;
12742 INT_ON;
12743 goto success;
12744 }
12745
12746 /* We failed. If there was an entry for this command, delete it */
12747 if (cmdp && updatetbl)
12748 delete_cmd_entry();
12749 if (act & DO_ERR)
12750 ash_msg("%s: %s", name, errmsg(e, "not found"));
12751 entry->cmdtype = CMDUNKNOWN;
12752 return;
12753
12754 builtin_success:
12755 if (!updatetbl) {
12756 entry->cmdtype = CMDBUILTIN;
12757 entry->u.cmd = bcmd;
12758 return;
12759 }
12760 INT_OFF;
12761 cmdp = cmdlookup(name, 1);
12762 cmdp->cmdtype = CMDBUILTIN;
12763 cmdp->param.cmd = bcmd;
12764 INT_ON;
12765 success:
12766 cmdp->rehash = 0;
12767 entry->cmdtype = cmdp->cmdtype;
12768 entry->u = cmdp->param;
12769}
12770
12771
Eric Andersencb57d552001-06-28 07:25:16 +000012772/*
Eric Andersencb57d552001-06-28 07:25:16 +000012773 * The trap builtin.
12774 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012775static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012776trapcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +000012777{
12778 char *action;
12779 char **ap;
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010012780 int signo, exitcode;
Eric Andersencb57d552001-06-28 07:25:16 +000012781
Eric Andersenc470f442003-07-28 09:56:35 +000012782 nextopt(nullstr);
12783 ap = argptr;
12784 if (!*ap) {
Denis Vlasenko2da584f2007-02-19 22:44:05 +000012785 for (signo = 0; signo < NSIG; signo++) {
Denys Vlasenko21d87d42009-09-25 00:06:51 +020012786 char *tr = trap_ptr[signo];
12787 if (tr) {
Denys Vlasenkoe74aaf92009-09-27 02:05:45 +020012788 /* note: bash adds "SIG", but only if invoked
12789 * as "bash". If called as "sh", or if set -o posix,
12790 * then it prints short signal names.
12791 * We are printing short names: */
12792 out1fmt("trap -- %s %s\n",
Denys Vlasenko21d87d42009-09-25 00:06:51 +020012793 single_quote(tr),
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +000012794 get_signame(signo));
Denys Vlasenko726e1a02009-09-25 02:58:20 +020012795 /* trap_ptr != trap only if we are in special-cased `trap` code.
12796 * In this case, we will exit very soon, no need to free(). */
Denys Vlasenkoe74aaf92009-09-27 02:05:45 +020012797 /* if (trap_ptr != trap && tp[0]) */
Denys Vlasenko726e1a02009-09-25 02:58:20 +020012798 /* free(tr); */
Eric Andersencb57d552001-06-28 07:25:16 +000012799 }
12800 }
Denys Vlasenko726e1a02009-09-25 02:58:20 +020012801 /*
Denys Vlasenko21d87d42009-09-25 00:06:51 +020012802 if (trap_ptr != trap) {
12803 free(trap_ptr);
12804 trap_ptr = trap;
12805 }
Denys Vlasenko726e1a02009-09-25 02:58:20 +020012806 */
Eric Andersencb57d552001-06-28 07:25:16 +000012807 return 0;
12808 }
Denys Vlasenko21d87d42009-09-25 00:06:51 +020012809
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +000012810 action = NULL;
12811 if (ap[1])
Eric Andersencb57d552001-06-28 07:25:16 +000012812 action = *ap++;
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010012813 exitcode = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000012814 while (*ap) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000012815 signo = get_signum(*ap);
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010012816 if (signo < 0) {
12817 /* Mimic bash message exactly */
12818 ash_msg("%s: invalid signal specification", *ap);
12819 exitcode = 1;
12820 goto next;
12821 }
Denis Vlasenkob012b102007-02-19 22:43:01 +000012822 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +000012823 if (action) {
Denis Vlasenko9f739442006-12-16 23:49:13 +000012824 if (LONE_DASH(action))
Eric Andersencb57d552001-06-28 07:25:16 +000012825 action = NULL;
Denys Vlasenkob4f51d32016-10-27 12:55:09 +020012826 else {
12827 if (action[0]) /* not NULL and not "" and not "-" */
12828 may_have_traps = 1;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012829 action = ckstrdup(action);
Denys Vlasenkob4f51d32016-10-27 12:55:09 +020012830 }
Eric Andersencb57d552001-06-28 07:25:16 +000012831 }
Denis Vlasenko60818682007-09-28 22:07:23 +000012832 free(trap[signo]);
Eric Andersencb57d552001-06-28 07:25:16 +000012833 trap[signo] = action;
12834 if (signo != 0)
12835 setsignal(signo);
Denis Vlasenkob012b102007-02-19 22:43:01 +000012836 INT_ON;
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010012837 next:
Eric Andersencb57d552001-06-28 07:25:16 +000012838 ap++;
12839 }
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010012840 return exitcode;
Eric Andersencb57d552001-06-28 07:25:16 +000012841}
12842
Eric Andersenc470f442003-07-28 09:56:35 +000012843
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000012844/* ============ Builtins */
Eric Andersenc470f442003-07-28 09:56:35 +000012845
Denys Vlasenko2ec34962014-09-08 16:52:39 +020012846#if ENABLE_ASH_HELP
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012847static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012848helpcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000012849{
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000012850 unsigned col;
12851 unsigned i;
Eric Andersenc470f442003-07-28 09:56:35 +000012852
Denys Vlasenkod6b05eb2009-06-06 20:59:55 +020012853 out1fmt(
Denis Vlasenko34d4d892009-04-04 20:24:37 +000012854 "Built-in commands:\n"
12855 "------------------\n");
Denis Vlasenkob71c6682007-07-21 15:08:09 +000012856 for (col = 0, i = 0; i < ARRAY_SIZE(builtintab); i++) {
Eric Andersenc470f442003-07-28 09:56:35 +000012857 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
Denis Vlasenko52764022007-02-24 13:42:56 +000012858 builtintab[i].name + 1);
Eric Andersenc470f442003-07-28 09:56:35 +000012859 if (col > 60) {
12860 out1fmt("\n");
12861 col = 0;
12862 }
12863 }
Denys Vlasenko2ec34962014-09-08 16:52:39 +020012864# if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko1aa7e472007-11-28 06:49:03 +000012865 {
12866 const char *a = applet_names;
12867 while (*a) {
12868 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), a);
12869 if (col > 60) {
12870 out1fmt("\n");
12871 col = 0;
12872 }
Ron Yorston2b919582016-04-08 11:57:20 +010012873 while (*a++ != '\0')
12874 continue;
Eric Andersenc470f442003-07-28 09:56:35 +000012875 }
12876 }
Denys Vlasenko2ec34962014-09-08 16:52:39 +020012877# endif
Denys Vlasenkoebedb942016-10-02 18:45:09 +020012878 newline_and_flush(stdout);
Eric Andersenc470f442003-07-28 09:56:35 +000012879 return EXIT_SUCCESS;
12880}
Denys Vlasenko2ec34962014-09-08 16:52:39 +020012881#endif
Eric Andersenc470f442003-07-28 09:56:35 +000012882
Flemming Madsend96ffda2013-04-07 18:47:24 +020012883#if MAX_HISTORY
12884static int FAST_FUNC
12885historycmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12886{
12887 show_history(line_input_state);
12888 return EXIT_SUCCESS;
12889}
12890#endif
12891
Eric Andersencb57d552001-06-28 07:25:16 +000012892/*
Eric Andersencb57d552001-06-28 07:25:16 +000012893 * The export and readonly commands.
12894 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012895static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012896exportcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000012897{
12898 struct var *vp;
12899 char *name;
12900 const char *p;
Eric Andersenc470f442003-07-28 09:56:35 +000012901 char **aptr;
Denys Vlasenkod5275882012-10-01 13:41:17 +020012902 char opt;
12903 int flag;
12904 int flag_off;
Eric Andersencb57d552001-06-28 07:25:16 +000012905
Denys Vlasenkod5275882012-10-01 13:41:17 +020012906 /* "readonly" in bash accepts, but ignores -n.
12907 * We do the same: it saves a conditional in nextopt's param.
12908 */
12909 flag_off = 0;
12910 while ((opt = nextopt("np")) != '\0') {
12911 if (opt == 'n')
12912 flag_off = VEXPORT;
12913 }
12914 flag = VEXPORT;
12915 if (argv[0][0] == 'r') {
12916 flag = VREADONLY;
12917 flag_off = 0; /* readonly ignores -n */
12918 }
12919 flag_off = ~flag_off;
12920
12921 /*if (opt_p_not_specified) - bash doesnt check this. Try "export -p NAME" */
12922 {
Denis Vlasenko2da584f2007-02-19 22:44:05 +000012923 aptr = argptr;
12924 name = *aptr;
12925 if (name) {
12926 do {
12927 p = strchr(name, '=');
12928 if (p != NULL) {
12929 p++;
12930 } else {
12931 vp = *findvar(hashvar(name), name);
12932 if (vp) {
Denys Vlasenkod5275882012-10-01 13:41:17 +020012933 vp->flags = ((vp->flags | flag) & flag_off);
Denis Vlasenko2da584f2007-02-19 22:44:05 +000012934 continue;
12935 }
Eric Andersencb57d552001-06-28 07:25:16 +000012936 }
Denys Vlasenkod5275882012-10-01 13:41:17 +020012937 setvar(name, p, (flag & flag_off));
Denis Vlasenko2da584f2007-02-19 22:44:05 +000012938 } while ((name = *++aptr) != NULL);
12939 return 0;
12940 }
Eric Andersencb57d552001-06-28 07:25:16 +000012941 }
Denys Vlasenkod5275882012-10-01 13:41:17 +020012942
12943 /* No arguments. Show the list of exported or readonly vars.
12944 * -n is ignored.
12945 */
Denis Vlasenko2da584f2007-02-19 22:44:05 +000012946 showvars(argv[0], flag, 0);
Eric Andersencb57d552001-06-28 07:25:16 +000012947 return 0;
12948}
12949
Eric Andersencb57d552001-06-28 07:25:16 +000012950/*
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000012951 * Delete a function if it exists.
Eric Andersencb57d552001-06-28 07:25:16 +000012952 */
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +000012953static void
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000012954unsetfunc(const char *name)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012955{
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000012956 struct tblentry *cmdp;
Eric Andersencb57d552001-06-28 07:25:16 +000012957
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000012958 cmdp = cmdlookup(name, 0);
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020012959 if (cmdp != NULL && cmdp->cmdtype == CMDFUNCTION)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000012960 delete_cmd_entry();
Eric Andersenc470f442003-07-28 09:56:35 +000012961}
12962
Eric Andersencb57d552001-06-28 07:25:16 +000012963/*
Eric Andersencb57d552001-06-28 07:25:16 +000012964 * The unset builtin command. We unset the function before we unset the
12965 * variable to allow a function to be unset when there is a readonly variable
12966 * with the same name.
12967 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012968static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012969unsetcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +000012970{
12971 char **ap;
12972 int i;
Eric Andersenc470f442003-07-28 09:56:35 +000012973 int flag = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000012974 int ret = 0;
12975
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020012976 while ((i = nextopt("vf")) != 0) {
Eric Andersenc470f442003-07-28 09:56:35 +000012977 flag = i;
Eric Andersencb57d552001-06-28 07:25:16 +000012978 }
Eric Andersencb57d552001-06-28 07:25:16 +000012979
Denis Vlasenko2da584f2007-02-19 22:44:05 +000012980 for (ap = argptr; *ap; ap++) {
Eric Andersenc470f442003-07-28 09:56:35 +000012981 if (flag != 'f') {
12982 i = unsetvar(*ap);
12983 ret |= i;
12984 if (!(i & 2))
12985 continue;
12986 }
12987 if (flag != 'v')
Eric Andersencb57d552001-06-28 07:25:16 +000012988 unsetfunc(*ap);
Eric Andersencb57d552001-06-28 07:25:16 +000012989 }
Eric Andersenc470f442003-07-28 09:56:35 +000012990 return ret & 1;
Eric Andersencb57d552001-06-28 07:25:16 +000012991}
12992
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000012993static const unsigned char timescmd_str[] ALIGN1 = {
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012994 ' ', offsetof(struct tms, tms_utime),
12995 '\n', offsetof(struct tms, tms_stime),
12996 ' ', offsetof(struct tms, tms_cutime),
12997 '\n', offsetof(struct tms, tms_cstime),
12998 0
12999};
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013000static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013001timescmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013002{
Denys Vlasenko8cd9f342010-06-18 15:36:48 +020013003 unsigned long clk_tck, s, t;
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013004 const unsigned char *p;
13005 struct tms buf;
13006
Bartosz Golaszewski5d2e4092014-06-22 14:01:13 +020013007 clk_tck = bb_clk_tck();
Eric Andersencb57d552001-06-28 07:25:16 +000013008 times(&buf);
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013009
13010 p = timescmd_str;
13011 do {
13012 t = *(clock_t *)(((char *) &buf) + p[1]);
13013 s = t / clk_tck;
Denys Vlasenko8cd9f342010-06-18 15:36:48 +020013014 t = t % clk_tck;
13015 out1fmt("%lum%lu.%03lus%c",
13016 s / 60, s % 60,
13017 (t * 1000) / clk_tck,
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013018 p[0]);
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020013019 p += 2;
13020 } while (*p);
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013021
Eric Andersencb57d552001-06-28 07:25:16 +000013022 return 0;
13023}
13024
Mike Frysinger98c52642009-04-02 10:02:37 +000013025#if ENABLE_SH_MATH_SUPPORT
Eric Andersenc470f442003-07-28 09:56:35 +000013026/*
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020013027 * The let builtin. Partially stolen from GNU Bash, the Bourne Again SHell.
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +000013028 * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
Eric Andersen90898442003-08-06 11:20:52 +000013029 *
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +000013030 * Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
Eric Andersenc470f442003-07-28 09:56:35 +000013031 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013032static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013033letcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersenc470f442003-07-28 09:56:35 +000013034{
Denis Vlasenko68404f12008-03-17 09:00:54 +000013035 arith_t i;
Eric Andersenc470f442003-07-28 09:56:35 +000013036
Denis Vlasenko68404f12008-03-17 09:00:54 +000013037 argv++;
13038 if (!*argv)
Denis Vlasenkob012b102007-02-19 22:43:01 +000013039 ash_msg_and_raise_error("expression expected");
Denis Vlasenko68404f12008-03-17 09:00:54 +000013040 do {
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +000013041 i = ash_arith(*argv);
Denis Vlasenko68404f12008-03-17 09:00:54 +000013042 } while (*++argv);
Eric Andersenc470f442003-07-28 09:56:35 +000013043
Denis Vlasenkod9e15f22006-11-27 16:49:55 +000013044 return !i;
Eric Andersenc470f442003-07-28 09:56:35 +000013045}
Eric Andersenc470f442003-07-28 09:56:35 +000013046#endif
Eric Andersen74bcd162001-07-30 21:41:37 +000013047
Eric Andersenc470f442003-07-28 09:56:35 +000013048/*
Denis Vlasenko59f351c2008-03-25 00:07:12 +000013049 * The read builtin. Options:
13050 * -r Do not interpret '\' specially
13051 * -s Turn off echo (tty only)
13052 * -n NCHARS Read NCHARS max
13053 * -p PROMPT Display PROMPT on stderr (if input is from tty)
13054 * -t SECONDS Timeout after SECONDS (tty or pipe only)
13055 * -u FD Read from given FD instead of fd 0
Eric Andersenc470f442003-07-28 09:56:35 +000013056 * This uses unbuffered input, which may be avoidable in some cases.
Denis Vlasenko59f351c2008-03-25 00:07:12 +000013057 * TODO: bash also has:
13058 * -a ARRAY Read into array[0],[1],etc
13059 * -d DELIM End on DELIM char, not newline
13060 * -e Use line editing (tty only)
Eric Andersenc470f442003-07-28 09:56:35 +000013061 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013062static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013063readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000013064{
Denys Vlasenko73067272010-01-12 22:11:24 +010013065 char *opt_n = NULL;
13066 char *opt_p = NULL;
13067 char *opt_t = NULL;
13068 char *opt_u = NULL;
13069 int read_flags = 0;
13070 const char *r;
Eric Andersenc470f442003-07-28 09:56:35 +000013071 int i;
13072
Denys Vlasenko73067272010-01-12 22:11:24 +010013073 while ((i = nextopt("p:u:rt:n:s")) != '\0') {
Denis Vlasenkobf0a2012006-12-26 10:42:51 +000013074 switch (i) {
Paul Fox02eb9342005-09-07 16:56:02 +000013075 case 'p':
Denys Vlasenko73067272010-01-12 22:11:24 +010013076 opt_p = optionarg;
Paul Fox02eb9342005-09-07 16:56:02 +000013077 break;
Paul Fox02eb9342005-09-07 16:56:02 +000013078 case 'n':
Denys Vlasenko73067272010-01-12 22:11:24 +010013079 opt_n = optionarg;
Paul Fox02eb9342005-09-07 16:56:02 +000013080 break;
13081 case 's':
Denys Vlasenko73067272010-01-12 22:11:24 +010013082 read_flags |= BUILTIN_READ_SILENT;
Paul Fox02eb9342005-09-07 16:56:02 +000013083 break;
Paul Fox02eb9342005-09-07 16:56:02 +000013084 case 't':
Denys Vlasenko73067272010-01-12 22:11:24 +010013085 opt_t = optionarg;
Paul Fox02eb9342005-09-07 16:56:02 +000013086 break;
Paul Fox02eb9342005-09-07 16:56:02 +000013087 case 'r':
Denys Vlasenko73067272010-01-12 22:11:24 +010013088 read_flags |= BUILTIN_READ_RAW;
Paul Fox02eb9342005-09-07 16:56:02 +000013089 break;
Denis Vlasenko59f351c2008-03-25 00:07:12 +000013090 case 'u':
Denys Vlasenko73067272010-01-12 22:11:24 +010013091 opt_u = optionarg;
Denis Vlasenko59f351c2008-03-25 00:07:12 +000013092 break;
Paul Fox02eb9342005-09-07 16:56:02 +000013093 default:
13094 break;
13095 }
Eric Andersenc470f442003-07-28 09:56:35 +000013096 }
Paul Fox02eb9342005-09-07 16:56:02 +000013097
Denys Vlasenko9e71e3c2012-09-06 13:28:10 +020013098 /* "read -s" needs to save/restore termios, can't allow ^C
13099 * to jump out of it.
13100 */
13101 INT_OFF;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020013102 r = shell_builtin_read(setvar0,
Denys Vlasenko73067272010-01-12 22:11:24 +010013103 argptr,
13104 bltinlookup("IFS"), /* can be NULL */
13105 read_flags,
13106 opt_n,
13107 opt_p,
13108 opt_t,
13109 opt_u
13110 );
Denys Vlasenko9e71e3c2012-09-06 13:28:10 +020013111 INT_ON;
Denis Vlasenko46aeab92009-03-31 19:18:17 +000013112
Denys Vlasenko73067272010-01-12 22:11:24 +010013113 if ((uintptr_t)r > 1)
13114 ash_msg_and_raise_error(r);
Denis Vlasenko037576d2007-10-20 18:30:38 +000013115
Denys Vlasenko73067272010-01-12 22:11:24 +010013116 return (uintptr_t)r;
Eric Andersenc470f442003-07-28 09:56:35 +000013117}
13118
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013119static int FAST_FUNC
Denys Vlasenko6283f982015-10-07 16:56:20 +020013120umaskcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000013121{
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013122 static const char permuser[3] ALIGN1 = "ogu";
Eric Andersenc470f442003-07-28 09:56:35 +000013123
Eric Andersenc470f442003-07-28 09:56:35 +000013124 mode_t mask;
Eric Andersenc470f442003-07-28 09:56:35 +000013125 int symbolic_mode = 0;
13126
13127 while (nextopt("S") != '\0') {
13128 symbolic_mode = 1;
13129 }
13130
Denis Vlasenkob012b102007-02-19 22:43:01 +000013131 INT_OFF;
Eric Andersenc470f442003-07-28 09:56:35 +000013132 mask = umask(0);
13133 umask(mask);
Denis Vlasenkob012b102007-02-19 22:43:01 +000013134 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +000013135
Denys Vlasenko6283f982015-10-07 16:56:20 +020013136 if (*argptr == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +000013137 if (symbolic_mode) {
Denys Vlasenko005c4922015-10-10 20:17:12 +020013138 char buf[sizeof(",u=rwx,g=rwx,o=rwx")];
Eric Andersenc470f442003-07-28 09:56:35 +000013139 char *p = buf;
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013140 int i;
Eric Andersenc470f442003-07-28 09:56:35 +000013141
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013142 i = 2;
13143 for (;;) {
Denys Vlasenko005c4922015-10-10 20:17:12 +020013144 *p++ = ',';
Eric Andersenc470f442003-07-28 09:56:35 +000013145 *p++ = permuser[i];
13146 *p++ = '=';
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013147 /* mask is 0..0uuugggooo. i=2 selects uuu bits */
Denys Vlasenko005c4922015-10-10 20:17:12 +020013148 if (!(mask & 0400)) *p++ = 'r';
13149 if (!(mask & 0200)) *p++ = 'w';
13150 if (!(mask & 0100)) *p++ = 'x';
13151 mask <<= 3;
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013152 if (--i < 0)
13153 break;
Eric Andersenc470f442003-07-28 09:56:35 +000013154 }
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013155 *p = '\0';
Denys Vlasenko005c4922015-10-10 20:17:12 +020013156 puts(buf + 1);
Eric Andersenc470f442003-07-28 09:56:35 +000013157 } else {
Denys Vlasenkoec046f72015-10-07 17:57:53 +020013158 out1fmt("%04o\n", mask);
Eric Andersenc470f442003-07-28 09:56:35 +000013159 }
13160 } else {
Denys Vlasenko6283f982015-10-07 16:56:20 +020013161 char *modestr = *argptr;
13162 /* numeric umasks are taken as-is */
13163 /* symbolic umasks are inverted: "umask a=rx" calls umask(222) */
13164 if (!isdigit(modestr[0]))
13165 mask ^= 0777;
Denys Vlasenko5711a2a2015-10-07 17:55:33 +020013166 mask = bb_parse_mode(modestr, mask);
13167 if ((unsigned)mask > 0777) {
Denys Vlasenko6283f982015-10-07 16:56:20 +020013168 ash_msg_and_raise_error("illegal mode: %s", modestr);
Eric Andersenc470f442003-07-28 09:56:35 +000013169 }
Denys Vlasenko6283f982015-10-07 16:56:20 +020013170 if (!isdigit(modestr[0]))
13171 mask ^= 0777;
13172 umask(mask);
Eric Andersenc470f442003-07-28 09:56:35 +000013173 }
13174 return 0;
13175}
13176
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013177static int FAST_FUNC
Denys Vlasenkof3c742f2010-03-06 20:12:00 +010013178ulimitcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersenc470f442003-07-28 09:56:35 +000013179{
Denys Vlasenkof3c742f2010-03-06 20:12:00 +010013180 return shell_builtin_ulimit(argv);
Eric Andersenc470f442003-07-28 09:56:35 +000013181}
13182
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013183/* ============ main() and helpers */
13184
13185/*
13186 * Called to exit the shell.
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013187 */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013188static void
13189exitshell(void)
13190{
13191 struct jmploc loc;
13192 char *p;
13193 int status;
13194
Denys Vlasenkobede2152011-09-04 16:12:33 +020013195#if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT
13196 save_history(line_input_state);
13197#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013198 status = exitstatus;
13199 TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
13200 if (setjmp(loc.loc)) {
Denis Vlasenko7f88e342009-03-19 03:36:18 +000013201 if (exception_type == EXEXIT)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013202 status = exitstatus;
13203 goto out;
13204 }
13205 exception_handler = &loc;
13206 p = trap[0];
13207 if (p) {
13208 trap[0] = NULL;
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020013209 evalskip = 0;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013210 evalstring(p, 0);
Denys Vlasenkof37e1152016-10-07 03:17:28 +020013211 /*free(p); - we'll exit soon */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013212 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013213 out:
Denys Vlasenkof37e1152016-10-07 03:17:28 +020013214 /* dash wraps setjobctl(0) in "if (setjmp(loc.loc) == 0) {...}".
13215 * our setjobctl(0) does not panic if tcsetpgrp fails inside it.
13216 */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013217 setjobctl(0);
Denys Vlasenkocaee80c2016-10-25 20:49:53 +020013218 flush_stdout_stderr();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013219 _exit(status);
13220 /* NOTREACHED */
13221}
13222
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +000013223static void
13224init(void)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013225{
Denys Vlasenko82dd14a2010-05-17 10:10:01 +020013226 /* we will never free this */
13227 basepf.next_to_pgetc = basepf.buf = ckmalloc(IBUFSIZ);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013228
Denys Vlasenko458c1f22016-10-27 23:51:19 +020013229 sigmode[SIGCHLD - 1] = S_DFL;
13230 setsignal(SIGCHLD);
13231
Denys Vlasenko7a7b0342009-12-04 04:18:31 +010013232 /* bash re-enables SIGHUP which is SIG_IGNed on entry.
13233 * Try: "trap '' HUP; bash; echo RET" and type "kill -HUP $$"
13234 */
Denys Vlasenkocacb2cd2010-10-05 00:13:02 +020013235 signal(SIGHUP, SIG_DFL);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013236
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013237 {
13238 char **envp;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013239 const char *p;
13240 struct stat st1, st2;
13241
13242 initvar();
13243 for (envp = environ; envp && *envp; envp++) {
Denys Vlasenkob6838b52016-09-30 11:33:47 +020013244 p = endofname(*envp);
13245 if (p != *envp && *p == '=') {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013246 setvareq(*envp, VEXPORT|VTEXTFIXED);
13247 }
13248 }
13249
Denys Vlasenkoe627ac92016-09-30 14:36:59 +020013250 setvareq((char*)defoptindvar, VTEXTFIXED);
13251
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020013252 setvar0("PPID", utoa(getppid()));
Bernhard Reutner-Fischer80f8cdf2013-11-08 14:25:24 +010013253#if ENABLE_ASH_BASH_COMPAT
13254 p = lookupvar("SHLVL");
Denys Vlasenko5680e982014-01-07 16:12:48 +010013255 setvar("SHLVL", utoa((p ? atoi(p) : 0) + 1), VEXPORT);
Denys Vlasenko3fa97af2014-04-15 11:43:29 +020013256 if (!lookupvar("HOSTNAME")) {
13257 struct utsname uts;
13258 uname(&uts);
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020013259 setvar0("HOSTNAME", uts.nodename);
Denys Vlasenko3fa97af2014-04-15 11:43:29 +020013260 }
Bernhard Reutner-Fischer80f8cdf2013-11-08 14:25:24 +010013261#endif
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013262 p = lookupvar("PWD");
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013263 if (p) {
Denys Vlasenkoef159702016-09-01 11:16:22 +020013264 if (p[0] != '/' || stat(p, &st1) || stat(".", &st2)
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013265 || st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino
13266 ) {
Denys Vlasenkoef159702016-09-01 11:16:22 +020013267 p = NULL;
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013268 }
13269 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013270 setpwd(p, 0);
13271 }
13272}
13273
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013274
13275//usage:#define ash_trivial_usage
Denys Vlasenko6b6af532011-03-08 10:24:17 +010013276//usage: "[-/+OPTIONS] [-/+o OPT]... [-c 'SCRIPT' [ARG0 [ARGS]] / FILE [ARGS]]"
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013277//usage:#define ash_full_usage "\n\n"
13278//usage: "Unix shell interpreter"
13279
13280//usage:#if ENABLE_FEATURE_SH_IS_ASH
13281//usage:# define sh_trivial_usage ash_trivial_usage
13282//usage:# define sh_full_usage ash_full_usage
13283//usage:#endif
13284//usage:#if ENABLE_FEATURE_BASH_IS_ASH
13285//usage:# define bash_trivial_usage ash_trivial_usage
13286//usage:# define bash_full_usage ash_full_usage
13287//usage:#endif
13288
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013289/*
13290 * Process the shell command line arguments.
13291 */
13292static void
Denis Vlasenko68404f12008-03-17 09:00:54 +000013293procargs(char **argv)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013294{
13295 int i;
13296 const char *xminusc;
13297 char **xargv;
13298
13299 xargv = argv;
13300 arg0 = xargv[0];
Denis Vlasenko68404f12008-03-17 09:00:54 +000013301 /* if (xargv[0]) - mmm, this is always true! */
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013302 xargv++;
13303 for (i = 0; i < NOPTS; i++)
13304 optlist[i] = 2;
13305 argptr = xargv;
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013306 if (options(/*cmdline:*/ 1)) {
Denis Vlasenko28bf6712008-02-14 15:01:47 +000013307 /* it already printed err message */
13308 raise_exception(EXERROR);
13309 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013310 xargv = argptr;
13311 xminusc = minusc;
13312 if (*xargv == NULL) {
13313 if (xminusc)
13314 ash_msg_and_raise_error(bb_msg_requires_arg, "-c");
13315 sflag = 1;
13316 }
13317 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
13318 iflag = 1;
13319 if (mflag == 2)
13320 mflag = iflag;
13321 for (i = 0; i < NOPTS; i++)
13322 if (optlist[i] == 2)
13323 optlist[i] = 0;
13324#if DEBUG == 2
13325 debug = 1;
13326#endif
13327 /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
13328 if (xminusc) {
13329 minusc = *xargv++;
13330 if (*xargv)
13331 goto setarg0;
13332 } else if (!sflag) {
13333 setinputfile(*xargv, 0);
13334 setarg0:
13335 arg0 = *xargv++;
13336 commandname = arg0;
13337 }
13338
13339 shellparam.p = xargv;
13340#if ENABLE_ASH_GETOPTS
13341 shellparam.optind = 1;
13342 shellparam.optoff = -1;
13343#endif
Denis Vlasenko01631112007-12-16 17:20:38 +000013344 /* assert(shellparam.malloced == 0 && shellparam.nparam == 0); */
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013345 while (*xargv) {
13346 shellparam.nparam++;
13347 xargv++;
13348 }
13349 optschanged();
13350}
13351
13352/*
Denys Vlasenko2eb0a7e2016-10-27 11:28:59 +020013353 * Read /etc/profile, ~/.profile, $ENV.
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013354 */
13355static void
13356read_profile(const char *name)
13357{
Denys Vlasenko2eb0a7e2016-10-27 11:28:59 +020013358 name = expandstr(name);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013359 if (setinputfile(name, INPUT_PUSH_FILE | INPUT_NOFILE_OK) < 0)
13360 return;
Denys Vlasenko0840c912016-10-01 15:27:44 +020013361 cmdloop(0);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013362 popfile();
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013363}
13364
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013365/*
13366 * This routine is called when an error or an interrupt occurs in an
13367 * interactive shell and control is returned to the main command loop.
Denys Vlasenko5ac04f22016-10-27 14:46:50 +020013368 * (In dash, this function is auto-generated by build machinery).
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013369 */
13370static void
13371reset(void)
13372{
13373 /* from eval.c: */
13374 evalskip = 0;
13375 loopnest = 0;
Denys Vlasenko5ac04f22016-10-27 14:46:50 +020013376
13377 /* from expand.c: */
13378 ifsfree();
13379
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013380 /* from input.c: */
Denis Vlasenko41eb3002008-11-28 03:42:31 +000013381 g_parsefile->left_in_buffer = 0;
13382 g_parsefile->left_in_line = 0; /* clear input buffer */
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013383 popallfiles();
Denys Vlasenko5ac04f22016-10-27 14:46:50 +020013384
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013385 /* from redir.c: */
Denys Vlasenkoe19923f2016-10-26 15:38:44 +020013386 while (redirlist)
13387 popredir(/*drop:*/ 0, /*restore:*/ 0);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013388}
13389
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013390#if PROFILE
13391static short profile_buf[16384];
13392extern int etext();
13393#endif
13394
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013395/*
13396 * Main routine. We initialize things, parse the arguments, execute
13397 * profiles if we're a login shell, and then call cmdloop to execute
13398 * commands. The setjmp call sets up the location to jump to when an
13399 * exception occurs. When an exception occurs the variable "state"
13400 * is used to figure out how far we had gotten.
13401 */
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +000013402int ash_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013403int ash_main(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013404{
Denis Vlasenko4e12b1a2008-12-23 23:36:47 +000013405 volatile smallint state;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013406 struct jmploc jmploc;
13407 struct stackmark smark;
13408
Denis Vlasenko01631112007-12-16 17:20:38 +000013409 /* Initialize global data */
13410 INIT_G_misc();
13411 INIT_G_memstack();
13412 INIT_G_var();
Denis Vlasenkoee87ebf2007-12-21 22:18:16 +000013413#if ENABLE_ASH_ALIAS
Denis Vlasenko01631112007-12-16 17:20:38 +000013414 INIT_G_alias();
Denis Vlasenkoee87ebf2007-12-21 22:18:16 +000013415#endif
Denis Vlasenko01631112007-12-16 17:20:38 +000013416 INIT_G_cmdtable();
13417
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013418#if PROFILE
13419 monitor(4, etext, profile_buf, sizeof(profile_buf), 50);
13420#endif
13421
13422#if ENABLE_FEATURE_EDITING
13423 line_input_state = new_line_input_t(FOR_SHELL | WITH_PATH_LOOKUP);
13424#endif
13425 state = 0;
13426 if (setjmp(jmploc.loc)) {
Denis Vlasenko7f88e342009-03-19 03:36:18 +000013427 smallint e;
Denis Vlasenko4e12b1a2008-12-23 23:36:47 +000013428 smallint s;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013429
13430 reset();
13431
Denis Vlasenko7f88e342009-03-19 03:36:18 +000013432 e = exception_type;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013433 s = state;
Denys Vlasenkob563f622010-09-25 17:15:13 +020013434 if (e == EXEXIT || s == 0 || iflag == 0 || shlvl) {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013435 exitshell();
Denys Vlasenkob563f622010-09-25 17:15:13 +020013436 }
13437 if (e == EXINT) {
Denys Vlasenko9c541002015-10-07 15:44:36 +020013438 newline_and_flush(stderr);
Denys Vlasenkob563f622010-09-25 17:15:13 +020013439 }
Denis Vlasenko7f88e342009-03-19 03:36:18 +000013440
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013441 popstackmark(&smark);
13442 FORCE_INT_ON; /* enable interrupts */
13443 if (s == 1)
13444 goto state1;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000013445 if (s == 2)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013446 goto state2;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000013447 if (s == 3)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013448 goto state3;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000013449 goto state4;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013450 }
13451 exception_handler = &jmploc;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013452 rootpid = getpid();
13453
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013454 init();
13455 setstackmark(&smark);
Denis Vlasenko68404f12008-03-17 09:00:54 +000013456 procargs(argv);
Denys Vlasenko474ed062016-10-30 18:30:29 +010013457#if DEBUG
13458 TRACE(("Shell args: "));
13459 trace_puts_args(argv);
13460#endif
Denis Vlasenko68404f12008-03-17 09:00:54 +000013461
Denys Vlasenko6088e132010-12-25 23:58:42 +010013462 if (argv[0] && argv[0][0] == '-')
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013463 isloginsh = 1;
13464 if (isloginsh) {
Stefan Hellermann4ef14392013-03-15 02:45:50 +010013465 const char *hp;
13466
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013467 state = 1;
13468 read_profile("/etc/profile");
13469 state1:
13470 state = 2;
Stefan Hellermann4ef14392013-03-15 02:45:50 +010013471 hp = lookupvar("HOME");
Denys Vlasenko2eb0a7e2016-10-27 11:28:59 +020013472 if (hp)
13473 read_profile("$HOME/.profile");
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013474 }
13475 state2:
13476 state = 3;
13477 if (
13478#ifndef linux
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013479 getuid() == geteuid() && getgid() == getegid() &&
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013480#endif
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013481 iflag
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013482 ) {
Denys Vlasenko2eb0a7e2016-10-27 11:28:59 +020013483 const char *shinit = lookupvar("ENV");
13484 if (shinit != NULL && *shinit != '\0')
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013485 read_profile(shinit);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013486 }
Denys Vlasenko2eb0a7e2016-10-27 11:28:59 +020013487 popstackmark(&smark);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013488 state3:
13489 state = 4;
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000013490 if (minusc) {
13491 /* evalstring pushes parsefile stack.
13492 * Ensure we don't falsely claim that 0 (stdin)
Denis Vlasenko5368ad52009-03-20 10:20:08 +000013493 * is one of stacked source fds.
13494 * Testcase: ash -c 'exec 1>&0' must not complain. */
Denys Vlasenko79b3d422010-06-03 04:29:08 +020013495 // if (!sflag) g_parsefile->pf_fd = -1;
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +020013496 // ^^ not necessary since now we special-case fd 0
13497 // in is_hidden_fd() to not be considered "hidden fd"
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013498 evalstring(minusc, 0);
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000013499 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013500
13501 if (sflag || minusc == NULL) {
Denys Vlasenko4840ae82011-09-04 15:28:03 +020013502#if MAX_HISTORY > 0 && ENABLE_FEATURE_EDITING_SAVEHISTORY
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +000013503 if (iflag) {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013504 const char *hp = lookupvar("HISTFILE");
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010013505 if (!hp) {
13506 hp = lookupvar("HOME");
Stefan Hellermann4ef14392013-03-15 02:45:50 +010013507 if (hp) {
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010013508 hp = concat_path_file(hp, ".ash_history");
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020013509 setvar0("HISTFILE", hp);
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010013510 free((char*)hp);
13511 hp = lookupvar("HISTFILE");
13512 }
13513 }
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000013514 if (hp)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013515 line_input_state->hist_file = hp;
Denys Vlasenko2c4de5b2011-03-31 13:16:52 +020013516# if ENABLE_FEATURE_SH_HISTFILESIZE
13517 hp = lookupvar("HISTFILESIZE");
13518 line_input_state->max_history = size_from_HISTFILESIZE(hp);
13519# endif
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013520 }
13521#endif
13522 state4: /* XXX ??? - why isn't this before the "if" statement */
13523 cmdloop(1);
13524 }
13525#if PROFILE
13526 monitor(0);
13527#endif
13528#ifdef GPROF
13529 {
13530 extern void _mcleanup(void);
13531 _mcleanup();
13532 }
13533#endif
Denys Vlasenkob563f622010-09-25 17:15:13 +020013534 TRACE(("End of main reached\n"));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013535 exitshell();
13536 /* NOTREACHED */
13537}
13538
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013539
Eric Andersendf82f612001-06-28 07:46:40 +000013540/*-
13541 * Copyright (c) 1989, 1991, 1993, 1994
Eric Andersen2870d962001-07-02 17:27:21 +000013542 * The Regents of the University of California. All rights reserved.
Eric Andersendf82f612001-06-28 07:46:40 +000013543 *
13544 * This code is derived from software contributed to Berkeley by
13545 * Kenneth Almquist.
13546 *
13547 * Redistribution and use in source and binary forms, with or without
13548 * modification, are permitted provided that the following conditions
13549 * are met:
13550 * 1. Redistributions of source code must retain the above copyright
13551 * notice, this list of conditions and the following disclaimer.
13552 * 2. Redistributions in binary form must reproduce the above copyright
13553 * notice, this list of conditions and the following disclaimer in the
13554 * documentation and/or other materials provided with the distribution.
"Vladimir N. Oleynik"ddc280e2005-12-15 12:01:49 +000013555 * 3. Neither the name of the University nor the names of its contributors
Eric Andersendf82f612001-06-28 07:46:40 +000013556 * may be used to endorse or promote products derived from this software
13557 * without specific prior written permission.
13558 *
13559 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
13560 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
13561 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
13562 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
13563 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
13564 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
13565 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
13566 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
13567 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
13568 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
13569 * SUCH DAMAGE.
13570 */